Backed out changeset 5df8f9f0a5b9 (bug 1370430) to see if it unbreaks builds a=backout CLOSED TREE

MozReview-Commit-ID: G2snPHLTZg5

--HG--
rename : third_party/rust/euclid-0.13.0/src/matrix2d.rs => third_party/rust/euclid/src/matrix2d.rs
rename : third_party/rust/euclid-0.13.0/src/matrix4d.rs => third_party/rust/euclid/src/matrix4d.rs
extra : amend_source : 796c79ec645c0d1d357d052585ef9da24ec887fe
This commit is contained in:
Wes Kocher 2017-06-13 19:16:09 -07:00
Родитель b32bf15627
Коммит c2afdb09bd
99 изменённых файлов: 2205 добавлений и 7746 удалений

Просмотреть файл

@ -79,4 +79,4 @@ to make sure that mozjs_sys also has its Cargo.lock file updated if needed, henc
the need to run the cargo update command in js/src as well. Hopefully this will
be resolved soon.
Latest Commit: 6752684fcc7402b0a5480e0b9f73152b2f9ed1e5
Latest Commit: b2614e4eb58f9dee08b8c38f96bc3bac834c837b

Просмотреть файл

@ -17,20 +17,20 @@ app_units = "0.4"
bincode = "1.0.0-alpha6"
bit-set = "0.4"
byteorder = "1.0"
euclid = "0.14.4"
euclid = "0.13"
fnv = "1.0"
gleam = "0.4.3"
lazy_static = "0.2"
log = "0.3"
num-traits = "0.1.32"
offscreen_gl_context = {version = "0.9.0", features = ["serde", "osmesa"], optional = true}
offscreen_gl_context = {version = "0.8.0", features = ["serde", "osmesa"], optional = true}
time = "0.1"
rayon = {version = "0.7", features = ["unstable"]}
webrender_traits = {path = "../webrender_traits"}
bitflags = "0.7"
gamma-lut = "0.2"
thread_profiler = "0.1.1"
plane-split = "0.5"
plane-split = "0.4"
[dev-dependencies]
angle = {git = "https://github.com/servo/angle", branch = "servo"}
@ -46,3 +46,15 @@ dwrote = "0.3"
[target.'cfg(target_os = "macos")'.dependencies]
core-graphics = "0.7.0"
core-text = "4.0"
[[example]]
name = "basic"
[[example]]
name = "blob"
[[example]]
name = "scrolling"
[[example]]
name = "yuv"

Просмотреть файл

@ -1,86 +0,0 @@
/* 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/. */
extern crate gleam;
extern crate glutin;
extern crate webrender;
extern crate webrender_traits;
#[macro_use]
extern crate lazy_static;
#[path="common/boilerplate.rs"]
mod boilerplate;
use boilerplate::HandyDandyRectBuilder;
use std::sync::Mutex;
use webrender_traits::*;
// This example creates a 100x100 white rect and allows the user to move it
// around by using the arrow keys. It does this by using the animation API.
fn body(_api: &RenderApi,
builder: &mut DisplayListBuilder,
_pipeline_id: &PipelineId,
_layout_size: &LayoutSize)
{
// Create a 100x100 stacking context with an animatable transform property.
// Note the magic "42" we use as the animation key. That is used to update
// the transform in the keyboard event handler code.
let bounds = (0,0).to(100, 100);
builder.push_stacking_context(webrender_traits::ScrollPolicy::Scrollable,
bounds,
Some(PropertyBinding::Binding(PropertyBindingKey::new(42))),
TransformStyle::Flat,
None,
webrender_traits::MixBlendMode::Normal,
Vec::new());
// Fill it with a white rect
let clip = builder.push_clip_region(&bounds, vec![], None);
builder.push_rect(bounds,
clip,
ColorF::new(1.0, 1.0, 1.0, 1.0));
builder.pop_stacking_context();
}
lazy_static! {
static ref TRANSFORM: Mutex<LayoutTransform> = Mutex::new(LayoutTransform::identity());
}
fn event_handler(event: &glutin::Event,
api: &RenderApi)
{
match *event {
glutin::Event::KeyboardInput(glutin::ElementState::Pressed, _, Some(key)) => {
let offset = match key {
glutin::VirtualKeyCode::Down => (0.0, 10.0),
glutin::VirtualKeyCode::Up => (0.0, -10.0),
glutin::VirtualKeyCode::Right => (10.0, 0.0),
glutin::VirtualKeyCode::Left => (-10.0, 0.0),
_ => return,
};
// Update the transform based on the keyboard input and push it to
// webrender using the generate_frame API. This will recomposite with
// the updated transform.
let new_transform = TRANSFORM.lock().unwrap().post_translate(LayoutVector3D::new(offset.0, offset.1, 0.0));
api.generate_frame(Some(DynamicProperties {
transforms: vec![
PropertyValue {
key: PropertyBindingKey::new(42),
value: new_transform,
},
],
floats: vec![],
}));
*TRANSFORM.lock().unwrap() = new_transform;
}
_ => ()
}
}
fn main() {
boilerplate::main_wrapper(body, event_handler, None);
}

Просмотреть файл

@ -21,7 +21,6 @@ use webrender_traits::{ClipRegionToken, ColorF, DisplayListBuilder, Epoch, Glyph
use webrender_traits::{DeviceIntPoint, DeviceUintSize, LayoutPoint, LayoutRect, LayoutSize};
use webrender_traits::{ImageData, ImageDescriptor, ImageFormat};
use webrender_traits::{PipelineId, RenderApi, TransformStyle, BoxShadowClipMode};
use euclid::vec2;
#[derive(Debug)]
enum Gesture {
@ -382,7 +381,7 @@ fn main() {
let rect = LayoutRect::new(LayoutPoint::new(0.0, 0.0), LayoutSize::new(0.0, 0.0));
let simple_box_bounds = LayoutRect::new(LayoutPoint::new(20.0, 200.0),
LayoutSize::new(50.0, 50.0));
let offset = vec2(10.0, 10.0);
let offset = LayoutPoint::new(10.0, 10.0);
let color = ColorF::new(1.0, 1.0, 1.0, 1.0);
let blur_radius = 0.0;
let spread_radius = 0.0;

Просмотреть файл

@ -10,36 +10,37 @@ extern crate webrender;
extern crate webrender_traits;
extern crate rayon;
#[path="common/boilerplate.rs"]
mod boilerplate;
use boilerplate::HandyDandyRectBuilder;
use gleam::gl;
use rayon::ThreadPool;
use rayon::Configuration as ThreadPoolConfig;
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::sync::Arc;
use std::sync::mpsc::{channel, Sender, Receiver};
use webrender_traits as wt;
use webrender_traits::{BlobImageData, BlobImageDescriptor, BlobImageError, BlobImageRenderer, BlobImageRequest};
use webrender_traits::{BlobImageResult, TileOffset, ImageStore, ColorF, ColorU, Epoch};
use webrender_traits::{DeviceUintSize, DeviceUintRect, LayoutPoint, LayoutRect, LayoutSize};
use webrender_traits::{ImageData, ImageDescriptor, ImageFormat, ImageRendering, ImageKey, TileSize};
use webrender_traits::{PipelineId, RasterizedBlobImage, TransformStyle};
// This example shows how to implement a very basic BlobImageRenderer that can only render
// a checkerboard pattern.
// The deserialized command list internally used by this example is just a color.
type ImageRenderingCommands = wt::ColorU;
type ImageRenderingCommands = ColorU;
// Serialize/deserialze the blob.
// Ror real usecases you should probably use serde rather than doing it by hand.
fn serialize_blob(color: wt::ColorU) -> Vec<u8> {
fn serialize_blob(color: ColorU) -> Vec<u8> {
vec![color.r, color.g, color.b, color.a]
}
fn deserialize_blob(blob: &[u8]) -> Result<ImageRenderingCommands, ()> {
let mut iter = blob.iter();
return match (iter.next(), iter.next(), iter.next(), iter.next()) {
(Some(&r), Some(&g), Some(&b), Some(&a)) => Ok(wt::ColorU::new(r, g, b, a)),
(Some(&a), None, None, None) => Ok(wt::ColorU::new(a, a, a, a)),
(Some(&r), Some(&g), Some(&b), Some(&a)) => Ok(ColorU::new(r, g, b, a)),
(Some(&a), None, None, None) => Ok(ColorU::new(a, a, a, a)),
_ => Err(()),
}
}
@ -48,9 +49,9 @@ fn deserialize_blob(blob: &[u8]) -> Result<ImageRenderingCommands, ()> {
// actual image data.
fn render_blob(
commands: Arc<ImageRenderingCommands>,
descriptor: &wt::BlobImageDescriptor,
tile: Option<wt::TileOffset>,
) -> wt::BlobImageResult {
descriptor: &BlobImageDescriptor,
tile: Option<TileOffset>,
) -> BlobImageResult {
let color = *commands;
// Allocate storage for the result. Right now the resource cache expects the
@ -77,17 +78,17 @@ fn render_blob(
let tc = if tile_checker { 0 } else { (1 - checker) * 40 };
match descriptor.format {
wt::ImageFormat::RGBA8 => {
ImageFormat::RGBA8 => {
texels.push(color.b * checker + tc);
texels.push(color.g * checker + tc);
texels.push(color.r * checker + tc);
texels.push(color.a * checker + tc);
}
wt::ImageFormat::A8 => {
ImageFormat::A8 => {
texels.push(color.a * checker + tc);
}
_ => {
return Err(wt::BlobImageError::Other(format!(
return Err(BlobImageError::Other(format!(
"Usupported image format {:?}",
descriptor.format
)));
@ -96,7 +97,7 @@ fn render_blob(
}
}
Ok(wt::RasterizedBlobImage {
Ok(RasterizedBlobImage {
data: texels,
width: descriptor.width,
height: descriptor.height,
@ -111,18 +112,18 @@ struct CheckerboardRenderer {
workers: Arc<ThreadPool>,
// the workers will use an mpsc channel to communicate the result.
tx: Sender<(wt::BlobImageRequest, wt::BlobImageResult)>,
rx: Receiver<(wt::BlobImageRequest, wt::BlobImageResult)>,
tx: Sender<(BlobImageRequest, BlobImageResult)>,
rx: Receiver<(BlobImageRequest, BlobImageResult)>,
// The deserialized drawing commands.
// In this example we store them in Arcs. This isn't necessary since in this simplified
// case the command list is a simple 32 bits value and would be cheap to clone before sending
// to the workers. But in a more realistic scenario the commands would typically be bigger
// and more expensive to clone, so let's pretend it is also the case here.
image_cmds: HashMap<wt::ImageKey, Arc<ImageRenderingCommands>>,
image_cmds: HashMap<ImageKey, Arc<ImageRenderingCommands>>,
// The images rendered in the current frame (not kept here between frames).
rendered_images: HashMap<wt::BlobImageRequest, Option<wt::BlobImageResult>>,
rendered_images: HashMap<BlobImageRequest, Option<BlobImageResult>>,
}
impl CheckerboardRenderer {
@ -138,26 +139,26 @@ impl CheckerboardRenderer {
}
}
impl wt::BlobImageRenderer for CheckerboardRenderer {
fn add(&mut self, key: wt::ImageKey, cmds: wt::BlobImageData, _: Option<wt::TileSize>) {
impl BlobImageRenderer for CheckerboardRenderer {
fn add(&mut self, key: ImageKey, cmds: BlobImageData, _: Option<TileSize>) {
self.image_cmds.insert(key, Arc::new(deserialize_blob(&cmds[..]).unwrap()));
}
fn update(&mut self, key: wt::ImageKey, cmds: wt::BlobImageData) {
fn update(&mut self, key: ImageKey, cmds: BlobImageData) {
// Here, updating is just replacing the current version of the commands with
// the new one (no incremental updates).
self.image_cmds.insert(key, Arc::new(deserialize_blob(&cmds[..]).unwrap()));
}
fn delete(&mut self, key: wt::ImageKey) {
fn delete(&mut self, key: ImageKey) {
self.image_cmds.remove(&key);
}
fn request(&mut self,
resources: &wt::BlobImageResources,
request: wt::BlobImageRequest,
descriptor: &wt::BlobImageDescriptor,
_dirty_rect: Option<wt::DeviceUintRect>) {
request: BlobImageRequest,
descriptor: &BlobImageDescriptor,
_dirty_rect: Option<DeviceUintRect>,
_images: &ImageStore) {
// This method is where we kick off our rendering jobs.
// It should avoid doing work on the calling thread as much as possible.
// In this example we will use the thread pool to render individual tiles.
@ -179,7 +180,7 @@ impl wt::BlobImageRenderer for CheckerboardRenderer {
self.rendered_images.insert(request, None);
}
fn resolve(&mut self, request: wt::BlobImageRequest) -> wt::BlobImageResult {
fn resolve(&mut self, request: BlobImageRequest) -> BlobImageResult {
// In this method we wait until the work is complete on the worker threads and
// gather the results.
@ -187,7 +188,7 @@ impl wt::BlobImageRenderer for CheckerboardRenderer {
// that we are looking for.
match self.rendered_images.entry(request) {
Entry::Vacant(_) => {
return Err(wt::BlobImageError::InvalidKey);
return Err(BlobImageError::InvalidKey);
}
Entry::Occupied(entry) => {
// None means we haven't yet received the result.
@ -208,70 +209,34 @@ impl wt::BlobImageRenderer for CheckerboardRenderer {
}
// If we break out of the loop above it means the channel closed unexpectedly.
Err(wt::BlobImageError::Other("Channel closed".into()))
Err(BlobImageError::Other("Channel closed".into()))
}
fn delete_font(&mut self, font: wt::FontKey) {}
}
fn body(api: &wt::RenderApi,
builder: &mut wt::DisplayListBuilder,
_pipeline_id: &wt::PipelineId,
layout_size: &wt::LayoutSize)
{
let blob_img1 = api.generate_image_key();
api.add_image(
blob_img1,
wt::ImageDescriptor::new(500, 500, wt::ImageFormat::RGBA8, true),
wt::ImageData::new_blob_image(serialize_blob(wt::ColorU::new(50, 50, 150, 255))),
Some(128),
);
let blob_img2 = api.generate_image_key();
api.add_image(
blob_img2,
wt::ImageDescriptor::new(200, 200, wt::ImageFormat::RGBA8, true),
wt::ImageData::new_blob_image(serialize_blob(wt::ColorU::new(50, 150, 50, 255))),
None,
);
let bounds = wt::LayoutRect::new(wt::LayoutPoint::zero(), *layout_size);
builder.push_stacking_context(wt::ScrollPolicy::Scrollable,
bounds,
None,
wt::TransformStyle::Flat,
None,
wt::MixBlendMode::Normal,
Vec::new());
let clip = builder.push_clip_region(&bounds, vec![], None);
builder.push_image(
(30, 30).by(500, 500),
clip,
wt::LayoutSize::new(500.0, 500.0),
wt::LayoutSize::new(0.0, 0.0),
wt::ImageRendering::Auto,
blob_img1,
);
let clip = builder.push_clip_region(&bounds, vec![], None);
builder.push_image(
(600, 600).by(200, 200),
clip,
wt::LayoutSize::new(200.0, 200.0),
wt::LayoutSize::new(0.0, 0.0),
wt::ImageRendering::Auto,
blob_img2,
);
builder.pop_stacking_context();
}
fn event_handler(_event: &glutin::Event,
_api: &wt::RenderApi)
{
}
fn main() {
let window = glutin::WindowBuilder::new()
.with_title("WebRender Sample (BlobImageRenderer)")
.with_multitouch()
.with_gl(glutin::GlRequest::GlThenGles {
opengl_version: (3, 2),
opengles_version: (3, 0)
})
.build()
.unwrap();
unsafe {
window.make_current().ok();
}
let gl = match gl::GlType::default() {
gl::GlType::Gl => unsafe { gl::GlFns::load_with(|symbol| window.get_proc_address(symbol) as *const _) },
gl::GlType::Gles => unsafe { gl::GlesFns::load_with(|symbol| window.get_proc_address(symbol) as *const _) },
};
println!("OpenGL version {}", gl.get_string(gl::VERSION));
let (width, height) = window.get_inner_size_pixels().unwrap();
let worker_config = ThreadPoolConfig::new().thread_name(|idx|{
format!("WebRender:Worker#{}", idx)
});
@ -279,12 +244,134 @@ fn main() {
let workers = Arc::new(ThreadPool::new(worker_config).unwrap());
let opts = webrender::RendererOptions {
debug: true,
workers: Some(Arc::clone(&workers)),
// Register our blob renderer, so that WebRender integrates it in the resource cache..
// Share the same pool of worker threads between WebRender and our blob renderer.
blob_image_renderer: Some(Box::new(CheckerboardRenderer::new(Arc::clone(&workers)))),
device_pixel_ratio: window.hidpi_factor(),
.. Default::default()
};
boilerplate::main_wrapper(body, event_handler, Some(opts));
let size = DeviceUintSize::new(width, height);
let (mut renderer, sender) = webrender::renderer::Renderer::new(gl, opts, size).unwrap();
let api = sender.create_api();
let notifier = Box::new(Notifier::new(window.create_window_proxy()));
renderer.set_render_notifier(notifier);
let epoch = Epoch(0);
let root_background_color = ColorF::new(0.2, 0.2, 0.2, 1.0);
let blob_img1 = api.generate_image_key();
api.add_image(
blob_img1,
ImageDescriptor::new(500, 500, ImageFormat::RGBA8, true),
ImageData::new_blob_image(serialize_blob(ColorU::new(50, 50, 150, 255))),
Some(128),
);
let blob_img2 = api.generate_image_key();
api.add_image(
blob_img2,
ImageDescriptor::new(200, 200, ImageFormat::RGBA8, true),
ImageData::new_blob_image(serialize_blob(ColorU::new(50, 150, 50, 255))),
None,
);
let pipeline_id = PipelineId(0, 0);
let layout_size = LayoutSize::new(width as f32, height as f32);
let mut builder = webrender_traits::DisplayListBuilder::new(pipeline_id, layout_size);
let bounds = LayoutRect::new(LayoutPoint::zero(), layout_size);
builder.push_stacking_context(webrender_traits::ScrollPolicy::Scrollable,
bounds,
None,
TransformStyle::Flat,
None,
webrender_traits::MixBlendMode::Normal,
Vec::new());
let clip = builder.push_clip_region(&bounds, vec![], None);
builder.push_image(
LayoutRect::new(LayoutPoint::new(30.0, 30.0), LayoutSize::new(500.0, 500.0)),
clip,
LayoutSize::new(500.0, 500.0),
LayoutSize::new(0.0, 0.0),
ImageRendering::Auto,
blob_img1,
);
let clip = builder.push_clip_region(&bounds, vec![], None);
builder.push_image(
LayoutRect::new(LayoutPoint::new(600.0, 60.0), LayoutSize::new(200.0, 200.0)),
clip,
LayoutSize::new(200.0, 200.0),
LayoutSize::new(0.0, 0.0),
ImageRendering::Auto,
blob_img2,
);
builder.pop_stacking_context();
api.set_display_list(
Some(root_background_color),
epoch,
LayoutSize::new(width as f32, height as f32),
builder.finalize(),
true);
api.set_root_pipeline(pipeline_id);
api.generate_frame(None);
'outer: for event in window.wait_events() {
let mut events = Vec::new();
events.push(event);
for event in window.poll_events() {
events.push(event);
}
for event in events {
match event {
glutin::Event::Closed |
glutin::Event::KeyboardInput(_, _, Some(glutin::VirtualKeyCode::Escape)) |
glutin::Event::KeyboardInput(_, _, Some(glutin::VirtualKeyCode::Q)) => break 'outer,
glutin::Event::KeyboardInput(glutin::ElementState::Pressed,
_, Some(glutin::VirtualKeyCode::P)) => {
let enable_profiler = !renderer.get_profiler_enabled();
renderer.set_profiler_enabled(enable_profiler);
api.generate_frame(None);
}
_ => ()
}
}
renderer.update();
renderer.render(DeviceUintSize::new(width, height));
window.swap_buffers().ok();
}
}
struct Notifier {
window_proxy: glutin::WindowProxy,
}
impl Notifier {
fn new(window_proxy: glutin::WindowProxy) -> Notifier {
Notifier {
window_proxy: window_proxy,
}
}
}
impl webrender_traits::RenderNotifier for Notifier {
fn new_frame_ready(&mut self) {
#[cfg(not(target_os = "android"))]
self.window_proxy.wakeup_event_loop();
}
fn new_scroll_frame_ready(&mut self, _composite_needed: bool) {
#[cfg(not(target_os = "android"))]
self.window_proxy.wakeup_event_loop();
}
}

Просмотреть файл

@ -1,155 +0,0 @@
/* 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 glutin;
use std::env;
use std::path::PathBuf;
use webrender;
use webrender_traits::*;
struct Notifier {
window_proxy: glutin::WindowProxy,
}
impl Notifier {
fn new(window_proxy: glutin::WindowProxy) -> Notifier {
Notifier {
window_proxy: window_proxy,
}
}
}
impl RenderNotifier for Notifier {
fn new_frame_ready(&mut self) {
#[cfg(not(target_os = "android"))]
self.window_proxy.wakeup_event_loop();
}
fn new_scroll_frame_ready(&mut self, _composite_needed: bool) {
#[cfg(not(target_os = "android"))]
self.window_proxy.wakeup_event_loop();
}
}
pub trait HandyDandyRectBuilder {
fn to(&self, x2: i32, y2: i32) -> LayoutRect;
fn by(&self, w: i32, h: i32) -> LayoutRect;
}
// Allows doing `(x, y).to(x2, y2)` or `(x, y).by(width, height)` with i32
// values to build a f32 LayoutRect
impl HandyDandyRectBuilder for (i32, i32) {
fn to(&self, x2: i32, y2: i32) -> LayoutRect {
LayoutRect::new(LayoutPoint::new(self.0 as f32, self.1 as f32),
LayoutSize::new((x2 - self.0) as f32, (y2 - self.1) as f32))
}
fn by(&self, w: i32, h: i32) -> LayoutRect {
LayoutRect::new(LayoutPoint::new(self.0 as f32, self.1 as f32),
LayoutSize::new(w as f32, h as f32))
}
}
pub fn main_wrapper(builder_callback: fn(&RenderApi,
&mut DisplayListBuilder,
&PipelineId,
&LayoutSize) -> (),
event_handler: fn(&glutin::Event,
&RenderApi) -> (),
options: Option<webrender::RendererOptions>)
{
let args: Vec<String> = env::args().collect();
let res_path = if args.len() > 1 {
Some(PathBuf::from(&args[1]))
} else {
None
};
let window = glutin::WindowBuilder::new()
.with_title("WebRender Sample App")
.with_multitouch()
.with_gl(glutin::GlRequest::GlThenGles {
opengl_version: (3, 2),
opengles_version: (3, 0)
})
.build()
.unwrap();
unsafe {
window.make_current().ok();
}
let gl = match gl::GlType::default() {
gl::GlType::Gl => unsafe { gl::GlFns::load_with(|symbol| window.get_proc_address(symbol) as *const _) },
gl::GlType::Gles => unsafe { gl::GlesFns::load_with(|symbol| window.get_proc_address(symbol) as *const _) },
};
println!("OpenGL version {}", gl.get_string(gl::VERSION));
println!("Shader resource path: {:?}", res_path);
let (width, height) = window.get_inner_size_pixels().unwrap();
let opts = webrender::RendererOptions {
resource_override_path: res_path,
debug: true,
precache_shaders: true,
device_pixel_ratio: window.hidpi_factor(),
.. options.unwrap_or(webrender::RendererOptions::default())
};
let size = DeviceUintSize::new(width, height);
let (mut renderer, sender) = webrender::renderer::Renderer::new(gl, opts, size).unwrap();
let api = sender.create_api();
let notifier = Box::new(Notifier::new(window.create_window_proxy()));
renderer.set_render_notifier(notifier);
let epoch = Epoch(0);
let root_background_color = ColorF::new(0.3, 0.0, 0.0, 1.0);
let pipeline_id = PipelineId(0, 0);
let layout_size = LayoutSize::new(width as f32, height as f32);
let mut builder = DisplayListBuilder::new(pipeline_id, layout_size);
builder_callback(&api, &mut builder, &pipeline_id, &layout_size);
api.set_display_list(
Some(root_background_color),
epoch,
LayoutSize::new(width as f32, height as f32),
builder.finalize(),
true);
api.set_root_pipeline(pipeline_id);
api.generate_frame(None);
'outer: for event in window.wait_events() {
let mut events = Vec::new();
events.push(event);
for event in window.poll_events() {
events.push(event);
}
for event in events {
match event {
glutin::Event::Closed |
glutin::Event::KeyboardInput(_, _, Some(glutin::VirtualKeyCode::Escape)) |
glutin::Event::KeyboardInput(_, _, Some(glutin::VirtualKeyCode::Q)) => break 'outer,
glutin::Event::KeyboardInput(glutin::ElementState::Pressed,
_, Some(glutin::VirtualKeyCode::P)) => {
let enable_profiler = !renderer.get_profiler_enabled();
renderer.set_profiler_enabled(enable_profiler);
api.generate_frame(None);
}
_ => event_handler(&event, &api),
}
}
renderer.update();
renderer.render(DeviceUintSize::new(width, height));
window.swap_buffers().ok();
}
}

Просмотреть файл

@ -7,22 +7,103 @@ extern crate glutin;
extern crate webrender;
extern crate webrender_traits;
#[macro_use]
extern crate lazy_static;
use gleam::gl;
use std::env;
use std::path::PathBuf;
use webrender_traits::{ClipId, ColorF, DeviceUintSize, Epoch, LayoutPoint, LayoutRect};
use webrender_traits::{LayoutSize, PipelineId, ScrollEventPhase, ScrollLocation, TransformStyle};
use webrender_traits::WorldPoint;
#[path="common/boilerplate.rs"]
mod boilerplate;
struct Notifier {
window_proxy: glutin::WindowProxy,
}
use boilerplate::HandyDandyRectBuilder;
use std::sync::Mutex;
use webrender_traits::*;
impl Notifier {
fn new(window_proxy: glutin::WindowProxy) -> Notifier {
Notifier {
window_proxy: window_proxy,
}
}
}
fn body(_api: &RenderApi,
builder: &mut DisplayListBuilder,
pipeline_id: &PipelineId,
layout_size: &LayoutSize)
{
let bounds = LayoutRect::new(LayoutPoint::zero(), *layout_size);
impl webrender_traits::RenderNotifier for Notifier {
fn new_frame_ready(&mut self) {
#[cfg(not(target_os = "android"))]
self.window_proxy.wakeup_event_loop();
}
fn new_scroll_frame_ready(&mut self, _composite_needed: bool) {
#[cfg(not(target_os = "android"))]
self.window_proxy.wakeup_event_loop();
}
}
trait HandyDandyRectBuilder {
fn to(&self, x2: i32, y2: i32) -> LayoutRect;
}
// Allows doing `(x, y).to(x2, y2)` to build a LayoutRect
impl HandyDandyRectBuilder for (i32, i32) {
fn to(&self, x2: i32, y2: i32) -> LayoutRect {
LayoutRect::new(LayoutPoint::new(self.0 as f32, self.1 as f32),
LayoutSize::new((x2 - self.0) as f32, (y2 - self.1) as f32))
}
}
fn main() {
let args: Vec<String> = env::args().collect();
let res_path = if args.len() > 1 {
Some(PathBuf::from(&args[1]))
} else {
None
};
let window = glutin::WindowBuilder::new()
.with_title("WebRender Scrolling Sample")
.with_gl(glutin::GlRequest::GlThenGles {
opengl_version: (3, 2),
opengles_version: (3, 0)
})
.build()
.unwrap();
unsafe {
window.make_current().ok();
}
let gl = match gl::GlType::default() {
gl::GlType::Gl => unsafe { gl::GlFns::load_with(|symbol| window.get_proc_address(symbol) as *const _) },
gl::GlType::Gles => unsafe { gl::GlesFns::load_with(|symbol| window.get_proc_address(symbol) as *const _) },
};
println!("OpenGL version {}", gl.get_string(gl::VERSION));
println!("Shader resource path: {:?}", res_path);
let (width, height) = window.get_inner_size_pixels().unwrap();
let opts = webrender::RendererOptions {
resource_override_path: res_path,
debug: true,
precache_shaders: true,
device_pixel_ratio: window.hidpi_factor(),
.. Default::default()
};
let size = DeviceUintSize::new(width, height);
let (mut renderer, sender) = webrender::renderer::Renderer::new(gl, opts, size).unwrap();
let api = sender.create_api();
let notifier = Box::new(Notifier::new(window.create_window_proxy()));
renderer.set_render_notifier(notifier);
let epoch = Epoch(0);
let root_background_color = ColorF::new(0.3, 0.0, 0.0, 1.0);
let pipeline_id = PipelineId(0, 0);
let layout_size = LayoutSize::new(width as f32, height as f32);
let mut builder = webrender_traits::DisplayListBuilder::new(pipeline_id, layout_size);
let bounds = LayoutRect::new(LayoutPoint::zero(), layout_size);
builder.push_stacking_context(webrender_traits::ScrollPolicy::Scrollable,
bounds,
None,
@ -46,7 +127,7 @@ fn body(_api: &RenderApi,
let clip = builder.push_clip_region(&scrollbox, vec![], None);
let clip_id = builder.define_clip((0, 0).to(1000, 1000),
clip,
Some(ClipId::new(42, *pipeline_id)));
Some(ClipId::new(42, pipeline_id)));
builder.push_clip_id(clip_id);
// now put some content into it.
// start with a white background
@ -72,7 +153,7 @@ fn body(_api: &RenderApi,
let clip = builder.push_clip_region(&(0, 100).to(200, 300), vec![], None);
let nested_clip_id = builder.define_clip((0, 100).to(300, 400),
clip,
Some(ClipId::new(43, *pipeline_id)));
Some(ClipId::new(43, pipeline_id)));
builder.push_clip_id(nested_clip_id);
// give it a giant gray background just to distinguish it and to easily
// visually identify the nested scrollbox
@ -100,51 +181,68 @@ fn body(_api: &RenderApi,
}
builder.pop_stacking_context();
}
lazy_static! {
static ref CURSOR_POSITION: Mutex<WorldPoint> = Mutex::new(WorldPoint::zero());
}
api.set_display_list(
Some(root_background_color),
epoch,
LayoutSize::new(width as f32, height as f32),
builder.finalize(),
true);
api.set_root_pipeline(pipeline_id);
api.generate_frame(None);
fn event_handler(event: &glutin::Event,
api: &RenderApi)
{
match *event {
glutin::Event::KeyboardInput(glutin::ElementState::Pressed, _, Some(key)) => {
let offset = match key {
glutin::VirtualKeyCode::Down => (0.0, -10.0),
glutin::VirtualKeyCode::Up => (0.0, 10.0),
glutin::VirtualKeyCode::Right => (-10.0, 0.0),
glutin::VirtualKeyCode::Left => (10.0, 0.0),
_ => return,
};
let mut cursor_position = WorldPoint::zero();
api.scroll(ScrollLocation::Delta(LayoutVector2D::new(offset.0, offset.1)),
*CURSOR_POSITION.lock().unwrap(),
ScrollEventPhase::Start);
'outer: for event in window.wait_events() {
let mut events = Vec::new();
events.push(event);
for event in window.poll_events() {
events.push(event);
}
glutin::Event::MouseMoved(x, y) => {
*CURSOR_POSITION.lock().unwrap() = WorldPoint::new(x as f32, y as f32);
}
glutin::Event::MouseWheel(delta, _, event_cursor_position) => {
if let Some((x, y)) = event_cursor_position {
*CURSOR_POSITION.lock().unwrap() = WorldPoint::new(x as f32, y as f32);
for event in events {
match event {
glutin::Event::Closed |
glutin::Event::KeyboardInput(_, _, Some(glutin::VirtualKeyCode::Escape)) |
glutin::Event::KeyboardInput(_, _, Some(glutin::VirtualKeyCode::Q)) => break 'outer,
glutin::Event::KeyboardInput(glutin::ElementState::Pressed, _, Some(key)) => {
let offset = match key {
glutin::VirtualKeyCode::Down => (0.0, -10.0),
glutin::VirtualKeyCode::Up => (0.0, 10.0),
glutin::VirtualKeyCode::Right => (-10.0, 0.0),
glutin::VirtualKeyCode::Left => (10.0, 0.0),
_ => continue,
};
api.scroll(ScrollLocation::Delta(LayoutPoint::new(offset.0, offset.1)),
cursor_position,
ScrollEventPhase::Start);
}
glutin::Event::MouseMoved(x, y) => {
cursor_position = WorldPoint::new(x as f32, y as f32);
}
glutin::Event::MouseWheel(delta, _, event_cursor_position) => {
if let Some((x, y)) = event_cursor_position {
cursor_position = WorldPoint::new(x as f32, y as f32);
}
const LINE_HEIGHT: f32 = 38.0;
let (dx, dy) = match delta {
glutin::MouseScrollDelta::LineDelta(dx, dy) => (dx, dy * LINE_HEIGHT),
glutin::MouseScrollDelta::PixelDelta(dx, dy) => (dx, dy),
};
api.scroll(ScrollLocation::Delta(LayoutPoint::new(dx, dy)),
cursor_position,
ScrollEventPhase::Start);
}
_ => ()
}
const LINE_HEIGHT: f32 = 38.0;
let (dx, dy) = match delta {
glutin::MouseScrollDelta::LineDelta(dx, dy) => (dx, dy * LINE_HEIGHT),
glutin::MouseScrollDelta::PixelDelta(dx, dy) => (dx, dy),
};
api.scroll(ScrollLocation::Delta(LayoutVector2D::new(dx, dy)),
*CURSOR_POSITION.lock().unwrap(),
ScrollEventPhase::Start);
}
_ => ()
renderer.update();
renderer.render(DeviceUintSize::new(width, height));
window.swap_buffers().ok();
}
}
fn main() {
boilerplate::main_wrapper(body, event_handler, None);
}

Просмотреть файл

@ -8,19 +8,18 @@
// as text-shadow.
void main(void) {
Primitive prim = load_primitive();
TextRun text = fetch_text_run(prim.specific_prim_address);
int glyph_index = prim.user_data0;
int resource_address = prim.user_data1;
Glyph glyph = fetch_glyph(prim.specific_prim_address, glyph_index);
ResourceRect res = fetch_resource_rect(resource_address + glyph_index);
PrimitiveInstance pi = fetch_prim_instance();
RenderTaskData task = fetch_render_task(pi.render_task_index);
TextRun text = fetch_text_run(pi.specific_prim_address);
Glyph glyph = fetch_glyph(pi.user_data0);
PrimitiveGeometry pg = fetch_prim_geometry(pi.global_prim_index);
ResourceRect res = fetch_resource_rect(pi.user_data1);
// Glyphs size is already in device-pixels.
// The render task origin is in device-pixels. Offset that by
// the glyph offset, relative to its primitive bounding rect.
vec2 size = res.uv_rect.zw - res.uv_rect.xy;
vec2 origin = prim.task.screen_space_origin + uDevicePixelRatio * (glyph.offset - prim.local_rect.p0);
vec2 origin = task.data0.xy + uDevicePixelRatio * (glyph.offset.xy - pg.local_rect.p0);
vec4 local_rect = vec4(origin, size);
vec2 texture_size = vec2(textureSize(sColor0, 0));

Просмотреть файл

@ -106,43 +106,21 @@ varying vec3 vClipMaskUv;
flat varying vec4 vLocalBounds;
#endif
// TODO(gw): This is here temporarily while we have
// both GPU store and cache. When the GPU
// store code is removed, we can change the
// PrimitiveInstance instance structure to
// use 2x unsigned shorts as vertex attributes
// instead of an int, and encode the UV directly
// in the vertices.
ivec2 get_resource_cache_uv(int address) {
return ivec2(address % WR_MAX_VERTEX_TEXTURE_WIDTH,
address / WR_MAX_VERTEX_TEXTURE_WIDTH);
}
uniform sampler2D sResourceCache;
vec4[2] fetch_from_resource_cache_2(int address) {
ivec2 uv = get_resource_cache_uv(address);
return vec4[2](
texelFetchOffset(sResourceCache, uv, 0, ivec2(0, 0)),
texelFetchOffset(sResourceCache, uv, 0, ivec2(1, 0))
);
}
#ifdef WR_VERTEX_SHADER
#define VECS_PER_LAYER 9
#define VECS_PER_RENDER_TASK 3
#define VECS_PER_PRIM_HEADER 2
#define VECS_PER_TEXT_RUN 1
#define VECS_PER_GRADIENT 3
#define VECS_PER_GRADIENT_STOP 2
#define VECS_PER_PRIM_GEOM 2
#define VECS_PER_SPLIT_GEOM 3
uniform sampler2D sLayers;
uniform sampler2D sRenderTasks;
uniform sampler2D sPrimGeometry;
uniform sampler2D sData16;
uniform sampler2D sData32;
uniform sampler2D sResourceRects;
uniform sampler2D sResourceCache;
// Instanced attributes
in ivec4 aData0;
@ -167,6 +145,18 @@ vec4[2] fetch_data_2(int index) {
);
}
// TODO(gw): This is here temporarily while we have
// both GPU store and cache. When the GPU
// store code is removed, we can change the
// PrimitiveInstance instance structure to
// use 2x unsigned shorts as vertex attributes
// instead of an int, and encode the UV directly
// in the vertices.
ivec2 get_resource_cache_uv(int address) {
return ivec2(address % WR_MAX_VERTEX_TEXTURE_WIDTH,
address / WR_MAX_VERTEX_TEXTURE_WIDTH);
}
vec4[8] fetch_from_resource_cache_8(int address) {
ivec2 uv = get_resource_cache_uv(address);
return vec4[8](
@ -331,8 +321,8 @@ struct GradientStop {
vec4 offset;
};
GradientStop fetch_gradient_stop(int address) {
vec4 data[2] = fetch_from_resource_cache_2(address);
GradientStop fetch_gradient_stop(int index) {
vec4 data[2] = fetch_data_2(index);
return GradientStop(data[0], data[1]);
}
@ -427,18 +417,12 @@ BorderCorners get_border_corners(Border border, RectWithSize local_rect) {
}
struct Glyph {
vec2 offset;
vec4 offset;
};
Glyph fetch_glyph(int specific_prim_address, int glyph_index) {
// Two glyphs are packed in each texel in the GPU cache.
int glyph_address = specific_prim_address +
VECS_PER_TEXT_RUN +
glyph_index / 2;
vec4 data = fetch_from_resource_cache_1(glyph_address);
// Select XY or ZW based on glyph index.
vec2 glyph = mix(data.xy, data.zw, bvec2(glyph_index % 2 == 1));
return Glyph(glyph);
Glyph fetch_glyph(int index) {
vec4 data = fetch_data_1(index);
return Glyph(data);
}
RectWithSize fetch_instance_geometry(int address) {
@ -446,8 +430,26 @@ RectWithSize fetch_instance_geometry(int address) {
return RectWithSize(data.xy, data.zw);
}
struct PrimitiveGeometry {
RectWithSize local_rect;
RectWithSize local_clip_rect;
};
PrimitiveGeometry fetch_prim_geometry(int index) {
PrimitiveGeometry pg;
ivec2 uv = get_fetch_uv(index, VECS_PER_PRIM_GEOM);
vec4 local_rect = texelFetchOffset(sPrimGeometry, uv, 0, ivec2(0, 0));
pg.local_rect = RectWithSize(local_rect.xy, local_rect.zw);
vec4 local_clip_rect = texelFetchOffset(sPrimGeometry, uv, 0, ivec2(1, 0));
pg.local_clip_rect = RectWithSize(local_clip_rect.xy, local_clip_rect.zw);
return pg;
}
struct PrimitiveInstance {
int prim_address;
int global_prim_index;
int specific_prim_address;
int render_task_index;
int clip_task_index;
@ -460,14 +462,14 @@ struct PrimitiveInstance {
PrimitiveInstance fetch_prim_instance() {
PrimitiveInstance pi;
pi.prim_address = aData0.x;
pi.specific_prim_address = pi.prim_address + VECS_PER_PRIM_HEADER;
pi.render_task_index = aData0.y;
pi.clip_task_index = aData0.z;
pi.layer_index = aData0.w;
pi.z = aData1.x;
pi.user_data0 = aData1.y;
pi.user_data1 = aData1.z;
pi.global_prim_index = aData0.x;
pi.specific_prim_address = aData0.y;
pi.render_task_index = aData0.z;
pi.clip_task_index = aData0.w;
pi.layer_index = aData1.x;
pi.z = aData1.y;
pi.user_data0 = aData1.z;
pi.user_data1 = aData1.w;
return pi;
}
@ -501,26 +503,24 @@ struct Primitive {
AlphaBatchTask task;
RectWithSize local_rect;
RectWithSize local_clip_rect;
int specific_prim_address;
int prim_index;
int user_data0;
int user_data1;
float z;
};
Primitive load_primitive() {
PrimitiveInstance pi = fetch_prim_instance();
Primitive load_primitive_custom(PrimitiveInstance pi) {
Primitive prim;
prim.layer = fetch_layer(pi.layer_index);
prim.clip_area = fetch_clip_area(pi.clip_task_index);
prim.task = fetch_alpha_batch_task(pi.render_task_index);
vec4 geom[2] = fetch_from_resource_cache_2(pi.prim_address);
prim.local_rect = RectWithSize(geom[0].xy, geom[0].zw);
prim.local_clip_rect = RectWithSize(geom[1].xy, geom[1].zw);
PrimitiveGeometry pg = fetch_prim_geometry(pi.global_prim_index);
prim.local_rect = pg.local_rect;
prim.local_clip_rect = pg.local_clip_rect;
prim.specific_prim_address = pi.specific_prim_address;
prim.prim_index = pi.specific_prim_address;
prim.user_data0 = pi.user_data0;
prim.user_data1 = pi.user_data1;
prim.z = float(pi.z);
@ -528,6 +528,13 @@ Primitive load_primitive() {
return prim;
}
Primitive load_primitive() {
PrimitiveInstance pi = fetch_prim_instance();
return load_primitive_custom(pi);
}
// Return the intersection of the plane (set up by "normal" and "point")
// with the ray (set up by "ray_origin" and "ray_dir"),
// writing the resulting scaler into "t".
@ -850,8 +857,10 @@ vec4 dither(vec4 color) {
}
#endif //WR_FEATURE_DITHERING
vec4 sample_gradient(int address, float offset, float gradient_repeat) {
// Modulo the offset if the gradient repeats.
vec4 sample_gradient(float offset, float gradient_repeat, float gradient_index, vec2 gradient_size) {
// Modulo the offset if the gradient repeats. We don't need to clamp non-repeating
// gradients because the gradient data texture is bound with CLAMP_TO_EDGE, and the
// first and last color entries are filled with the first and last stop colors
float x = mix(offset, fract(offset), gradient_repeat);
// Calculate the color entry index to use for this offset:
@ -859,25 +868,22 @@ vec4 sample_gradient(int address, float offset, float gradient_repeat) {
// offsets from [0, 1) use the color entries in the range of [1, N-1)
// offsets >= 1 use the last color entry, N-1
// so transform the range [0, 1) -> [1, N-1)
// TODO(gw): In the future we might consider making the size of the
// LUT vary based on number / distribution of stops in the gradient.
const int GRADIENT_ENTRIES = 128;
x = 1.0 + x * float(GRADIENT_ENTRIES);
float gradient_entries = 0.5 * gradient_size.x;
x = x * (gradient_entries - 2.0) + 1.0;
// Calculate the texel to index into the gradient color entries:
// floor(x) is the gradient color entry index
// fract(x) is the linear filtering factor between start and end
int lut_offset = 2 * int(floor(x)); // There is a [start, end] color per entry.
// so, 2 * floor(x) + 0.5 is the center of the start color
// finally, add floor(x) to interpolate to end
x = 2.0 * floor(x) + 0.5 + fract(x);
// Ensure we don't fetch outside the valid range of the LUT.
lut_offset = clamp(lut_offset, 0, 2 * (GRADIENT_ENTRIES + 1));
// Gradient color entries are encoded with high bits in one row and low bits in the next
// So use linear filtering to mix (gradient_index + 1) with (gradient_index)
float y = gradient_index * 2.0 + 0.5 + 1.0 / 256.0;
// Fetch the start and end color.
vec4 texels[2] = fetch_from_resource_cache_2(address + lut_offset);
// Finally interpolate and apply dithering
return dither(mix(texels[0], texels[1], fract(x)));
// Finally sample and apply dithering
return dither(texture(sGradients, vec2(x, y) / gradient_size));
}
//

Просмотреть файл

@ -1,5 +1,3 @@
#line 1
/* 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/. */
@ -14,7 +12,8 @@ void main(void) {
float offset = dot(pos - vStartPoint, vScaledDir);
oFragColor = sample_gradient(vGradientAddress,
offset,
vGradientRepeat);
oFragColor = sample_gradient(offset,
vGradientRepeat,
vGradientIndex,
vGradientTextureSize);
}

Просмотреть файл

@ -2,7 +2,8 @@
* 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/. */
flat varying int vGradientAddress;
flat varying float vGradientIndex;
flat varying vec2 vGradientTextureSize;
flat varying float vGradientRepeat;
flat varying vec2 vScaledDir;

Просмотреть файл

@ -5,7 +5,7 @@
void main(void) {
Primitive prim = load_primitive();
Gradient gradient = fetch_gradient(prim.specific_prim_address);
Gradient gradient = fetch_gradient(prim.prim_index);
VertexInfo vi = write_vertex(prim.local_rect,
prim.local_clip_rect,
@ -26,7 +26,11 @@ void main(void) {
vTileSize = gradient.tile_size_repeat.xy;
vTileRepeat = gradient.tile_size_repeat.zw;
vGradientAddress = prim.specific_prim_address + VECS_PER_GRADIENT;
// V coordinate of gradient row in lookup texture.
vGradientIndex = float(prim.user_data0);
// The texture size of the lookup texture
vGradientTextureSize = vec2(textureSize(sGradients, 0));
// Whether to repeat the gradient instead of clamping.
vGradientRepeat = float(int(gradient.extend_mode.x) == EXTEND_MODE_REPEAT);

Просмотреть файл

@ -117,7 +117,7 @@ int select_style(int color_select, vec2 fstyle) {
void main(void) {
Primitive prim = load_primitive();
Border border = fetch_border(prim.specific_prim_address);
Border border = fetch_border(prim.prim_index);
int sub_part = prim.user_data0;
BorderCorners corners = get_border_corners(border, prim.local_rect);

Просмотреть файл

@ -104,7 +104,7 @@ void write_clip_params(float style,
void main(void) {
Primitive prim = load_primitive();
Border border = fetch_border(prim.specific_prim_address);
Border border = fetch_border(prim.prim_index);
int sub_part = prim.user_data0;
BorderCorners corners = get_border_corners(border, prim.local_rect);
vec4 color = border.colors[sub_part];

Просмотреть файл

@ -7,8 +7,8 @@
void main(void) {
Primitive prim = load_primitive();
BoxShadow bs = fetch_boxshadow(prim.specific_prim_address);
RectWithSize segment_rect = fetch_instance_geometry(prim.specific_prim_address + BS_HEADER_VECS + prim.user_data0);
BoxShadow bs = fetch_boxshadow(prim.prim_index);
RectWithSize segment_rect = fetch_instance_geometry(prim.prim_index + BS_HEADER_VECS + prim.user_data0);
VertexInfo vi = write_vertex(segment_rect,
prim.local_clip_rect,

Просмотреть файл

@ -5,16 +5,12 @@
void main(void) {
Primitive prim = load_primitive();
Gradient gradient = fetch_gradient(prim.specific_prim_address);
Gradient gradient = fetch_gradient(prim.prim_index);
vec4 abs_start_end_point = gradient.start_end_point + prim.local_rect.p0.xyxy;
int stop_address = prim.specific_prim_address +
VECS_PER_GRADIENT +
VECS_PER_GRADIENT_STOP * prim.user_data0;
GradientStop g0 = fetch_gradient_stop(stop_address);
GradientStop g1 = fetch_gradient_stop(stop_address + VECS_PER_GRADIENT_STOP);
GradientStop g0 = fetch_gradient_stop(prim.user_data0 + 0);
GradientStop g1 = fetch_gradient_stop(prim.user_data0 + 1);
RectWithSize segment_rect;
vec2 axis;

Просмотреть файл

@ -5,7 +5,7 @@
void main(void) {
Primitive prim = load_primitive();
Image image = fetch_image(prim.specific_prim_address);
Image image = fetch_image(prim.prim_index);
ResourceRect res = fetch_resource_rect(prim.user_data0);
#ifdef WR_FEATURE_TRANSFORM

Просмотреть файл

@ -49,7 +49,8 @@ void main(void) {
}
}
oFragColor = sample_gradient(vGradientAddress,
offset,
vGradientRepeat);
oFragColor = sample_gradient(offset,
vGradientRepeat,
vGradientIndex,
vGradientTextureSize);
}

Просмотреть файл

@ -2,7 +2,8 @@
* 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/. */
flat varying int vGradientAddress;
flat varying float vGradientIndex;
flat varying vec2 vGradientTextureSize;
flat varying float vGradientRepeat;
flat varying vec2 vStartCenter;

Просмотреть файл

@ -5,7 +5,7 @@
void main(void) {
Primitive prim = load_primitive();
RadialGradient gradient = fetch_radial_gradient(prim.specific_prim_address);
RadialGradient gradient = fetch_radial_gradient(prim.prim_index);
VertexInfo vi = write_vertex(prim.local_rect,
prim.local_clip_rect,
@ -34,7 +34,11 @@ void main(void) {
vTileSize.y *= ratio_xy;
vTileRepeat.y *= ratio_xy;
vGradientAddress = prim.specific_prim_address + VECS_PER_GRADIENT;
// V coordinate of gradient row in lookup texture.
vGradientIndex = float(prim.user_data0);
// The texture size of the lookup texture
vGradientTextureSize = vec2(textureSize(sGradients, 0));
// Whether to repeat the gradient instead of clamping.
vGradientRepeat = float(int(gradient.start_end_radius_ratio_xy_extend_mode.w) == EXTEND_MODE_REPEAT);

Просмотреть файл

@ -5,7 +5,7 @@
void main(void) {
Primitive prim = load_primitive();
Rectangle rect = fetch_rectangle(prim.specific_prim_address);
Rectangle rect = fetch_rectangle(prim.prim_index);
vColor = rect.color;
#ifdef WR_FEATURE_TRANSFORM
TransformVertexInfo vi = write_transform_vertex(prim.local_rect,

Просмотреть файл

@ -3,16 +3,18 @@
* 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/. */
uniform sampler2D sSplitGeometry;
struct SplitGeometry {
vec3 points[4];
};
SplitGeometry fetch_split_geometry(int address) {
ivec2 uv = get_resource_cache_uv(address);
SplitGeometry fetch_split_geometry(int index) {
ivec2 uv = get_fetch_uv(index, VECS_PER_SPLIT_GEOM);
vec4 data0 = texelFetchOffset(sResourceCache, uv, 0, ivec2(0, 0));
vec4 data1 = texelFetchOffset(sResourceCache, uv, 0, ivec2(1, 0));
vec4 data2 = texelFetchOffset(sResourceCache, uv, 0, ivec2(2, 0));
vec4 data0 = texelFetchOffset(sSplitGeometry, uv, 0, ivec2(0, 0));
vec4 data1 = texelFetchOffset(sSplitGeometry, uv, 0, ivec2(1, 0));
vec4 data2 = texelFetchOffset(sSplitGeometry, uv, 0, ivec2(2, 0));
SplitGeometry geo;
geo.points = vec3[4](

Просмотреть файл

@ -5,14 +5,11 @@
void main(void) {
Primitive prim = load_primitive();
TextRun text = fetch_text_run(prim.specific_prim_address);
TextRun text = fetch_text_run(prim.prim_index);
Glyph glyph = fetch_glyph(prim.user_data0);
ResourceRect res = fetch_resource_rect(prim.user_data1);
int glyph_index = prim.user_data0;
int resource_address = prim.user_data1;
Glyph glyph = fetch_glyph(prim.specific_prim_address, glyph_index);
ResourceRect res = fetch_resource_rect(resource_address + glyph_index);
RectWithSize local_rect = RectWithSize(glyph.offset,
RectWithSize local_rect = RectWithSize(glyph.offset.xy,
(res.uv_rect.zw - res.uv_rect.xy) / uDevicePixelRatio);
#ifdef WR_FEATURE_TRANSFORM

Просмотреть файл

@ -67,7 +67,7 @@ void main(void) {
#endif
#endif
YuvImage image = fetch_yuv_image(prim.specific_prim_address);
YuvImage image = fetch_yuv_image(prim.prim_index);
vStretchSize = image.size;
vHalfTexelY = vec2(0.5) / y_texture_size_normalization_factor;

Просмотреть файл

@ -2,6 +2,7 @@
* 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 euclid::Point3D;
use geometry::ray_intersects_rect;
use mask_cache::{ClipSource, MaskCacheInfo, RegionMode};
use prim_store::GpuBlock32;
@ -12,8 +13,7 @@ use util::TransformedRectKind;
use webrender_traits::{ClipId, ClipRegion, DeviceIntRect, LayerPixel, LayerPoint, LayerRect};
use webrender_traits::{LayerSize, LayerToScrollTransform, LayerToWorldTransform, PipelineId};
use webrender_traits::{ScrollClamping, ScrollEventPhase, ScrollLayerRect, ScrollLocation};
use webrender_traits::{WorldPoint, LayerVector2D};
use webrender_traits::{as_scroll_parent_vector};
use webrender_traits::{WorldPoint, WorldPoint4D};
#[cfg(target_os = "macos")]
const CAN_OVERSCROLL: bool = true;
@ -72,14 +72,14 @@ pub enum NodeType {
/// Other nodes just do clipping, but no transformation.
Clip(ClipInfo),
/// Other nodes just do clipping, but no transformation.
ScrollFrame(ScrollingState),
}
/// Contains information common among all types of ClipScrollTree nodes.
/// Contains scrolling and transform information stacking contexts.
#[derive(Clone, Debug)]
pub struct ClipScrollNode {
/// Manages scrolling offset, overscroll state etc.
pub scrolling: ScrollingState,
/// Size of the content inside the scroll region (in logical pixels)
pub content_size: LayerSize,
@ -105,7 +105,7 @@ pub struct ClipScrollNode {
/// The scroll offset of all the nodes between us and our parent reference frame.
/// This is used to calculate intersections between us and content or nodes that
/// are also direct children of our reference frame.
pub reference_frame_relative_scroll_offset: LayerVector2D,
pub reference_frame_relative_scroll_offset: LayerPoint,
/// Pipeline that this layer belongs to
pub pipeline_id: PipelineId,
@ -121,26 +121,6 @@ pub struct ClipScrollNode {
}
impl ClipScrollNode {
pub fn new_scroll_frame(pipeline_id: PipelineId,
parent_id: ClipId,
content_rect: &LayerRect,
frame_rect: &LayerRect)
-> ClipScrollNode {
ClipScrollNode {
content_size: content_rect.size,
local_viewport_rect: *frame_rect,
local_clip_rect: *frame_rect,
combined_local_viewport_rect: LayerRect::zero(),
world_viewport_transform: LayerToWorldTransform::identity(),
world_content_transform: LayerToWorldTransform::identity(),
reference_frame_relative_scroll_offset: LayerVector2D::zero(),
parent: Some(parent_id),
children: Vec::new(),
pipeline_id: pipeline_id,
node_type: NodeType::ScrollFrame(ScrollingState::new()),
}
}
pub fn new(pipeline_id: PipelineId,
parent_id: ClipId,
content_rect: &LayerRect,
@ -151,13 +131,14 @@ impl ClipScrollNode {
// of the node.
let local_viewport_rect = LayerRect::new(content_rect.origin, clip_rect.size);
ClipScrollNode {
scrolling: ScrollingState::new(),
content_size: content_rect.size,
local_viewport_rect: local_viewport_rect,
local_clip_rect: local_viewport_rect,
combined_local_viewport_rect: LayerRect::zero(),
world_viewport_transform: LayerToWorldTransform::identity(),
world_content_transform: LayerToWorldTransform::identity(),
reference_frame_relative_scroll_offset: LayerVector2D::zero(),
reference_frame_relative_scroll_offset: LayerPoint::zero(),
parent: Some(parent_id),
children: Vec::new(),
pipeline_id: pipeline_id,
@ -172,13 +153,14 @@ impl ClipScrollNode {
pipeline_id: PipelineId)
-> ClipScrollNode {
ClipScrollNode {
scrolling: ScrollingState::new(),
content_size: content_size,
local_viewport_rect: *local_viewport_rect,
local_clip_rect: *local_viewport_rect,
combined_local_viewport_rect: LayerRect::zero(),
world_viewport_transform: LayerToWorldTransform::identity(),
world_content_transform: LayerToWorldTransform::identity(),
reference_frame_relative_scroll_offset: LayerVector2D::zero(),
reference_frame_relative_scroll_offset: LayerPoint::zero(),
parent: parent_id,
children: Vec::new(),
pipeline_id: pipeline_id,
@ -190,26 +172,45 @@ impl ClipScrollNode {
self.children.push(child);
}
pub fn finalize(&mut self, new_scrolling: &ScrollingState) {
match self.node_type {
NodeType::ReferenceFrame(_) | NodeType::Clip(_) =>
warn!("Tried to scroll a non-scroll node."),
NodeType::ScrollFrame(ref mut scrolling) => *scrolling = *new_scrolling,
}
pub fn finalize(&mut self, scrolling: &ScrollingState) {
self.scrolling = *scrolling;
}
pub fn overscroll_amount(&self) -> LayerSize {
let scrollable_width = self.scrollable_width();
let overscroll_x = if self.scrolling.offset.x > 0.0 {
-self.scrolling.offset.x
} else if self.scrolling.offset.x < -scrollable_width {
-scrollable_width - self.scrolling.offset.x
} else {
0.0
};
let scrollable_height = self.scrollable_height();
let overscroll_y = if self.scrolling.offset.y > 0.0 {
-self.scrolling.offset.y
} else if self.scrolling.offset.y < -scrollable_height {
-scrollable_height - self.scrolling.offset.y
} else {
0.0
};
LayerSize::new(overscroll_x, overscroll_y)
}
pub fn set_scroll_origin(&mut self, origin: &LayerPoint, clamp: ScrollClamping) -> bool {
let scrollable_height = self.scrollable_height();
let scrollable_width = self.scrollable_width();
let scrolling = match self.node_type {
NodeType::ReferenceFrame(_) | NodeType::Clip(_) => {
warn!("Tried to scroll a non-scroll node.");
match self.node_type {
NodeType::ReferenceFrame(_) => {
warn!("Tried to scroll a reference frame.");
return false;
}
NodeType::ScrollFrame(ref mut scrolling) => scrolling,
NodeType::Clip(_) => {}
};
let scrollable_height = self.scrollable_height();
let scrollable_width = self.scrollable_width();
let new_offset = match clamp {
ScrollClamping::ToContentBounds => {
if scrollable_height <= 0. && scrollable_width <= 0. {
@ -217,35 +218,35 @@ impl ClipScrollNode {
}
let origin = LayerPoint::new(origin.x.max(0.0), origin.y.max(0.0));
LayerVector2D::new((-origin.x).max(-scrollable_width).min(0.0).round(),
(-origin.y).max(-scrollable_height).min(0.0).round())
LayerPoint::new((-origin.x).max(-scrollable_width).min(0.0).round(),
(-origin.y).max(-scrollable_height).min(0.0).round())
}
ScrollClamping::NoClamping => LayerPoint::zero() - *origin,
};
if new_offset == scrolling.offset {
if new_offset == self.scrolling.offset {
return false;
}
scrolling.offset = new_offset;
scrolling.bouncing_back = false;
scrolling.started_bouncing_back = false;
self.scrolling.offset = new_offset;
self.scrolling.bouncing_back = false;
self.scrolling.started_bouncing_back = false;
true
}
pub fn update_transform(&mut self,
parent_reference_frame_transform: &LayerToWorldTransform,
parent_combined_viewport_rect: &ScrollLayerRect,
parent_scroll_offset: LayerVector2D,
parent_accumulated_scroll_offset: LayerVector2D) {
parent_scroll_offset: LayerPoint,
parent_accumulated_scroll_offset: LayerPoint) {
self.reference_frame_relative_scroll_offset = match self.node_type {
NodeType::ReferenceFrame(_) => LayerVector2D::zero(),
NodeType::Clip(_) | NodeType::ScrollFrame(..) => parent_accumulated_scroll_offset,
NodeType::ReferenceFrame(_) => LayerPoint::zero(),
NodeType::Clip(_) => parent_accumulated_scroll_offset,
};
let local_transform = match self.node_type {
NodeType::ReferenceFrame(transform) => transform,
NodeType::Clip(_) | NodeType::ScrollFrame(..) => LayerToScrollTransform::identity(),
NodeType::Clip(_) => LayerToScrollTransform::identity(),
};
let inv_transform = match local_transform.inverse() {
@ -264,14 +265,14 @@ impl ClipScrollNode {
// local viewport rect doesn't include scrolling offsets so the only one that matters
// is the relative offset between us and the parent.
let parent_combined_viewport_in_local_space =
inv_transform.pre_translate(-as_scroll_parent_vector(&parent_scroll_offset).to_3d())
inv_transform.pre_translated(-parent_scroll_offset.x, -parent_scroll_offset.y, 0.0)
.transform_rect(parent_combined_viewport_rect);
// Now that we have the combined viewport rectangle of the parent nodes in local space,
// we do the intersection and get our combined viewport rect in the coordinate system
// starting from our origin.
self.combined_local_viewport_rect = match self.node_type {
NodeType::Clip(_) | NodeType::ScrollFrame(..) => {
NodeType::Clip(_) => {
parent_combined_viewport_in_local_space.intersection(&self.local_clip_rect)
.unwrap_or(LayerRect::zero())
}
@ -290,14 +291,17 @@ impl ClipScrollNode {
// with the local_viewport_rect to get its position in world space.
self.world_viewport_transform =
parent_reference_frame_transform
.pre_translate(parent_accumulated_scroll_offset.to_3d())
.pre_translated(parent_accumulated_scroll_offset.x,
parent_accumulated_scroll_offset.y,
0.0)
.pre_mul(&local_transform.with_destination::<LayerPixel>());
// The transformation for any content inside of us is the viewport transformation, plus
// whatever scrolling offset we supply as well.
let scroll_offset = self.scroll_offset();
self.world_content_transform =
self.world_viewport_transform.pre_translate(scroll_offset.to_3d());
self.world_viewport_transform.pre_translated(self.scrolling.offset.x,
self.scrolling.offset.y,
0.0);
}
pub fn scrollable_height(&self) -> f32 {
@ -309,89 +313,95 @@ impl ClipScrollNode {
}
pub fn scroll(&mut self, scroll_location: ScrollLocation, phase: ScrollEventPhase) -> bool {
let scrollable_width = self.scrollable_width();
let scrollable_height = self.scrollable_height();
let scrolling = match self.node_type {
NodeType::ReferenceFrame(_) | NodeType::Clip(_) => return false,
NodeType::ScrollFrame(ref mut scrolling) => scrolling,
};
if scrolling.started_bouncing_back && phase == ScrollEventPhase::Move(false) {
if self.scrolling.started_bouncing_back && phase == ScrollEventPhase::Move(false) {
return false;
}
let mut delta = match scroll_location {
ScrollLocation::Delta(delta) => delta,
ScrollLocation::Start => {
if scrolling.offset.y.round() >= 0.0 {
if self.scrolling.offset.y.round() >= 0.0 {
// Nothing to do on this layer.
return false;
}
scrolling.offset.y = 0.0;
self.scrolling.offset.y = 0.0;
return true;
},
ScrollLocation::End => {
let end_pos = self.local_viewport_rect.size.height - self.content_size.height;
if scrolling.offset.y.round() <= end_pos {
if self.scrolling.offset.y.round() <= end_pos {
// Nothing to do on this layer.
return false;
}
scrolling.offset.y = end_pos;
self.scrolling.offset.y = end_pos;
return true;
}
};
let overscroll_amount = scrolling.overscroll_amount(scrollable_width, scrollable_height);
let overscrolling = CAN_OVERSCROLL && (overscroll_amount.x != 0.0 ||
overscroll_amount.y != 0.0);
let overscroll_amount = self.overscroll_amount();
let overscrolling = CAN_OVERSCROLL && (overscroll_amount.width != 0.0 ||
overscroll_amount.height != 0.0);
if overscrolling {
if overscroll_amount.x != 0.0 {
delta.x /= overscroll_amount.x.abs()
if overscroll_amount.width != 0.0 {
delta.x /= overscroll_amount.width.abs()
}
if overscroll_amount.y != 0.0 {
delta.y /= overscroll_amount.y.abs()
if overscroll_amount.height != 0.0 {
delta.y /= overscroll_amount.height.abs()
}
}
let scrollable_width = self.scrollable_width();
let scrollable_height = self.scrollable_height();
let is_unscrollable = scrollable_width <= 0. && scrollable_height <= 0.;
let original_layer_scroll_offset = scrolling.offset;
let original_layer_scroll_offset = self.scrolling.offset;
if scrollable_width > 0. {
scrolling.offset.x = scrolling.offset.x + delta.x;
self.scrolling.offset.x = self.scrolling.offset.x + delta.x;
if is_unscrollable || !CAN_OVERSCROLL {
scrolling.offset.x = scrolling.offset.x.min(0.0).max(-scrollable_width).round();
self.scrolling.offset.x =
self.scrolling.offset.x.min(0.0).max(-scrollable_width).round();
}
}
if scrollable_height > 0. {
scrolling.offset.y = scrolling.offset.y + delta.y;
self.scrolling.offset.y = self.scrolling.offset.y + delta.y;
if is_unscrollable || !CAN_OVERSCROLL {
scrolling.offset.y = scrolling.offset.y.min(0.0).max(-scrollable_height).round();
self.scrolling.offset.y =
self.scrolling.offset.y.min(0.0).max(-scrollable_height).round();
}
}
if phase == ScrollEventPhase::Start || phase == ScrollEventPhase::Move(true) {
scrolling.started_bouncing_back = false
self.scrolling.started_bouncing_back = false
} else if overscrolling &&
((delta.x < 1.0 && delta.y < 1.0) || phase == ScrollEventPhase::End) {
scrolling.started_bouncing_back = true;
scrolling.bouncing_back = true
self.scrolling.started_bouncing_back = true;
self.scrolling.bouncing_back = true
}
if CAN_OVERSCROLL {
scrolling.stretch_overscroll_spring(overscroll_amount);
self.stretch_overscroll_spring();
}
scrolling.offset != original_layer_scroll_offset || scrolling.started_bouncing_back
self.scrolling.offset != original_layer_scroll_offset ||
self.scrolling.started_bouncing_back
}
pub fn stretch_overscroll_spring(&mut self) {
let overscroll_amount = self.overscroll_amount();
self.scrolling.spring.coords(self.scrolling.offset,
self.scrolling.offset,
self.scrolling.offset + overscroll_amount);
}
pub fn tick_scrolling_bounce_animation(&mut self) {
if let NodeType::ScrollFrame(ref mut scrolling) = self.node_type {
scrolling.tick_scrolling_bounce_animation();
let finished = self.scrolling.spring.animate();
self.scrolling.offset = self.scrolling.spring.current();
if finished {
self.scrolling.bouncing_back = false
}
}
@ -400,89 +410,48 @@ impl ClipScrollNode {
let z0 = -10000.0;
let z1 = 10000.0;
let p0 = inv.transform_point3d(&cursor.extend(z0));
let p1 = inv.transform_point3d(&cursor.extend(z1));
let p0 = inv.transform_point4d(&WorldPoint4D::new(cursor.x, cursor.y, z0, 1.0));
let p0 = Point3D::new(p0.x / p0.w,
p0.y / p0.w,
p0.z / p0.w);
let p1 = inv.transform_point4d(&WorldPoint4D::new(cursor.x, cursor.y, z1, 1.0));
let p1 = Point3D::new(p1.x / p1.w,
p1.y / p1.w,
p1.z / p1.w);
if self.scrollable_width() <= 0. && self.scrollable_height() <= 0. {
return false;
}
ray_intersects_rect(p0.to_untyped(), p1.to_untyped(), self.local_viewport_rect.to_untyped())
ray_intersects_rect(p0, p1, self.local_viewport_rect.to_untyped())
}
pub fn scroll_offset(&self) -> LayerVector2D {
pub fn scroll_offset(&self) -> Option<LayerPoint> {
match self.node_type {
NodeType::ScrollFrame(ref scrolling) => scrolling.offset,
_ => LayerVector2D::zero(),
}
}
pub fn is_overscrolling(&self) -> bool {
match self.node_type {
NodeType::ScrollFrame(ref scrolling) => {
let overscroll_amount = scrolling.overscroll_amount(self.scrollable_width(),
self.scrollable_height());
overscroll_amount.x != 0.0 || overscroll_amount.y != 0.0
}
_ => false,
NodeType::Clip(_) if self.scrollable_width() > 0. || self.scrollable_height() > 0. =>
Some(self.scrolling.offset),
_ => None,
}
}
}
#[derive(Copy, Clone, Debug)]
pub struct ScrollingState {
pub offset: LayerVector2D,
pub offset: LayerPoint,
pub spring: Spring,
pub started_bouncing_back: bool,
pub bouncing_back: bool,
pub should_handoff_scroll: bool
}
/// Manages scrolling offset, overscroll state, etc.
impl ScrollingState {
pub fn new() -> ScrollingState {
ScrollingState {
offset: LayerVector2D::zero(),
offset: LayerPoint::zero(),
spring: Spring::at(LayerPoint::zero(), STIFFNESS, DAMPING),
started_bouncing_back: false,
bouncing_back: false,
should_handoff_scroll: false
}
}
pub fn stretch_overscroll_spring(&mut self, overscroll_amount: LayerVector2D) {
let offset = self.offset.to_point();
self.spring.coords(offset, offset, offset + overscroll_amount);
}
pub fn tick_scrolling_bounce_animation(&mut self) {
let finished = self.spring.animate();
self.offset = self.spring.current().to_vector();
if finished {
self.bouncing_back = false
}
}
pub fn overscroll_amount(&self,
scrollable_width: f32,
scrollable_height: f32)
-> LayerVector2D {
let overscroll_x = if self.offset.x > 0.0 {
-self.offset.x
} else if self.offset.x < -scrollable_width {
-scrollable_width - self.offset.x
} else {
0.0
};
let overscroll_y = if self.offset.y > 0.0 {
-self.offset.y
} else if self.offset.y < -scrollable_height {
-scrollable_height - self.offset.y
} else {
0.0
};
LayerVector2D::new(overscroll_x, overscroll_y)
}
}

Просмотреть файл

@ -10,7 +10,7 @@ use std::hash::BuildHasherDefault;
use webrender_traits::{ClipId, LayerPoint, LayerRect, LayerToScrollTransform};
use webrender_traits::{LayerToWorldTransform, PipelineId, ScrollClamping, ScrollEventPhase};
use webrender_traits::{ScrollLayerRect, ScrollLayerState, ScrollLocation, WorldPoint};
use webrender_traits::{as_scroll_parent_rect, LayerVector2D};
use webrender_traits::as_scroll_parent_rect;
pub type ScrollStates = HashMap<ClipId, ScrollingState, BuildHasherDefault<FnvHasher>>;
@ -22,10 +22,10 @@ pub struct ClipScrollTree {
/// node to scroll even if a touch operation leaves the boundaries of that node.
pub currently_scrolling_node_id: Option<ClipId>,
/// The current frame id, used for giving a unique id to all new dynamically
/// added frames and clips. The ClipScrollTree increments this by one every
/// time a new dynamic frame is created.
current_new_node_item: u64,
/// The current reference frame id, used for giving a unique id to all new
/// reference frames. The ClipScrollTree increments this by one every time a
/// reference frame is created.
current_reference_frame_id: u64,
/// The root reference frame, which is the true root of the ClipScrollTree. Initially
/// this ID is not valid, which is indicated by ```node``` being empty.
@ -49,7 +49,7 @@ impl ClipScrollTree {
currently_scrolling_node_id: None,
root_reference_frame_id: ClipId::root_reference_frame(dummy_pipeline),
topmost_scrolling_node_id: ClipId::root_scroll_node(dummy_pipeline),
current_new_node_item: 1,
current_reference_frame_id: 0,
pipelines_to_discard: HashSet::new(),
}
}
@ -72,10 +72,8 @@ impl ClipScrollTree {
-> HashSet<ClipId, BuildHasherDefault<FnvHasher>> {
let mut nodes_bouncing_back = HashSet::default();
for (clip_id, node) in self.nodes.iter() {
if let NodeType::ScrollFrame(ref scrolling) = node.node_type {
if scrolling.bouncing_back {
nodes_bouncing_back.insert(*clip_id);
}
if node.scrolling.bouncing_back {
nodes_bouncing_back.insert(*clip_id);
}
}
nodes_bouncing_back
@ -87,15 +85,14 @@ impl ClipScrollTree {
-> Option<ClipId> {
self.nodes.get(&clip_id).and_then(|node| {
for child_layer_id in node.children.iter().rev() {
if let Some(layer_id) =
self.find_scrolling_node_at_point_in_node(cursor, *child_layer_id) {
if let Some(layer_id) =
self.find_scrolling_node_at_point_in_node(cursor, *child_layer_id) {
return Some(layer_id);
}
}
match node.node_type {
NodeType::ScrollFrame(..) => {},
_ => return None,
if clip_id.is_reference_frame() {
return None;
}
if node.ray_intersects_node(cursor) {
@ -114,24 +111,21 @@ impl ClipScrollTree {
pub fn get_scroll_node_state(&self) -> Vec<ScrollLayerState> {
let mut result = vec![];
for (id, node) in self.nodes.iter() {
if let NodeType::ScrollFrame(scrolling) = node.node_type {
result.push(ScrollLayerState { id: *id, scroll_offset: scrolling.offset })
match node.scroll_offset() {
Some(offset) => result.push(ScrollLayerState { id: *id, scroll_offset: offset }),
None => {}
}
}
result
}
pub fn drain(&mut self) -> ScrollStates {
self.current_new_node_item = 1;
self.current_reference_frame_id = 1;
let mut scroll_states = HashMap::default();
for (layer_id, old_node) in &mut self.nodes.drain() {
if self.pipelines_to_discard.contains(&layer_id.pipeline_id()) {
continue;
}
if let NodeType::ScrollFrame(scrolling) = old_node.node_type {
scroll_states.insert(layer_id, scrolling);
if !self.pipelines_to_discard.contains(&layer_id.pipeline_id()) {
scroll_states.insert(layer_id, old_node.scrolling);
}
}
@ -140,6 +134,11 @@ impl ClipScrollTree {
}
pub fn scroll_node(&mut self, origin: LayerPoint, id: ClipId, clamp: ScrollClamping) -> bool {
if id.is_reference_frame() {
warn!("Tried to scroll a reference frame.");
return false;
}
if self.nodes.is_empty() {
self.pending_scroll_offsets.insert(id, (origin, clamp));
return false;
@ -185,33 +184,37 @@ impl ClipScrollTree {
let topmost_scrolling_node_id = self.topmost_scrolling_node_id();
let non_root_overscroll = if clip_id != topmost_scrolling_node_id {
self.nodes.get(&clip_id).unwrap().is_overscrolling()
// true if the current node is overscrolling,
// and it is not the root scroll node.
let child_node = self.nodes.get(&clip_id).unwrap();
let overscroll_amount = child_node.overscroll_amount();
overscroll_amount.width != 0.0 || overscroll_amount.height != 0.0
} else {
false
};
let mut switch_node = false;
if let Some(node) = self.nodes.get_mut(&clip_id) {
if let NodeType::ScrollFrame(ref mut scrolling) = node.node_type {
match phase {
ScrollEventPhase::Start => {
// if this is a new gesture, we do not switch node,
// however we do save the state of non_root_overscroll,
// for use in the subsequent Move phase.
scrolling.should_handoff_scroll = non_root_overscroll;
},
ScrollEventPhase::Move(_) => {
// Switch node if movement originated in a new gesture,
// from a non root node in overscroll.
switch_node = scrolling.should_handoff_scroll && non_root_overscroll
},
ScrollEventPhase::End => {
// clean-up when gesture ends.
scrolling.should_handoff_scroll = false;
}
}
}
}
let switch_node = match phase {
ScrollEventPhase::Start => {
// if this is a new gesture, we do not switch node,
// however we do save the state of non_root_overscroll,
// for use in the subsequent Move phase.
let mut current_node = self.nodes.get_mut(&clip_id).unwrap();
current_node.scrolling.should_handoff_scroll = non_root_overscroll;
false
},
ScrollEventPhase::Move(_) => {
// Switch node if movement originated in a new gesture,
// from a non root node in overscroll.
let current_node = self.nodes.get_mut(&clip_id).unwrap();
current_node.scrolling.should_handoff_scroll && non_root_overscroll
},
ScrollEventPhase::End => {
// clean-up when gesture ends.
let mut current_node = self.nodes.get_mut(&clip_id).unwrap();
current_node.scrolling.should_handoff_scroll = false;
false
},
};
let clip_id = if switch_node {
topmost_scrolling_node_id
@ -232,16 +235,16 @@ impl ClipScrollTree {
self.update_node_transform(root_reference_frame_id,
&LayerToWorldTransform::create_translation(pan.x, pan.y, 0.0),
&as_scroll_parent_rect(&root_viewport),
LayerVector2D::zero(),
LayerVector2D::zero());
LayerPoint::zero(),
LayerPoint::zero());
}
fn update_node_transform(&mut self,
layer_id: ClipId,
parent_reference_frame_transform: &LayerToWorldTransform,
parent_viewport_rect: &ScrollLayerRect,
parent_scroll_offset: LayerVector2D,
parent_accumulated_scroll_offset: LayerVector2D) {
parent_scroll_offset: LayerPoint,
parent_accumulated_scroll_offset: LayerPoint) {
// TODO(gw): This is an ugly borrow check workaround to clone these.
// Restructure this to avoid the clones!
let (reference_frame_transform,
@ -262,14 +265,11 @@ impl ClipScrollTree {
// we need to reset both these values.
let (transform, offset, accumulated_scroll_offset) = match node.node_type {
NodeType::ReferenceFrame(..) =>
(node.world_viewport_transform,
LayerVector2D::zero(),
LayerVector2D::zero()),
_ => {
let scroll_offset = node.scroll_offset();
(node.world_viewport_transform, LayerPoint::zero(), LayerPoint::zero()),
NodeType::Clip(_) => {
(*parent_reference_frame_transform,
scroll_offset,
scroll_offset + parent_accumulated_scroll_offset)
node.scrolling.offset,
node.scrolling.offset + parent_accumulated_scroll_offset)
}
};
@ -316,19 +316,17 @@ impl ClipScrollTree {
}
pub fn generate_new_clip_id(&mut self, pipeline_id: PipelineId) -> ClipId {
let new_id = ClipId::DynamicallyAddedNode(self.current_new_node_item, pipeline_id);
self.current_new_node_item += 1;
new_id
}
pub fn add_reference_frame(&mut self,
rect: &LayerRect,
transform: &LayerToScrollTransform,
pipeline_id: PipelineId,
parent_id: Option<ClipId>)
-> ClipId {
let reference_frame_id = self.generate_new_clip_id(pipeline_id);
let reference_frame_id =
ClipId::ReferenceFrame(self.current_reference_frame_id, pipeline_id);
self.current_reference_frame_id += 1;
let node = ClipScrollNode::new_reference_frame(parent_id,
rect,
rect.size,
@ -375,13 +373,10 @@ impl ClipScrollTree {
NodeType::ReferenceFrame(ref transform) => {
pt.new_level(format!("ReferenceFrame {:?}", transform));
}
NodeType::ScrollFrame(scrolling_info) => {
pt.new_level(format!("ScrollFrame"));
pt.add_item(format!("scroll.offset: {:?}", scrolling_info.offset));
}
}
pt.add_item(format!("content_size: {:?}", node.content_size));
pt.add_item(format!("scroll.offset: {:?}", node.scrolling.offset));
pt.add_item(format!("combined_local_viewport_rect: {:?}", node.combined_local_viewport_rect));
pt.add_item(format!("local_viewport_rect: {:?}", node.local_viewport_rect));
pt.add_item(format!("local_clip_rect: {:?}", node.local_clip_rect));

Просмотреть файл

@ -5,7 +5,7 @@
use debug_font_data;
use device::{Device, GpuMarker, ProgramId, VAOId, TextureId, VertexFormat};
use device::{TextureFilter, VertexUsageHint, TextureTarget};
use euclid::{Transform3D, Point2D, Size2D, Rect};
use euclid::{Matrix4D, Point2D, Size2D, Rect};
use internal_types::{ORTHO_NEAR_PLANE, ORTHO_FAR_PLANE, TextureSampler};
use internal_types::{DebugFontVertex, DebugColorVertex, RenderTargetMode, PackedColor};
use std::f32;
@ -166,12 +166,12 @@ impl DebugRenderer {
device.set_blend(true);
device.set_blend_mode_alpha();
let projection = Transform3D::ortho(0.0,
viewport_size.width as f32,
viewport_size.height as f32,
0.0,
ORTHO_NEAR_PLANE,
ORTHO_FAR_PLANE);
let projection = Matrix4D::ortho(0.0,
viewport_size.width as f32,
viewport_size.height as f32,
0.0,
ORTHO_NEAR_PLANE,
ORTHO_FAR_PLANE);
// Triangles
if !self.tri_vertices.is_empty() {

Просмотреть файл

@ -2,7 +2,7 @@
* 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 euclid::Transform3D;
use euclid::Matrix4D;
use fnv::FnvHasher;
use gleam::gl;
use internal_types::{PackedVertex, RenderTargetMode, TextureSampler, DEFAULT_TEXTURE};
@ -1059,7 +1059,7 @@ impl Device {
pub fn bind_program(&mut self,
program_id: ProgramId,
projection: &Transform3D<f32>) {
projection: &Matrix4D<f32>) {
debug_assert!(self.inside_frame);
if self.bound_program != program_id {
@ -1554,6 +1554,16 @@ impl Device {
self.gl.uniform_1i(u_tasks, TextureSampler::RenderTasks as i32);
}
let u_prim_geom = self.gl.get_uniform_location(program.id, "sPrimGeometry");
if u_prim_geom != -1 {
self.gl.uniform_1i(u_prim_geom, TextureSampler::Geometry as i32);
}
let u_data16 = self.gl.get_uniform_location(program.id, "sData16");
if u_data16 != -1 {
self.gl.uniform_1i(u_data16, TextureSampler::Data16 as i32);
}
let u_data32 = self.gl.get_uniform_location(program.id, "sData32");
if u_data32 != -1 {
self.gl.uniform_1i(u_data32, TextureSampler::Data32 as i32);
@ -1569,6 +1579,16 @@ impl Device {
self.gl.uniform_1i(u_resource_rects, TextureSampler::ResourceRects as i32);
}
let u_gradients = self.gl.get_uniform_location(program.id, "sGradients");
if u_gradients != -1 {
self.gl.uniform_1i(u_gradients, TextureSampler::Gradients as i32);
}
let u_split_geometry = self.gl.get_uniform_location(program.id, "sSplitGeometry");
if u_split_geometry != -1 {
self.gl.uniform_1i(u_split_geometry, TextureSampler::SplitGeometry as i32);
}
Ok(())
}
@ -1622,7 +1642,7 @@ impl Device {
fn set_uniforms(&self,
program: &Program,
transform: &Transform3D<f32>,
transform: &Matrix4D<f32>,
device_pixel_ratio: f32) {
debug_assert!(self.inside_frame);
self.gl.uniform_matrix_4fv(program.u_transform,

Просмотреть файл

@ -3,9 +3,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use app_units::Au;
use euclid::rect;
use euclid::rect::rect;
use fnv::FnvHasher;
use gpu_cache::GpuCache;
use internal_types::{ANGLE_FLOAT_TO_FIXED, AxisDirection};
use internal_types::{LowLevelFilterOp};
use internal_types::{RendererFrame};
@ -22,7 +21,7 @@ use util::{ComplexClipRegionHelpers, subtract_rect};
use webrender_traits::{BuiltDisplayList, BuiltDisplayListIter, ClipAndScrollInfo, ClipDisplayItem};
use webrender_traits::{ClipId, ClipRegion, ColorF, DeviceUintRect, DeviceUintSize, DisplayItemRef};
use webrender_traits::{Epoch, FilterOp, ImageDisplayItem, ItemRange, LayerPoint, LayerRect};
use webrender_traits::{LayerSize, LayerToScrollTransform, LayoutSize, LayoutTransform, LayerVector2D};
use webrender_traits::{LayerSize, LayerToScrollTransform, LayoutSize, LayoutTransform};
use webrender_traits::{MixBlendMode, PipelineId, ScrollClamping, ScrollEventPhase};
use webrender_traits::{ScrollLayerState, ScrollLocation, ScrollPolicy, SpecificDisplayItem};
use webrender_traits::{StackingContext, TileOffset, TransformStyle, WorldPoint};
@ -91,23 +90,26 @@ impl StackingContextHelpers for StackingContext {
properties: &SceneProperties) -> Vec<LowLevelFilterOp> {
let mut filters = vec![];
for filter in display_list.get(input_filters) {
if filter.is_noop() {
continue;
}
match filter {
FilterOp::Blur(radius) => {
filters.push(LowLevelFilterOp::Blur(radius, AxisDirection::Horizontal));
filters.push(LowLevelFilterOp::Blur(radius, AxisDirection::Vertical));
filters.push(LowLevelFilterOp::Blur(
radius,
AxisDirection::Horizontal));
filters.push(LowLevelFilterOp::Blur(
radius,
AxisDirection::Vertical));
}
FilterOp::Brightness(amount) => {
filters.push(LowLevelFilterOp::Brightness(Au::from_f32_px(amount)));
filters.push(
LowLevelFilterOp::Brightness(Au::from_f32_px(amount)));
}
FilterOp::Contrast(amount) => {
filters.push(LowLevelFilterOp::Contrast(Au::from_f32_px(amount)));
filters.push(
LowLevelFilterOp::Contrast(Au::from_f32_px(amount)));
}
FilterOp::Grayscale(amount) => {
filters.push(LowLevelFilterOp::Grayscale(Au::from_f32_px(amount)));
filters.push(
LowLevelFilterOp::Grayscale(Au::from_f32_px(amount)));
}
FilterOp::HueRotate(angle) => {
filters.push(
@ -115,17 +117,21 @@ impl StackingContextHelpers for StackingContext {
angle * ANGLE_FLOAT_TO_FIXED) as i32));
}
FilterOp::Invert(amount) => {
filters.push(LowLevelFilterOp::Invert(Au::from_f32_px(amount)));
filters.push(
LowLevelFilterOp::Invert(Au::from_f32_px(amount)));
}
FilterOp::Opacity(ref value) => {
let amount = properties.resolve_float(value, 1.0);
filters.push(LowLevelFilterOp::Opacity(Au::from_f32_px(amount)));
filters.push(
LowLevelFilterOp::Opacity(Au::from_f32_px(amount)));
}
FilterOp::Saturate(amount) => {
filters.push(LowLevelFilterOp::Saturate(Au::from_f32_px(amount)));
filters.push(
LowLevelFilterOp::Saturate(Au::from_f32_px(amount)));
}
FilterOp::Sepia(amount) => {
filters.push(LowLevelFilterOp::Sepia(Au::from_f32_px(amount)));
filters.push(
LowLevelFilterOp::Sepia(Au::from_f32_px(amount)));
}
}
}
@ -211,7 +217,8 @@ impl Frame {
None => return,
};
let display_list = match scene.display_lists.get(&root_pipeline_id) {
let display_list = scene.display_lists.get(&root_pipeline_id);
let display_list = match display_list {
Some(display_list) => display_list,
None => return,
};
@ -267,20 +274,12 @@ impl Frame {
item: &ClipDisplayItem,
content_rect: &LayerRect,
clip: &ClipRegion) {
let clip_viewport = LayerRect::new(content_rect.origin, clip.main.size);
let new_clip_id = self.clip_scroll_tree.generate_new_clip_id(pipeline_id);
context.builder.add_clip_scroll_node(new_clip_id,
context.builder.add_clip_scroll_node(item.id,
parent_id,
pipeline_id,
&clip_viewport,
&content_rect,
clip,
&mut self.clip_scroll_tree);
context.builder.add_scroll_frame(item.id,
new_clip_id,
pipeline_id,
&content_rect,
&clip_viewport,
&mut self.clip_scroll_tree);
}
@ -289,7 +288,7 @@ impl Frame {
pipeline_id: PipelineId,
context: &mut FlattenContext,
context_scroll_node_id: ClipId,
mut reference_frame_relative_offset: LayerVector2D,
mut reference_frame_relative_offset: LayerPoint,
bounds: &LayerRect,
stacking_context: &StackingContext,
filters: ItemRange<FilterOp>) {
@ -334,7 +333,7 @@ impl Frame {
LayerToScrollTransform::create_translation(reference_frame_relative_offset.x,
reference_frame_relative_offset.y,
0.0)
.pre_translate(bounds.origin.to_vector().to_3d())
.pre_translated(bounds.origin.x, bounds.origin.y, 0.0)
.pre_mul(&transform)
.pre_mul(&perspective);
@ -345,9 +344,9 @@ impl Frame {
&transform,
&mut self.clip_scroll_tree);
context.replacements.push((context_scroll_node_id, clip_id));
reference_frame_relative_offset = LayerVector2D::zero();
reference_frame_relative_offset = LayerPoint::zero();
} else {
reference_frame_relative_offset = LayerVector2D::new(
reference_frame_relative_offset = LayerPoint::new(
reference_frame_relative_offset.x + bounds.origin.x,
reference_frame_relative_offset.y + bounds.origin.y);
}
@ -379,15 +378,15 @@ impl Frame {
pipeline_id: PipelineId,
parent_id: ClipId,
bounds: &LayerRect,
clip_region: &ClipRegion,
context: &mut FlattenContext,
reference_frame_relative_offset: LayerVector2D) {
reference_frame_relative_offset: LayerPoint) {
let pipeline = match context.scene.pipeline_map.get(&pipeline_id) {
Some(pipeline) => pipeline,
None => return,
};
let display_list = match context.scene.display_lists.get(&pipeline_id) {
let display_list = context.scene.display_lists.get(&pipeline_id);
let display_list = match display_list {
Some(display_list) => display_list,
None => return,
};
@ -400,27 +399,19 @@ impl Frame {
reference_frame_relative_offset.y + bounds.origin.y,
0.0);
let new_clip_id = self.clip_scroll_tree.generate_new_clip_id(pipeline_id);
context.builder.add_clip_scroll_node(new_clip_id,
parent_id,
parent_id.pipeline_id(),
bounds,
clip_region,
&mut self.clip_scroll_tree);
let iframe_reference_frame_id =
context.builder.push_reference_frame(Some(new_clip_id),
context.builder.push_reference_frame(Some(parent_id),
pipeline_id,
&iframe_rect,
&transform,
&mut self.clip_scroll_tree);
context.builder.add_scroll_frame(
context.builder.add_clip_scroll_node(
ClipId::root_scroll_node(pipeline_id),
iframe_reference_frame_id,
pipeline_id,
&LayerRect::new(LayerPoint::zero(), pipeline.content_size),
&iframe_rect,
&ClipRegion::simple(&iframe_rect),
&mut self.clip_scroll_tree);
self.flatten_root(&mut display_list.iter(), pipeline_id, context, &pipeline.content_size);
@ -432,7 +423,7 @@ impl Frame {
item: DisplayItemRef<'a, 'b>,
pipeline_id: PipelineId,
context: &mut FlattenContext,
reference_frame_relative_offset: LayerVector2D)
reference_frame_relative_offset: LayerPoint)
-> Option<BuiltDisplayListIter<'a>> {
let mut clip_and_scroll = item.clip_and_scroll();
clip_and_scroll.scroll_node_id =
@ -492,10 +483,13 @@ impl Frame {
text_info.glyph_options);
}
SpecificDisplayItem::Rectangle(ref info) => {
let display_list = context.scene.display_lists
.get(&pipeline_id)
.expect("No display list?!");
// Try to extract the opaque inner rectangle out of the clipped primitive.
if let Some(opaque_rect) = clip_intersection(&item.rect(),
item.clip_region(),
item.display_list()) {
display_list) {
let mut results = Vec::new();
subtract_rect(&item.rect(), &opaque_rect, &mut results);
// The inner rectangle is considered opaque within this layer.
@ -583,7 +577,6 @@ impl Frame {
self.flatten_iframe(info.pipeline_id,
clip_and_scroll.scroll_node_id,
&item.rect(),
&item.clip_region(),
context,
reference_frame_relative_offset);
}
@ -612,7 +605,7 @@ impl Frame {
context: &mut FlattenContext,
content_size: &LayoutSize) {
let root_bounds = LayerRect::new(LayerPoint::zero(), *content_size);
context.builder.push_stacking_context(&LayerVector2D::zero(),
context.builder.push_stacking_context(&LayerPoint::zero(),
pipeline_id,
CompositeOps::default(),
root_bounds,
@ -627,7 +620,7 @@ impl Frame {
// For the root pipeline, there's no need to add a full screen rectangle
// here, as it's handled by the framebuffer clear.
let clip_id = ClipId::root_scroll_node(pipeline_id);
if context.scene.root_pipeline_id != Some(pipeline_id) {
if context.scene.root_pipeline_id.unwrap() != pipeline_id {
if let Some(pipeline) = context.scene.pipeline_map.get(&pipeline_id) {
if let Some(bg_color) = pipeline.background_color {
context.builder.add_solid_rectangle(ClipAndScrollInfo::simple(clip_id),
@ -640,7 +633,7 @@ impl Frame {
}
self.flatten_items(traversal, pipeline_id, context, LayerVector2D::zero());
self.flatten_items(traversal, pipeline_id, context, LayerPoint::zero());
if self.frame_builder_config.enable_scrollbars {
let scrollbar_rect = LayerRect::new(LayerPoint::zero(), LayerSize::new(10.0, 70.0));
@ -659,7 +652,7 @@ impl Frame {
traversal: &mut BuiltDisplayListIter<'a>,
pipeline_id: PipelineId,
context: &mut FlattenContext,
reference_frame_relative_offset: LayerVector2D) {
reference_frame_relative_offset: LayerPoint) {
loop {
let subtraversal = {
let item = match traversal.next() {
@ -942,7 +935,7 @@ impl Frame {
);
let mut prim_rect = LayerRect::new(
item_rect.origin + LayerVector2D::new(
item_rect.origin + LayerPoint::new(
tile_offset.x as f32 * stretched_tile_size.width,
tile_offset.y as f32 * stretched_tile_size.height,
),
@ -975,7 +968,6 @@ impl Frame {
pub fn build(&mut self,
resource_cache: &mut ResourceCache,
gpu_cache: &mut GpuCache,
display_lists: &DisplayListMap,
device_pixel_ratio: f32,
pan: LayerPoint,
@ -984,7 +976,6 @@ impl Frame {
-> RendererFrame {
self.clip_scroll_tree.update_all_node_transforms(pan);
let frame = self.build_frame(resource_cache,
gpu_cache,
display_lists,
device_pixel_ratio,
texture_cache_profile,
@ -998,7 +989,6 @@ impl Frame {
fn build_frame(&mut self,
resource_cache: &mut ResourceCache,
gpu_cache: &mut GpuCache,
display_lists: &DisplayListMap,
device_pixel_ratio: f32,
texture_cache_profile: &mut TextureCacheProfileCounters,
@ -1007,7 +997,6 @@ impl Frame {
let mut frame_builder = self.frame_builder.take();
let frame = frame_builder.as_mut().map(|builder|
builder.build(resource_cache,
gpu_cache,
self.id,
&mut self.clip_scroll_tree,
display_lists,

Просмотреть файл

@ -4,15 +4,14 @@
use app_units::Au;
use frame::FrameId;
use gpu_cache::GpuCache;
use gpu_store::GpuStoreAddress;
use internal_types::{HardwareCompositeOp, SourceTexture};
use mask_cache::{ClipMode, ClipSource, MaskCacheInfo, RegionMode};
use plane_split::{BspSplitter, Polygon, Splitter};
use prim_store::{GradientPrimitiveCpu, ImagePrimitiveCpu};
use prim_store::{ImagePrimitiveKind, PrimitiveContainer, PrimitiveIndex};
use prim_store::{ImagePrimitiveKind, PrimitiveContainer, PrimitiveGeometry, PrimitiveIndex};
use prim_store::{PrimitiveStore, RadialGradientPrimitiveCpu};
use prim_store::{RectanglePrimitive, TextRunPrimitiveCpu};
use prim_store::{RectanglePrimitive, SplitGeometry, TextRunPrimitiveCpu};
use prim_store::{BoxShadowPrimitiveCpu, TexelRect, YuvImagePrimitiveCpu};
use profiler::{FrameProfileCounters, GpuCacheProfileCounters, TextureCacheProfileCounters};
use render_task::{AlphaRenderItem, MaskCacheKey, MaskResult, RenderTask, RenderTaskIndex};
@ -22,7 +21,7 @@ use clip_scroll_node::{ClipInfo, ClipScrollNode, NodeType};
use clip_scroll_tree::ClipScrollTree;
use std::{cmp, f32, i32, mem, usize};
use std::collections::HashMap;
use euclid::{SideOffsets2D, vec2, vec3};
use euclid::{SideOffsets2D, TypedPoint3D};
use tiling::{ContextIsolation, StackingContextIndex};
use tiling::{ClipScrollGroup, ClipScrollGroupIndex, CompositeOps, DisplayListMap, Frame};
use tiling::{PackedLayer, PackedLayerIndex, PrimitiveFlags, PrimitiveRunCmd, RenderPass};
@ -35,7 +34,7 @@ use webrender_traits::{DeviceUintRect, DeviceUintSize, ExtendMode, FontKey, Font
use webrender_traits::{GlyphInstance, GlyphOptions, GradientStop, ImageKey, ImageRendering};
use webrender_traits::{ItemRange, LayerPoint, LayerRect, LayerSize, LayerToScrollTransform};
use webrender_traits::{PipelineId, RepeatMode, TileOffset, TransformStyle, WebGLContextId};
use webrender_traits::{WorldPixel, YuvColorSpace, YuvData, LayerVector2D};
use webrender_traits::{WorldPixel, YuvColorSpace, YuvData};
#[derive(Debug, Clone)]
struct ImageBorderSegment {
@ -96,7 +95,7 @@ fn make_polygon(sc: &StackingContext, node: &ClipScrollNode, anchor: usize)
// Which in turn needs it to be a render task property obeyed by all primitives
// upon rendering, possibly not limited to `write_*_vertex` implementations.
let size = sc.local_bounds.bottom_right();
let bounds = LayerRect::new(sc.reference_frame_offset.to_point(), LayerSize::new(size.x, size.y));
let bounds = LayerRect::new(sc.reference_frame_offset, LayerSize::new(size.x, size.y));
Polygon::from_transformed_rect(bounds, node.world_content_transform, anchor)
}
@ -198,6 +197,10 @@ impl FrameBuilder {
self.create_clip_scroll_group_if_necessary(stacking_context_index, clip_and_scroll);
let geometry = PrimitiveGeometry {
local_rect: *rect,
local_clip_rect: clip_region.main,
};
let mut clip_sources = Vec::new();
if clip_region.is_complex() {
clip_sources.push(ClipSource::Region(clip_region.clone(), RegionMode::ExcludeRect));
@ -208,8 +211,7 @@ impl FrameBuilder {
let clip_info = MaskCacheInfo::new(&clip_sources,
&mut self.prim_store.gpu_data32);
let prim_index = self.prim_store.add_primitive(rect,
&clip_region.main,
let prim_index = self.prim_store.add_primitive(geometry,
clip_sources,
clip_info,
container);
@ -253,7 +255,7 @@ impl FrameBuilder {
}
pub fn push_stacking_context(&mut self,
reference_frame_offset: &LayerVector2D,
reference_frame_offset: &LayerPoint,
pipeline_id: PipelineId,
composite_ops: CompositeOps,
local_bounds: LayerRect,
@ -353,14 +355,12 @@ impl FrameBuilder {
let topmost_scrolling_node_id = ClipId::root_scroll_node(pipeline_id);
clip_scroll_tree.topmost_scrolling_node_id = topmost_scrolling_node_id;
self.add_scroll_frame(topmost_scrolling_node_id,
clip_scroll_tree.root_reference_frame_id,
pipeline_id,
&LayerRect::new(LayerPoint::zero(), *content_size),
&viewport_rect,
clip_scroll_tree);
self.add_clip_scroll_node(topmost_scrolling_node_id,
clip_scroll_tree.root_reference_frame_id,
pipeline_id,
&LayerRect::new(LayerPoint::zero(), *content_size),
&ClipRegion::simple(&viewport_rect),
clip_scroll_tree);
topmost_scrolling_node_id
}
@ -384,21 +384,6 @@ impl FrameBuilder {
self.packed_layers.push(PackedLayer::empty());
}
pub fn add_scroll_frame(&mut self,
new_node_id: ClipId,
parent_id: ClipId,
pipeline_id: PipelineId,
content_rect: &LayerRect,
frame_rect: &LayerRect,
clip_scroll_tree: &mut ClipScrollTree) {
let node = ClipScrollNode::new_scroll_frame(pipeline_id,
parent_id,
content_rect,
frame_rect);
clip_scroll_tree.add_node(node, new_node_id);
}
pub fn pop_reference_frame(&mut self) {
self.reference_frame_stack.pop();
}
@ -451,17 +436,17 @@ impl FrameBuilder {
let rect = LayerRect::new(origin, size);
let tl_outer = LayerPoint::new(rect.origin.x, rect.origin.y);
let tl_inner = tl_outer + vec2(border_item.widths.left, border_item.widths.top);
let tl_inner = tl_outer + LayerPoint::new(border_item.widths.left, border_item.widths.top);
let tr_outer = LayerPoint::new(rect.origin.x + rect.size.width, rect.origin.y);
let tr_inner = tr_outer + vec2(-border_item.widths.right, border_item.widths.top);
let tr_inner = tr_outer + LayerPoint::new(-border_item.widths.right, border_item.widths.top);
let bl_outer = LayerPoint::new(rect.origin.x, rect.origin.y + rect.size.height);
let bl_inner = bl_outer + vec2(border_item.widths.left, -border_item.widths.bottom);
let bl_inner = bl_outer + LayerPoint::new(border_item.widths.left, -border_item.widths.bottom);
let br_outer = LayerPoint::new(rect.origin.x + rect.size.width,
rect.origin.y + rect.size.height);
let br_inner = br_outer - vec2(border_item.widths.right, border_item.widths.bottom);
let br_inner = br_outer - LayerPoint::new(border_item.widths.right, border_item.widths.bottom);
// Build the list of gradient segments
vec![
@ -505,17 +490,17 @@ impl FrameBuilder {
let py3 = border.patch.height;
let tl_outer = LayerPoint::new(rect.origin.x, rect.origin.y);
let tl_inner = tl_outer + vec2(border_item.widths.left, border_item.widths.top);
let tl_inner = tl_outer + LayerPoint::new(border_item.widths.left, border_item.widths.top);
let tr_outer = LayerPoint::new(rect.origin.x + rect.size.width, rect.origin.y);
let tr_inner = tr_outer + vec2(-border_item.widths.right, border_item.widths.top);
let tr_inner = tr_outer + LayerPoint::new(-border_item.widths.right, border_item.widths.top);
let bl_outer = LayerPoint::new(rect.origin.x, rect.origin.y + rect.size.height);
let bl_inner = bl_outer + vec2(border_item.widths.left, -border_item.widths.bottom);
let bl_inner = bl_outer + LayerPoint::new(border_item.widths.left, -border_item.widths.bottom);
let br_outer = LayerPoint::new(rect.origin.x + rect.size.width,
rect.origin.y + rect.size.height);
let br_inner = br_outer - vec2(border_item.widths.right, border_item.widths.bottom);
let br_inner = br_outer - LayerPoint::new(border_item.widths.right, border_item.widths.bottom);
// Build the list of image segments
let mut segments = vec![
@ -679,6 +664,9 @@ impl FrameBuilder {
stops_count: stops_count,
extend_mode: extend_mode,
reverse_stops: reverse_stops,
cache_dirty: true,
gpu_data_address: GpuStoreAddress(0),
gpu_data_count: 0,
gpu_blocks: [
[sp.x, sp.y, ep.x, ep.y].into(),
[tile_size.width, tile_size.height, tile_repeat.width, tile_repeat.height].into(),
@ -713,6 +701,7 @@ impl FrameBuilder {
let radial_gradient_cpu = RadialGradientPrimitiveCpu {
stops_range: stops,
extend_mode: extend_mode,
cache_dirty: true,
gpu_data_address: GpuStoreAddress(0),
gpu_data_count: 0,
gpu_blocks: [
@ -783,12 +772,15 @@ impl FrameBuilder {
blur_radius: blur_radius,
glyph_range: glyph_range,
glyph_count: glyph_count,
cache_dirty: true,
glyph_instances: Vec::new(),
color_texture_id: SourceTexture::Invalid,
color: *color,
render_mode: render_mode,
glyph_options: glyph_options,
resource_address: GpuStoreAddress(0),
gpu_data_address: GpuStoreAddress(0),
gpu_data_count: 0,
};
self.add_primitive(clip_and_scroll,
@ -839,7 +831,7 @@ impl FrameBuilder {
clip_and_scroll: ClipAndScrollInfo,
box_bounds: &LayerRect,
clip_region: &ClipRegion,
box_offset: &LayerVector2D,
box_offset: &LayerPoint,
color: &ColorF,
blur_radius: f32,
spread_radius: f32,
@ -1098,7 +1090,6 @@ impl FrameBuilder {
clip_scroll_tree: &mut ClipScrollTree,
display_lists: &DisplayListMap,
resource_cache: &mut ResourceCache,
gpu_cache: &mut GpuCache,
profile_counters: &mut FrameProfileCounters,
device_pixel_ratio: f32) {
profile_scope!("cull");
@ -1107,61 +1098,56 @@ impl FrameBuilder {
clip_scroll_tree,
display_lists,
resource_cache,
gpu_cache,
profile_counters,
device_pixel_ratio);
}
fn update_scroll_bars(&mut self,
clip_scroll_tree: &ClipScrollTree,
gpu_cache: &mut GpuCache) {
fn update_scroll_bars(&mut self, clip_scroll_tree: &ClipScrollTree) {
let distance_from_edge = 8.0;
for scrollbar_prim in &self.scrollbar_prims {
let metadata = &mut self.prim_store.cpu_metadata[scrollbar_prim.prim_index.0];
let mut geom = (*self.prim_store.gpu_geometry.get(GpuStoreAddress(scrollbar_prim.prim_index.0 as i32))).clone();
let clip_scroll_node = &clip_scroll_tree.nodes[&scrollbar_prim.clip_id];
// Invalidate what's in the cache so it will get rebuilt.
gpu_cache.invalidate(&metadata.gpu_location);
let scrollable_distance = clip_scroll_node.scrollable_height();
if scrollable_distance <= 0.0 {
metadata.local_clip_rect.size = LayerSize::zero();
geom.local_clip_rect.size = LayerSize::zero();
*self.prim_store.gpu_geometry.get_mut(GpuStoreAddress(scrollbar_prim.prim_index.0 as i32)) = geom;
continue;
}
let scroll_offset = clip_scroll_node.scroll_offset();
let f = -scroll_offset.y / scrollable_distance;
let f = -clip_scroll_node.scrolling.offset.y / scrollable_distance;
let min_y = clip_scroll_node.local_viewport_rect.origin.y -
scroll_offset.y +
clip_scroll_node.scrolling.offset.y +
distance_from_edge;
let max_y = clip_scroll_node.local_viewport_rect.origin.y +
clip_scroll_node.local_viewport_rect.size.height -
scroll_offset.y -
metadata.local_rect.size.height -
clip_scroll_node.scrolling.offset.y -
geom.local_rect.size.height -
distance_from_edge;
metadata.local_rect.origin.x = clip_scroll_node.local_viewport_rect.origin.x +
clip_scroll_node.local_viewport_rect.size.width -
metadata.local_rect.size.width -
distance_from_edge;
geom.local_rect.origin.x = clip_scroll_node.local_viewport_rect.origin.x +
clip_scroll_node.local_viewport_rect.size.width -
geom.local_rect.size.width -
distance_from_edge;
metadata.local_rect.origin.y = util::lerp(min_y, max_y, f);
metadata.local_clip_rect = metadata.local_rect;
geom.local_rect.origin.y = util::lerp(min_y, max_y, f);
geom.local_clip_rect = geom.local_rect;
// TODO(gw): The code to set / update border clips on scroll bars
// has been broken for a long time, so I've removed it
// for now. We can re-add that code once the clips
// data is moved over to the GPU cache!
let clip_source = if scrollbar_prim.border_radius > 0.0 {
Some(ClipSource::Complex(geom.local_rect, scrollbar_prim.border_radius, ClipMode::Clip))
} else {
None
};
self.prim_store.set_clip_source(scrollbar_prim.prim_index, clip_source);
*self.prim_store.gpu_geometry.get_mut(GpuStoreAddress(scrollbar_prim.prim_index.0 as i32)) = geom;
}
}
fn build_render_task(&mut self,
clip_scroll_tree: &ClipScrollTree,
gpu_cache: &mut GpuCache)
fn build_render_task(&mut self, clip_scroll_tree: &ClipScrollTree)
-> (RenderTask, usize) {
profile_scope!("build_render_task");
@ -1185,6 +1171,7 @@ impl FrameBuilder {
// The plane splitter, using a simple BSP tree.
let mut splitter = BspSplitter::new();
self.prim_store.gpu_split_geometry.clear();
debug!("build_render_task()");
for cmd in &self.cmds {
@ -1302,18 +1289,19 @@ impl FrameBuilder {
current_task.children.extend(preserve_3d_map.values().cloned());
debug!("\tplane splitting in {:?}", current_task.id);
// Z axis is directed at the screen, `sort` is ascending, and we need back-to-front order.
for poly in splitter.sort(vec3(0.0, 0.0, 1.0)) {
for poly in splitter.sort(TypedPoint3D::new(0.0, 0.0, 1.0)) {
let sc_index = StackingContextIndex(poly.anchor);
let task_id = preserve_3d_map[&sc_index].id;
debug!("\t\tproduce {:?} -> {:?} for {:?}", sc_index, poly, task_id);
let pp = &poly.points;
let gpu_blocks = [
[pp[0].x, pp[0].y, pp[0].z, pp[1].x].into(),
[pp[1].y, pp[1].z, pp[2].x, pp[2].y].into(),
[pp[2].z, pp[3].x, pp[3].y, pp[3].z].into(),
];
let handle = gpu_cache.push_per_frame_blocks(&gpu_blocks);
let item = AlphaRenderItem::SplitComposite(sc_index, task_id, handle, next_z);
let split_geo = SplitGeometry {
data: [pp[0].x, pp[0].y, pp[0].z,
pp[1].x, pp[1].y, pp[1].z,
pp[2].x, pp[2].y, pp[2].z,
pp[3].x, pp[3].y, pp[3].z],
};
let gpu_index = self.prim_store.gpu_split_geometry.push(split_geo);
let item = AlphaRenderItem::SplitComposite(sc_index, task_id, gpu_index, next_z);
current_task.as_alpha_batch().items.push(item);
}
splitter.reset();
@ -1369,7 +1357,6 @@ impl FrameBuilder {
pub fn build(&mut self,
resource_cache: &mut ResourceCache,
gpu_cache: &mut GpuCache,
frame_id: FrameId,
clip_scroll_tree: &mut ClipScrollTree,
display_lists: &DisplayListMap,
@ -1383,7 +1370,6 @@ impl FrameBuilder {
profile_counters.total_primitives.set(self.prim_store.prim_count());
resource_cache.begin_frame(frame_id);
gpu_cache.begin_frame();
let screen_rect = DeviceIntRect::new(
DeviceIntPoint::zero(),
@ -1397,17 +1383,16 @@ impl FrameBuilder {
let cache_size = DeviceUintSize::new(cmp::max(1024, screen_rect.size.width as u32),
cmp::max(1024, screen_rect.size.height as u32));
self.update_scroll_bars(clip_scroll_tree, gpu_cache);
self.update_scroll_bars(clip_scroll_tree);
self.build_layer_screen_rects_and_cull_layers(&screen_rect,
clip_scroll_tree,
display_lists,
resource_cache,
gpu_cache,
&mut profile_counters,
device_pixel_ratio);
let (main_render_task, static_render_task_count) = self.build_render_task(clip_scroll_tree, gpu_cache);
let (main_render_task, static_render_task_count) = self.build_render_task(clip_scroll_tree);
let mut render_tasks = RenderTaskCollection::new(static_render_task_count);
let mut required_pass_count = 0;
@ -1426,7 +1411,8 @@ impl FrameBuilder {
let deferred_resolves = self.prim_store.resolve_primitives(resource_cache,
device_pixel_ratio);
let gpu_cache_updates = gpu_cache.end_frame(gpu_cache_profile);
let gpu_cache_updates = resource_cache.gpu_cache
.end_frame(gpu_cache_profile);
let mut passes = Vec::new();
@ -1446,7 +1432,6 @@ impl FrameBuilder {
clip_scroll_group_store: &self.clip_scroll_group_store,
prim_store: &self.prim_store,
resource_cache: resource_cache,
gpu_cache: gpu_cache,
};
pass.build(&ctx, &mut render_tasks);
@ -1467,7 +1452,11 @@ impl FrameBuilder {
cache_size: cache_size,
layer_texture_data: self.packed_layers.clone(),
render_task_data: render_tasks.render_task_data,
gpu_data16: self.prim_store.gpu_data16.build(),
gpu_data32: self.prim_store.gpu_data32.build(),
gpu_geometry: self.prim_store.gpu_geometry.build(),
gpu_gradient_data: self.prim_store.gpu_gradient_data.build(),
gpu_split_geometry: self.prim_store.gpu_split_geometry.build(),
gpu_resource_rects: self.prim_store.gpu_resource_rects.build(),
deferred_resolves: deferred_resolves,
gpu_cache_updates: Some(gpu_cache_updates),
@ -1482,7 +1471,6 @@ struct LayerRectCalculationAndCullingPass<'a> {
clip_scroll_tree: &'a mut ClipScrollTree,
display_lists: &'a DisplayListMap,
resource_cache: &'a mut ResourceCache,
gpu_cache: &'a mut GpuCache,
profile_counters: &'a mut FrameProfileCounters,
device_pixel_ratio: f32,
stacking_context_stack: Vec<StackingContextIndex>,
@ -1503,7 +1491,6 @@ impl<'a> LayerRectCalculationAndCullingPass<'a> {
clip_scroll_tree: &'a mut ClipScrollTree,
display_lists: &'a DisplayListMap,
resource_cache: &'a mut ResourceCache,
gpu_cache: &'a mut GpuCache,
profile_counters: &'a mut FrameProfileCounters,
device_pixel_ratio: f32) {
@ -1513,7 +1500,6 @@ impl<'a> LayerRectCalculationAndCullingPass<'a> {
clip_scroll_tree: clip_scroll_tree,
display_lists: display_lists,
resource_cache: resource_cache,
gpu_cache: gpu_cache,
profile_counters: profile_counters,
device_pixel_ratio: device_pixel_ratio,
stacking_context_stack: Vec::new(),
@ -1546,7 +1532,7 @@ impl<'a> LayerRectCalculationAndCullingPass<'a> {
for (_, ref mut node) in self.clip_scroll_tree.nodes.iter_mut() {
let node_clip_info = match node.node_type {
NodeType::Clip(ref mut clip_info) => clip_info,
_ => continue,
NodeType::ReferenceFrame(_) => continue,
};
let packed_layer_index = node_clip_info.packed_layer_index;
@ -1556,13 +1542,15 @@ impl<'a> LayerRectCalculationAndCullingPass<'a> {
// so we need to account for that origin in the transformation we assign to
// the packed layer.
let transform = node.world_viewport_transform
.pre_translate(node.local_viewport_rect.origin.to_vector().to_3d());
.pre_translated(node.local_viewport_rect.origin.x,
node.local_viewport_rect.origin.y,
0.0);
packed_layer.set_transform(transform);
// Meanwhile, the combined viewport rect is relative to the reference frame, so
// we move it into the local coordinate system of the node.
let local_viewport_rect =
node.combined_local_viewport_rect.translate(&-node.local_viewport_rect.origin.to_vector());
node.combined_local_viewport_rect.translate(&-node.local_viewport_rect.origin);
node_clip_info.screen_bounding_rect = packed_layer.set_rect(&local_viewport_rect,
self.screen_rect,
@ -1605,7 +1593,9 @@ impl<'a> LayerRectCalculationAndCullingPass<'a> {
// The world content transform is relative to the containing reference frame,
// so we translate into the origin of the stacking context itself.
let transform = scroll_node.world_content_transform
.pre_translate(stacking_context.reference_frame_offset.to_3d());
.pre_translated(stacking_context.reference_frame_offset.x,
stacking_context.reference_frame_offset.y,
0.0);
packed_layer.set_transform(transform);
if !stacking_context.can_contribute_to_scene() {
@ -1619,7 +1609,7 @@ impl<'a> LayerRectCalculationAndCullingPass<'a> {
.translate(&clip_node.reference_frame_relative_scroll_offset)
.translate(&-scroll_node.reference_frame_relative_scroll_offset)
.translate(&-stacking_context.reference_frame_offset)
.translate(&-scroll_node.scroll_offset());
.translate(&-scroll_node.scrolling.offset);
group.screen_bounding_rect = packed_layer.set_rect(viewport_rect,
self.screen_rect,
self.device_pixel_ratio);
@ -1750,7 +1740,6 @@ impl<'a> LayerRectCalculationAndCullingPass<'a> {
self.device_pixel_ratio) {
self.frame_builder.prim_store.prepare_prim_for_render(prim_index,
self.resource_cache,
self.gpu_cache,
&packed_layer.transform,
self.device_pixel_ratio,
display_list);

Просмотреть файл

@ -2,6 +2,8 @@
* 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 std::collections::HashSet;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct FreeListItemId(u32);
@ -83,6 +85,11 @@ impl<T: FreeListItem> FreeList<T> {
&self.items[id.0 as usize]
}
pub fn get_mut(&mut self, id: FreeListItemId) -> &mut T {
debug_assert_eq!(self.free_iter().find(|&fid| fid==id), None);
&mut self.items[id.0 as usize]
}
#[allow(dead_code)]
pub fn len(&self) -> usize {
self.alloc_count
@ -97,4 +104,20 @@ impl<T: FreeListItem> FreeList<T> {
self.first_free_index = Some(id);
data
}
pub fn for_each_item<F>(&mut self, f: F) where F: Fn(&mut T) {
//TODO: this could be done much faster. Instead of gathering the free
// indices into a set, we could re-order the free list to be ascending.
// That is an one-time operation with at most O(nf^2), where
// nf = number of elements in the free list
// Then this code would just walk both `items` and the ascending free
// list, essentially skipping the free indices for free.
let free_ids: HashSet<_> = self.free_iter().collect();
for (index, mut item) in self.items.iter_mut().enumerate() {
if !free_ids.contains(&FreeListItemId(index as u32)) {
f(&mut item);
}
}
}
}

Просмотреть файл

@ -41,8 +41,10 @@ pub fn ray_intersects_rect(ray_origin: Point3D<f32>,
];
let parameters = [
rect.origin.to_3d(),
rect.bottom_right().to_3d(),
Point3D::new(rect.origin.x, rect.origin.y, 0.0),
Point3D::new(rect.origin.x + rect.size.width,
rect.origin.y + rect.size.height,
0.0),
];
let mut tmin = (parameters[sign[0]].x - ray_origin.x) * inv_direction.x;

Просмотреть файл

@ -15,7 +15,7 @@ use std::sync::mpsc::{channel, Receiver, Sender};
use std::collections::HashSet;
use std::mem;
use texture_cache::{TextureCacheItemId, TextureCache};
use webrender_traits::FontTemplate;
use internal_types::FontTemplate;
use webrender_traits::{FontKey, FontRenderMode, ImageData, ImageFormat};
use webrender_traits::{ImageDescriptor, ColorF, LayoutPoint};
use webrender_traits::{GlyphKey, GlyphOptions, GlyphInstance, GlyphDimensions};
@ -248,7 +248,9 @@ impl GlyphRasterizer {
for job in rasterized_glyphs {
let image_id = job.result.and_then(
|glyph| if glyph.width > 0 && glyph.height > 0 {
let image_id = texture_cache.insert(
let image_id = texture_cache.new_item_id();
texture_cache.insert(
image_id,
ImageDescriptor {
width: glyph.width,
height: glyph.height,

Просмотреть файл

@ -27,22 +27,15 @@
use device::FrameId;
use profiler::GpuCacheProfileCounters;
use renderer::MAX_VERTEX_TEXTURE_WIDTH;
use std::{mem, u32};
use std::mem;
use webrender_traits::{ColorF, LayerRect};
pub const GPU_CACHE_INITIAL_HEIGHT: u32 = 512;
const FRAMES_BEFORE_EVICTION: usize = 10;
const NEW_ROWS_PER_RESIZE: u32 = 512;
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
struct Epoch(u32);
impl Epoch {
fn next(&mut self) {
*self = Epoch(self.0.wrapping_add(1));
}
}
#[derive(Debug, Copy, Clone)]
struct CacheLocation {
block_index: BlockIndex,
@ -200,10 +193,6 @@ struct FreeBlockLists {
free_list_2: Option<BlockIndex>,
free_list_4: Option<BlockIndex>,
free_list_8: Option<BlockIndex>,
free_list_16: Option<BlockIndex>,
free_list_32: Option<BlockIndex>,
free_list_64: Option<BlockIndex>,
free_list_128: Option<BlockIndex>,
free_list_large: Option<BlockIndex>,
}
@ -214,10 +203,6 @@ impl FreeBlockLists {
free_list_2: None,
free_list_4: None,
free_list_8: None,
free_list_16: None,
free_list_32: None,
free_list_64: None,
free_list_128: None,
free_list_large: None,
}
}
@ -232,11 +217,7 @@ impl FreeBlockLists {
2 => (2, &mut self.free_list_2),
3...4 => (4, &mut self.free_list_4),
5...8 => (8, &mut self.free_list_8),
9...16 => (16, &mut self.free_list_16),
17...32 => (32, &mut self.free_list_32),
33...64 => (64, &mut self.free_list_64),
65...128 => (128, &mut self.free_list_128),
129...MAX_VERTEX_TEXTURE_WIDTH => (MAX_VERTEX_TEXTURE_WIDTH, &mut self.free_list_large),
9...MAX_VERTEX_TEXTURE_WIDTH => (MAX_VERTEX_TEXTURE_WIDTH, &mut self.free_list_large),
_ => panic!("Can't allocate > MAX_VERTEX_TEXTURE_WIDTH per resource!"),
}
}
@ -294,8 +275,10 @@ impl Texture {
// See if we need a new row (if free-list has nothing available)
if free_list.is_none() {
// TODO(gw): Handle the case where we need to resize
// the cache texture itself!
if self.rows.len() as u32 == self.height {
self.height += NEW_ROWS_PER_RESIZE;
panic!("need to re-alloc texture!!");
}
// Create a new row.
@ -375,7 +358,7 @@ impl Texture {
let (_, free_list) = self.free_lists
.get_actual_block_count_and_free_list(row.block_count_per_item);
block.epoch.next();
block.epoch = Epoch(block.epoch.0 + 1);
block.next = *free_list;
*free_list = Some(index);
@ -461,16 +444,6 @@ impl GpuCache {
self.texture.evict_old_blocks(self.frame_id);
}
// Invalidate a (possibly) existing block in the cache.
// This means the next call to request() for this location
// will rebuild the data and upload it to the GPU.
pub fn invalidate(&mut self, handle: &GpuCacheHandle) {
if let Some(ref location) = handle.location {
let block = &mut self.texture.blocks[location.block_index.0];
block.epoch.next();
}
}
// Request a resource be added to the cache. If the resource
/// is already in the cache, `None` will be returned.
pub fn request<'a>(&'a mut self, handle: &'a mut GpuCacheHandle) -> Option<GpuDataRequest<'a>> {
@ -483,7 +456,6 @@ impl GpuCache {
return None
}
}
Some(GpuDataRequest {
handle: handle,
frame_id: self.frame_id,
@ -492,23 +464,6 @@ impl GpuCache {
})
}
// Push an array of data blocks to be uploaded to the GPU
// unconditionally for this frame. The cache handle will
// assert if the caller tries to retrieve the address
// of this handle on a subsequent frame. This is typically
// used for uploading data that changes every frame, and
// therefore makes no sense to try and cache.
pub fn push_per_frame_blocks(&mut self, blocks: &[GpuBlockData]) -> GpuCacheHandle {
let start_index = self.texture.pending_blocks.len();
self.texture.pending_blocks.extend_from_slice(blocks);
let location = self.texture.push_data(start_index,
blocks.len(),
self.frame_id);
GpuCacheHandle {
location: Some(location),
}
}
/// End the frame. Return the list of updates to apply to the
/// device specific cache texture.
pub fn end_frame(&mut self,

Просмотреть файл

@ -48,11 +48,18 @@ pub enum SourceTexture {
}
const COLOR_FLOAT_TO_FIXED: f32 = 255.0;
const COLOR_FLOAT_TO_FIXED_WIDE: f32 = 65535.0;
pub const ANGLE_FLOAT_TO_FIXED: f32 = 65535.0;
pub const ORTHO_NEAR_PLANE: f32 = -1000000.0;
pub const ORTHO_FAR_PLANE: f32 = 1000000.0;
#[derive(Clone)]
pub enum FontTemplate {
Raw(Arc<Vec<u8>>, u32),
Native(NativeFontHandle),
}
#[derive(Debug, PartialEq, Eq)]
pub enum TextureSampler {
Color0,
@ -60,11 +67,15 @@ pub enum TextureSampler {
Color2,
CacheA8,
CacheRGBA8,
Data16,
Data32,
ResourceCache,
Layers,
RenderTasks,
Geometry,
ResourceRects,
Gradients,
SplitGeometry,
Dither,
}
@ -132,6 +143,7 @@ pub enum ClipAttribute {
}
// A packed RGBA8 color ordered for vertex data or similar.
// Use PackedTexel instead if intending to upload to a texture.
#[derive(Debug, Clone, Copy)]
#[repr(C)]
@ -153,6 +165,37 @@ impl PackedColor {
}
}
// RGBA8 textures currently pack texels in BGRA format for upload.
// PackedTexel abstracts away this difference from PackedColor.
#[derive(Debug, Clone, Copy)]
#[repr(C)]
pub struct PackedTexel {
pub b: u8,
pub g: u8,
pub r: u8,
pub a: u8,
}
impl PackedTexel {
pub fn high_bytes(color: &ColorF) -> PackedTexel {
Self::extract_bytes(color, 8)
}
pub fn low_bytes(color: &ColorF) -> PackedTexel {
Self::extract_bytes(color, 0)
}
fn extract_bytes(color: &ColorF, shift_by: i32) -> PackedTexel {
PackedTexel {
b: ((0.5 + color.b * COLOR_FLOAT_TO_FIXED_WIDE).floor() as u32 >> shift_by & 0xff) as u8,
g: ((0.5 + color.g * COLOR_FLOAT_TO_FIXED_WIDE).floor() as u32 >> shift_by & 0xff) as u8,
r: ((0.5 + color.r * COLOR_FLOAT_TO_FIXED_WIDE).floor() as u32 >> shift_by & 0xff) as u8,
a: ((0.5 + color.a * COLOR_FLOAT_TO_FIXED_WIDE).floor() as u32 >> shift_by & 0xff) as u8,
}
}
}
#[derive(Debug, Clone, Copy)]
#[repr(C)]
pub struct PackedVertex {

Просмотреть файл

@ -8,9 +8,9 @@ use border::BorderCornerInstance;
use euclid::{Size2D};
use gpu_cache::{GpuBlockData, GpuCache, GpuCacheHandle, GpuDataRequest, ToGpuBlocks};
use gpu_store::GpuStoreAddress;
use internal_types::SourceTexture;
use internal_types::{SourceTexture, PackedTexel};
use mask_cache::{ClipMode, ClipSource, MaskCacheInfo};
use renderer::{VertexDataStore, MAX_VERTEX_TEXTURE_WIDTH};
use renderer::{VertexDataStore, GradientDataStore, SplitGeometryStore, MAX_VERTEX_TEXTURE_WIDTH};
use render_task::{RenderTask, RenderTaskLocation};
use resource_cache::{CacheItem, ImageProperties, ResourceCache};
use std::mem;
@ -23,7 +23,7 @@ use webrender_traits::{device_length, DeviceIntRect, DeviceIntSize};
use webrender_traits::{DeviceRect, DevicePoint, DeviceSize};
use webrender_traits::{LayerRect, LayerSize, LayerPoint, LayoutPoint};
use webrender_traits::{LayerToWorldTransform, GlyphInstance, GlyphOptions};
use webrender_traits::{ExtendMode, GradientStop, TileOffset};
use webrender_traits::{ExtendMode, GradientStop, AuxIter, TileOffset};
pub const CLIP_DATA_GPU_SIZE: usize = 5;
pub const MASK_DATA_GPU_SIZE: usize = 1;
@ -89,6 +89,22 @@ pub enum PrimitiveKind {
BoxShadow,
}
/// Geometry description for simple rectangular primitives, uploaded to the GPU.
#[derive(Debug, Clone)]
pub struct PrimitiveGeometry {
pub local_rect: LayerRect,
pub local_clip_rect: LayerRect,
}
impl Default for PrimitiveGeometry {
fn default() -> PrimitiveGeometry {
PrimitiveGeometry {
local_rect: unsafe { mem::uninitialized() },
local_clip_rect: unsafe { mem::uninitialized() },
}
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum PrimitiveCacheKey {
BoxShadow(BoxShadowPrimitiveCacheKey),
@ -125,12 +141,6 @@ pub struct PrimitiveMetadata {
// text run.
pub render_task: Option<RenderTask>,
pub clip_task: Option<RenderTask>,
// TODO(gw): In the future, we should just pull these
// directly from the DL item, instead of
// storing them here.
pub local_rect: LayerRect,
pub local_clip_rect: LayerRect,
}
impl PrimitiveMetadata {
@ -139,6 +149,20 @@ impl PrimitiveMetadata {
}
}
#[derive(Debug, Clone)]
pub struct SplitGeometry {
pub data: [f32; 12],
}
impl Default for SplitGeometry {
fn default() -> SplitGeometry {
SplitGeometry {
data: unsafe { mem::uninitialized() },
}
}
}
#[derive(Debug, Clone)]
#[repr(C)]
pub struct RectanglePrimitive {
@ -246,36 +270,45 @@ impl ToGpuBlocks for BoxShadowPrimitiveCpu {
}
}
#[derive(Debug, Clone)]
#[repr(C)]
pub struct GradientStopGpu {
color: ColorF,
offset: f32,
padding: [f32; 3],
}
#[derive(Debug)]
pub struct GradientPrimitiveCpu {
pub stops_range: ItemRange<GradientStop>,
pub stops_count: usize,
pub extend_mode: ExtendMode,
pub reverse_stops: bool,
pub cache_dirty: bool,
pub gpu_data_address: GpuStoreAddress,
pub gpu_data_count: i32,
pub gpu_blocks: [GpuBlockData; 3],
}
impl GradientPrimitiveCpu {
fn build_gpu_blocks_for_aligned(&self,
display_list: &BuiltDisplayList,
mut request: GpuDataRequest) {
impl ToGpuBlocks for GradientPrimitiveCpu {
fn write_gpu_blocks(&self, mut request: GpuDataRequest) {
request.extend_from_slice(&self.gpu_blocks);
let src_stops = display_list.get(self.stops_range);
for src in src_stops {
request.push(src.color.premultiplied().into());
request.push([src.offset, 0.0, 0.0, 0.0].into());
}
}
}
fn build_gpu_blocks_for_angle_radial(&self,
display_list: &BuiltDisplayList,
mut request: GpuDataRequest) {
#[derive(Debug)]
pub struct RadialGradientPrimitiveCpu {
pub stops_range: ItemRange<GradientStop>,
pub extend_mode: ExtendMode,
pub cache_dirty: bool,
pub gpu_data_address: GpuStoreAddress,
pub gpu_data_count: i32,
pub gpu_blocks: [GpuBlockData; 3],
}
impl ToGpuBlocks for RadialGradientPrimitiveCpu {
fn write_gpu_blocks(&self, mut request: GpuDataRequest) {
request.extend_from_slice(&self.gpu_blocks);
let gradient_builder = GradientGpuBlockBuilder::new(self.stops_range,
display_list);
gradient_builder.build(self.reverse_stops, &mut request);
}
}
@ -298,32 +331,47 @@ pub const GRADIENT_DATA_SIZE: usize = GRADIENT_DATA_TABLE_SIZE + 2;
#[repr(C)]
// An entry in a gradient data table representing a segment of the gradient color space.
pub struct GradientDataEntry {
pub start_color: ColorF,
pub end_color: ColorF,
pub start_color: PackedTexel,
pub end_color: PackedTexel,
}
struct GradientGpuBlockBuilder<'a> {
stops_range: ItemRange<GradientStop>,
display_list: &'a BuiltDisplayList,
#[repr(C)]
// A table of gradient entries, with two colors per entry, that specify the start and end color
// within the segment of the gradient space represented by that entry. To lookup a gradient result,
// first the entry index is calculated to determine which two colors to interpolate between, then
// the offset within that entry bucket is used to interpolate between the two colors in that entry.
// This layout preserves hard stops, as the end color for a given entry can differ from the start
// color for the following entry, despite them being adjacent. Colors are stored within in BGRA8
// format for texture upload. This table requires the gradient color stops to be normalized to the
// range [0, 1]. The first and last entries hold the first and last color stop colors respectively,
// while the entries in between hold the interpolated color stop values for the range [0, 1].
pub struct GradientData {
pub colors_high: [GradientDataEntry; GRADIENT_DATA_SIZE],
pub colors_low: [GradientDataEntry; GRADIENT_DATA_SIZE],
}
impl<'a> GradientGpuBlockBuilder<'a> {
fn new(stops_range: ItemRange<GradientStop>,
display_list: &'a BuiltDisplayList) -> GradientGpuBlockBuilder<'a> {
GradientGpuBlockBuilder {
stops_range: stops_range,
display_list: display_list,
impl Default for GradientData {
fn default() -> GradientData {
GradientData {
colors_high: unsafe { mem::uninitialized() },
colors_low: unsafe { mem::uninitialized() }
}
}
}
impl Clone for GradientData {
fn clone(&self) -> GradientData {
GradientData {
colors_high: self.colors_high,
colors_low: self.colors_low,
}
}
}
impl GradientData {
/// Generate a color ramp filling the indices in [start_idx, end_idx) and interpolating
/// from start_color to end_color.
fn fill_colors(&self,
start_idx: usize,
end_idx: usize,
start_color: &ColorF,
end_color: &ColorF,
entries: &mut [GradientDataEntry; GRADIENT_DATA_SIZE]) {
fn fill_colors(&mut self, start_idx: usize, end_idx: usize, start_color: &ColorF, end_color: &ColorF) {
// Calculate the color difference for individual steps in the ramp.
let inv_steps = 1.0 / (end_idx - start_idx) as f32;
let step_r = (end_color.r - start_color.r) * inv_steps;
@ -332,16 +380,24 @@ impl<'a> GradientGpuBlockBuilder<'a> {
let step_a = (end_color.a - start_color.a) * inv_steps;
let mut cur_color = *start_color;
let mut cur_color_high = PackedTexel::high_bytes(&cur_color);
let mut cur_color_low = PackedTexel::low_bytes(&cur_color);
// Walk the ramp writing start and end colors for each entry.
for index in start_idx..end_idx {
let entry = &mut entries[index];
entry.start_color = cur_color;
let high_byte_entry = &mut self.colors_high[index];
let low_byte_entry = &mut self.colors_low[index];
high_byte_entry.start_color = cur_color_high;
low_byte_entry.start_color = cur_color_low;
cur_color.r += step_r;
cur_color.g += step_g;
cur_color.b += step_b;
cur_color.a += step_a;
entry.end_color = cur_color;
cur_color_high = PackedTexel::high_bytes(&cur_color);
cur_color_low = PackedTexel::low_bytes(&cur_color);
high_byte_entry.end_color = cur_color_high;
low_byte_entry.end_color = cur_color_low;
}
}
@ -355,8 +411,7 @@ impl<'a> GradientGpuBlockBuilder<'a> {
}
// Build the gradient data from the supplied stops, reversing them if necessary.
fn build(&self, reverse_stops: bool, request: &mut GpuDataRequest) {
let src_stops = self.display_list.get(self.stops_range);
fn build(&mut self, src_stops: AuxIter<GradientStop>, reverse_stops: bool) {
// Preconditions (should be ensured by DisplayListBuilder):
// * we have at least two stops
@ -368,20 +423,9 @@ impl<'a> GradientGpuBlockBuilder<'a> {
let mut cur_color = first.color.premultiplied();
debug_assert_eq!(first.offset, 0.0);
// A table of gradient entries, with two colors per entry, that specify the start and end color
// within the segment of the gradient space represented by that entry. To lookup a gradient result,
// first the entry index is calculated to determine which two colors to interpolate between, then
// the offset within that entry bucket is used to interpolate between the two colors in that entry.
// This layout preserves hard stops, as the end color for a given entry can differ from the start
// color for the following entry, despite them being adjacent. Colors are stored within in BGRA8
// format for texture upload. This table requires the gradient color stops to be normalized to the
// range [0, 1]. The first and last entries hold the first and last color stop colors respectively,
// while the entries in between hold the interpolated color stop values for the range [0, 1].
let mut entries: [GradientDataEntry; GRADIENT_DATA_SIZE] = unsafe { mem::uninitialized() };
if reverse_stops {
// Fill in the first entry (for reversed stops) with the first color stop
self.fill_colors(GRADIENT_DATA_LAST_STOP, GRADIENT_DATA_LAST_STOP + 1, &cur_color, &cur_color, &mut entries);
self.fill_colors(GRADIENT_DATA_LAST_STOP, GRADIENT_DATA_LAST_STOP + 1, &cur_color, &cur_color);
// Fill in the center of the gradient table, generating a color ramp between each consecutive pair
// of gradient stops. Each iteration of a loop will fill the indices in [next_idx, cur_idx). The
@ -393,7 +437,7 @@ impl<'a> GradientGpuBlockBuilder<'a> {
if next_idx < cur_idx {
self.fill_colors(next_idx, cur_idx,
&next_color, &cur_color, &mut entries);
&next_color, &cur_color);
cur_idx = next_idx;
}
@ -402,10 +446,10 @@ impl<'a> GradientGpuBlockBuilder<'a> {
debug_assert_eq!(cur_idx, GRADIENT_DATA_TABLE_BEGIN);
// Fill in the last entry (for reversed stops) with the last color stop
self.fill_colors(GRADIENT_DATA_FIRST_STOP, GRADIENT_DATA_FIRST_STOP + 1, &cur_color, &cur_color, &mut entries);
self.fill_colors(GRADIENT_DATA_FIRST_STOP, GRADIENT_DATA_FIRST_STOP + 1, &cur_color, &cur_color);
} else {
// Fill in the first entry with the first color stop
self.fill_colors(GRADIENT_DATA_FIRST_STOP, GRADIENT_DATA_FIRST_STOP + 1, &cur_color, &cur_color, &mut entries);
self.fill_colors(GRADIENT_DATA_FIRST_STOP, GRADIENT_DATA_FIRST_STOP + 1, &cur_color, &cur_color);
// Fill in the center of the gradient table, generating a color ramp between each consecutive pair
// of gradient stops. Each iteration of a loop will fill the indices in [cur_idx, next_idx). The
@ -417,7 +461,7 @@ impl<'a> GradientGpuBlockBuilder<'a> {
if next_idx > cur_idx {
self.fill_colors(cur_idx, next_idx,
&cur_color, &next_color, &mut entries);
&cur_color, &next_color);
cur_idx = next_idx;
}
@ -426,35 +470,15 @@ impl<'a> GradientGpuBlockBuilder<'a> {
debug_assert_eq!(cur_idx, GRADIENT_DATA_TABLE_END);
// Fill in the last entry with the last color stop
self.fill_colors(GRADIENT_DATA_LAST_STOP, GRADIENT_DATA_LAST_STOP + 1, &cur_color, &cur_color, &mut entries);
}
for entry in entries.iter() {
request.push(entry.start_color.into());
request.push(entry.end_color.into());
self.fill_colors(GRADIENT_DATA_LAST_STOP, GRADIENT_DATA_LAST_STOP + 1, &cur_color, &cur_color);
}
}
}
#[derive(Debug)]
pub struct RadialGradientPrimitiveCpu {
pub stops_range: ItemRange<GradientStop>,
pub extend_mode: ExtendMode,
pub gpu_data_address: GpuStoreAddress,
pub gpu_data_count: i32,
pub gpu_blocks: [GpuBlockData; 3],
}
impl RadialGradientPrimitiveCpu {
fn build_gpu_blocks_for_angle_radial(&self,
display_list: &BuiltDisplayList,
mut request: GpuDataRequest) {
request.extend_from_slice(&self.gpu_blocks);
let gradient_builder = GradientGpuBlockBuilder::new(self.stops_range,
display_list);
gradient_builder.build(false, &mut request);
}
#[derive(Debug, Clone)]
#[repr(C)]
struct InstanceRect {
rect: LayerRect,
}
#[derive(Debug, Clone)]
@ -464,6 +488,7 @@ pub struct TextRunPrimitiveCpu {
pub blur_radius: f32,
pub glyph_range: ItemRange<GlyphInstance>,
pub glyph_count: usize,
pub cache_dirty: bool,
// TODO(gw): Maybe make this an Arc for sharing with resource cache
pub glyph_instances: Vec<GlyphInstance>,
pub color_texture_id: SourceTexture,
@ -471,24 +496,13 @@ pub struct TextRunPrimitiveCpu {
pub render_mode: FontRenderMode,
pub resource_address: GpuStoreAddress,
pub glyph_options: Option<GlyphOptions>,
pub gpu_data_address: GpuStoreAddress,
pub gpu_data_count: i32,
}
impl ToGpuBlocks for TextRunPrimitiveCpu {
fn write_gpu_blocks(&self, mut request: GpuDataRequest) {
request.push(self.color.into());
// Two glyphs are packed per GPU block.
for glyph_chunk in self.glyph_instances.chunks(2) {
// In the case of an odd number of glyphs, the
// last glyph will get duplicated in the final
// GPU block.
let first_glyph = glyph_chunk.first().unwrap();
let second_glyph = glyph_chunk.last().unwrap();
request.push([first_glyph.point.x,
first_glyph.point.y,
second_glyph.point.x,
second_glyph.point.y].into());
}
}
}
@ -652,7 +666,13 @@ pub struct PrimitiveStore {
pub cpu_box_shadows: Vec<BoxShadowPrimitiveCpu>,
/// Gets uploaded directly to GPU via vertex texture.
pub gpu_geometry: VertexDataStore<PrimitiveGeometry>,
pub gpu_data16: VertexDataStore<GpuBlock16>,
pub gpu_data32: VertexDataStore<GpuBlock32>,
pub gpu_gradient_data: GradientDataStore,
/// Geometry generated by plane splitting.
pub gpu_split_geometry: SplitGeometryStore,
/// Resolved resource rects.
pub gpu_resource_rects: VertexDataStore<TexelRect>,
@ -675,7 +695,11 @@ impl PrimitiveStore {
cpu_borders: Vec::new(),
cpu_box_shadows: Vec::new(),
prims_to_resolve: Vec::new(),
gpu_geometry: VertexDataStore::new(),
gpu_data16: VertexDataStore::new(),
gpu_data32: VertexDataStore::new(),
gpu_gradient_data: GradientDataStore::new(),
gpu_split_geometry: SplitGeometryStore::new(),
gpu_resource_rects: VertexDataStore::new(),
}
}
@ -693,7 +717,11 @@ impl PrimitiveStore {
cpu_borders: recycle_vec(self.cpu_borders),
cpu_box_shadows: recycle_vec(self.cpu_box_shadows),
prims_to_resolve: recycle_vec(self.prims_to_resolve),
gpu_geometry: self.gpu_geometry.recycle(),
gpu_data16: self.gpu_data16.recycle(),
gpu_data32: self.gpu_data32.recycle(),
gpu_gradient_data: self.gpu_gradient_data.recycle(),
gpu_split_geometry: self.gpu_split_geometry.recycle(),
gpu_resource_rects: self.gpu_resource_rects.recycle(),
}
}
@ -707,13 +735,13 @@ impl PrimitiveStore {
}
pub fn add_primitive(&mut self,
local_rect: &LayerRect,
local_clip_rect: &LayerRect,
geometry: PrimitiveGeometry,
clips: Vec<ClipSource>,
clip_info: Option<MaskCacheInfo>,
container: PrimitiveContainer) -> PrimitiveIndex {
let prim_index = self.cpu_metadata.len();
self.cpu_bounding_rects.push(None);
self.gpu_geometry.push(geometry);
let metadata = match container {
PrimitiveContainer::Rectangle(rect) => {
@ -728,8 +756,6 @@ impl PrimitiveStore {
gpu_location: GpuCacheHandle::new(),
render_task: None,
clip_task: None,
local_rect: *local_rect,
local_clip_rect: *local_clip_rect,
};
self.cpu_rectangles.push(rect);
@ -737,7 +763,10 @@ impl PrimitiveStore {
metadata
}
PrimitiveContainer::TextRun(mut text_cpu) => {
let gpu_glyphs_address = self.gpu_data16.alloc(text_cpu.glyph_count);
text_cpu.resource_address = self.gpu_resource_rects.alloc(text_cpu.glyph_count);
text_cpu.gpu_data_address = gpu_glyphs_address;
text_cpu.gpu_data_count = text_cpu.glyph_count as i32;
let metadata = PrimitiveMetadata {
is_opaque: false,
@ -748,8 +777,6 @@ impl PrimitiveStore {
gpu_location: GpuCacheHandle::new(),
render_task: None,
clip_task: None,
local_rect: *local_rect,
local_clip_rect: *local_clip_rect,
};
self.cpu_text_runs.push(text_cpu);
@ -767,8 +794,6 @@ impl PrimitiveStore {
gpu_location: GpuCacheHandle::new(),
render_task: None,
clip_task: None,
local_rect: *local_rect,
local_clip_rect: *local_clip_rect,
};
self.cpu_images.push(image_cpu);
@ -786,8 +811,6 @@ impl PrimitiveStore {
gpu_location: GpuCacheHandle::new(),
render_task: None,
clip_task: None,
local_rect: *local_rect,
local_clip_rect: *local_clip_rect,
};
self.cpu_yuv_images.push(image_cpu);
@ -803,14 +826,17 @@ impl PrimitiveStore {
gpu_location: GpuCacheHandle::new(),
render_task: None,
clip_task: None,
local_rect: *local_rect,
local_clip_rect: *local_clip_rect,
};
self.cpu_borders.push(border_cpu);
metadata
}
PrimitiveContainer::AlignedGradient(gradient_cpu) => {
PrimitiveContainer::AlignedGradient(mut gradient_cpu) => {
let gpu_stops_address = self.gpu_data32.alloc(gradient_cpu.stops_count);
gradient_cpu.gpu_data_address = gpu_stops_address;
gradient_cpu.gpu_data_count = gradient_cpu.stops_count as i32;
let metadata = PrimitiveMetadata {
// TODO: calculate if the gradient is actually opaque
is_opaque: false,
@ -821,14 +847,17 @@ impl PrimitiveStore {
gpu_location: GpuCacheHandle::new(),
render_task: None,
clip_task: None,
local_rect: *local_rect,
local_clip_rect: *local_clip_rect,
};
self.cpu_gradients.push(gradient_cpu);
metadata
}
PrimitiveContainer::AngleGradient(gradient_cpu) => {
PrimitiveContainer::AngleGradient(mut gradient_cpu) => {
let gpu_gradient_address = self.gpu_gradient_data.alloc(1);
gradient_cpu.gpu_data_address = gpu_gradient_address;
gradient_cpu.gpu_data_count = 1;
let metadata = PrimitiveMetadata {
// TODO: calculate if the gradient is actually opaque
is_opaque: false,
@ -839,14 +868,17 @@ impl PrimitiveStore {
gpu_location: GpuCacheHandle::new(),
render_task: None,
clip_task: None,
local_rect: *local_rect,
local_clip_rect: *local_clip_rect,
};
self.cpu_gradients.push(gradient_cpu);
metadata
}
PrimitiveContainer::RadialGradient(radial_gradient_cpu) => {
PrimitiveContainer::RadialGradient(mut radial_gradient_cpu) => {
let gpu_gradient_address = self.gpu_gradient_data.alloc(1);
radial_gradient_cpu.gpu_data_address = gpu_gradient_address;
radial_gradient_cpu.gpu_data_count = 1;
let metadata = PrimitiveMetadata {
// TODO: calculate if the gradient is actually opaque
is_opaque: false,
@ -857,8 +889,6 @@ impl PrimitiveStore {
gpu_location: GpuCacheHandle::new(),
render_task: None,
clip_task: None,
local_rect: *local_rect,
local_clip_rect: *local_clip_rect,
};
self.cpu_radial_gradients.push(radial_gradient_cpu);
@ -899,8 +929,6 @@ impl PrimitiveStore {
gpu_location: GpuCacheHandle::new(),
render_task: Some(render_task),
clip_task: None,
local_rect: *local_rect,
local_clip_rect: *local_clip_rect,
};
self.cpu_box_shadows.push(box_shadow);
@ -1074,6 +1102,28 @@ impl PrimitiveStore {
deferred_resolves
}
pub fn set_clip_source(&mut self, index: PrimitiveIndex, source: Option<ClipSource>) {
let metadata = &mut self.cpu_metadata[index.0];
metadata.clips = match source {
Some(source) => {
let (rect, is_complex) = match source {
ClipSource::Complex(rect, radius, _) => (rect, radius > 0.0),
ClipSource::Region(ref region, _) => (region.main, region.is_complex()),
ClipSource::BorderCorner{..} => panic!("Not supported!"),
};
self.gpu_geometry.get_mut(GpuStoreAddress(index.0 as i32))
.local_clip_rect = rect;
if is_complex {
metadata.clip_cache_info = None; //CLIP TODO: re-use the existing GPU allocation
}
vec![source]
}
None => {
vec![]
}
}
}
pub fn get_metadata(&self, index: PrimitiveIndex) -> &PrimitiveMetadata {
&self.cpu_metadata[index.0]
}
@ -1088,12 +1138,12 @@ impl PrimitiveStore {
layer_transform: &LayerToWorldTransform,
layer_combined_local_clip_rect: &LayerRect,
device_pixel_ratio: f32) -> bool {
let metadata = &self.cpu_metadata[prim_index.0];
let geom = &self.gpu_geometry.get(GpuStoreAddress(prim_index.0 as i32));
let bounding_rect = metadata.local_rect
.intersection(&metadata.local_clip_rect)
.and_then(|rect| rect.intersection(layer_combined_local_clip_rect))
.and_then(|ref local_rect| {
let bounding_rect = geom.local_rect
.intersection(&geom.local_clip_rect)
.and_then(|rect| rect.intersection(layer_combined_local_clip_rect))
.and_then(|ref local_rect| {
let xf_rect = TransformedRect::new(local_rect,
layer_transform,
device_pixel_ratio);
@ -1108,7 +1158,6 @@ impl PrimitiveStore {
pub fn prepare_prim_for_render(&mut self,
prim_index: PrimitiveIndex,
resource_cache: &mut ResourceCache,
gpu_cache: &mut GpuCache,
layer_transform: &LayerToWorldTransform,
device_pixel_ratio: f32,
display_list: &BuiltDisplayList) {
@ -1116,6 +1165,45 @@ impl PrimitiveStore {
let metadata = &mut self.cpu_metadata[prim_index.0];
let mut prim_needs_resolve = false;
// Mark this GPU resource as required for this frame.
if let Some(request) = resource_cache.gpu_cache.request(&mut metadata.gpu_location) {
match metadata.prim_kind {
PrimitiveKind::Rectangle => {
let rect = &self.cpu_rectangles[metadata.cpu_prim_index.0];
rect.write_gpu_blocks(request);
}
PrimitiveKind::Border => {
let border = &self.cpu_borders[metadata.cpu_prim_index.0];
border.write_gpu_blocks(request);
}
PrimitiveKind::BoxShadow => {
let box_shadow = &self.cpu_box_shadows[metadata.cpu_prim_index.0];
box_shadow.write_gpu_blocks(request);
}
PrimitiveKind::Image => {
let image = &self.cpu_images[metadata.cpu_prim_index.0];
image.write_gpu_blocks(request);
}
PrimitiveKind::YuvImage => {
let yuv_image = &self.cpu_yuv_images[metadata.cpu_prim_index.0];
yuv_image.write_gpu_blocks(request);
}
PrimitiveKind::AlignedGradient |
PrimitiveKind::AngleGradient => {
let gradient = &self.cpu_gradients[metadata.cpu_prim_index.0];
gradient.write_gpu_blocks(request);
}
PrimitiveKind::RadialGradient => {
let gradient = &self.cpu_radial_gradients[metadata.cpu_prim_index.0];
gradient.write_gpu_blocks(request);
}
PrimitiveKind::TextRun => {
let text = &self.cpu_text_runs[metadata.cpu_prim_index.0];
text.write_gpu_blocks(request);
}
}
}
if let Some(ref mut clip_info) = metadata.clip_cache_info {
clip_info.update(&metadata.clips,
layer_transform,
@ -1155,14 +1243,23 @@ impl PrimitiveStore {
let src_glyphs = display_list.get(text.glyph_range);
prim_needs_resolve = true;
// Cache the glyph positions, if not in the cache already.
if text.glyph_instances.is_empty() {
if text.cache_dirty {
text.cache_dirty = false;
debug_assert!(text.gpu_data_count == src_glyphs.len() as i32);
debug_assert!(text.glyph_instances.is_empty());
let dest_glyphs = self.gpu_data16.get_slice_mut(text.gpu_data_address,
src_glyphs.len());
let mut glyph_key = GlyphKey::new(text.font_key,
font_size_dp,
text.color,
0,
LayoutPoint::new(0.0, 0.0),
text.render_mode);
let mut actual_glyph_count = 0;
for src in src_glyphs {
glyph_key.index = src.index;
glyph_key.subpixel_point.set_offset(src.point, text.render_mode);
@ -1180,31 +1277,42 @@ impl PrimitiveStore {
let glyph_pos = LayerPoint::new(x, y);
dest_glyphs[actual_glyph_count] = GpuBlock16::from(GlyphPrimitive {
padding: LayerPoint::zero(),
offset: glyph_pos,
});
text.glyph_instances.push(GlyphInstance {
index: src.index,
point: glyph_pos,
});
}
}
metadata.render_task = if text.blur_radius == 0.0 {
None
} else {
// This is a text-shadow element. Create a render task that will
// render the text run to a target, and then apply a gaussian
// blur to that text run in order to build the actual primitive
// which will be blitted to the framebuffer.
let cache_width = (metadata.local_rect.size.width * device_pixel_ratio).ceil() as i32;
let cache_height = (metadata.local_rect.size.height * device_pixel_ratio).ceil() as i32;
let cache_size = DeviceIntSize::new(cache_width, cache_height);
let cache_key = PrimitiveCacheKey::TextShadow(prim_index);
let blur_radius = device_length(text.blur_radius,
device_pixel_ratio);
Some(RenderTask::new_blur(cache_key,
cache_size,
blur_radius,
prim_index))
};
actual_glyph_count += 1;
}
let render_task = if text.blur_radius == 0.0 {
None
} else {
// This is a text-shadow element. Create a render task that will
// render the text run to a target, and then apply a gaussian
// blur to that text run in order to build the actual primitive
// which will be blitted to the framebuffer.
let geom = &self.gpu_geometry.get(GpuStoreAddress(prim_index.0 as i32));
let cache_width = (geom.local_rect.size.width * device_pixel_ratio).ceil() as i32;
let cache_height = (geom.local_rect.size.height * device_pixel_ratio).ceil() as i32;
let cache_size = DeviceIntSize::new(cache_width, cache_height);
let cache_key = PrimitiveCacheKey::TextShadow(prim_index);
let blur_radius = device_length(text.blur_radius,
device_pixel_ratio);
Some(RenderTask::new_blur(cache_key,
cache_size,
blur_radius,
prim_index))
};
text.gpu_data_count = actual_glyph_count as i32;
metadata.render_task = render_task;
}
resource_cache.request_glyphs(text.font_key,
font_size_dp,
@ -1246,55 +1354,44 @@ impl PrimitiveStore {
// TODO(nical): Currently assuming no tile_spacing for yuv images.
metadata.is_opaque = true;
}
PrimitiveKind::AlignedGradient |
PrimitiveKind::AngleGradient |
PrimitiveKind::RadialGradient => {}
}
PrimitiveKind::AlignedGradient => {
let gradient = &mut self.cpu_gradients[metadata.cpu_prim_index.0];
if gradient.cache_dirty {
let src_stops = display_list.get(gradient.stops_range);
// Mark this GPU resource as required for this frame.
if let Some(mut request) = gpu_cache.request(&mut metadata.gpu_location) {
request.push(metadata.local_rect.into());
request.push(metadata.local_clip_rect.into());
debug_assert!(gradient.gpu_data_count == src_stops.len() as i32);
let dest_stops = self.gpu_data32.get_slice_mut(gradient.gpu_data_address,
src_stops.len());
match metadata.prim_kind {
PrimitiveKind::Rectangle => {
let rect = &self.cpu_rectangles[metadata.cpu_prim_index.0];
rect.write_gpu_blocks(request);
for (src, dest) in src_stops.zip(dest_stops.iter_mut()) {
*dest = GpuBlock32::from(GradientStopGpu {
offset: src.offset,
color: src.color.premultiplied(),
padding: [0.0; 3],
});
}
gradient.cache_dirty = false;
}
PrimitiveKind::Border => {
let border = &self.cpu_borders[metadata.cpu_prim_index.0];
border.write_gpu_blocks(request);
}
PrimitiveKind::AngleGradient => {
let gradient = &mut self.cpu_gradients[metadata.cpu_prim_index.0];
if gradient.cache_dirty {
let src_stops = display_list.get(gradient.stops_range);
let dest_gradient = self.gpu_gradient_data.get_mut(gradient.gpu_data_address);
dest_gradient.build(src_stops, gradient.reverse_stops);
gradient.cache_dirty = false;
}
PrimitiveKind::BoxShadow => {
let box_shadow = &self.cpu_box_shadows[metadata.cpu_prim_index.0];
box_shadow.write_gpu_blocks(request);
}
PrimitiveKind::Image => {
let image = &self.cpu_images[metadata.cpu_prim_index.0];
image.write_gpu_blocks(request);
}
PrimitiveKind::YuvImage => {
let yuv_image = &self.cpu_yuv_images[metadata.cpu_prim_index.0];
yuv_image.write_gpu_blocks(request);
}
PrimitiveKind::AlignedGradient => {
let gradient = &self.cpu_gradients[metadata.cpu_prim_index.0];
gradient.build_gpu_blocks_for_aligned(display_list,
request);
}
PrimitiveKind::AngleGradient => {
let gradient = &self.cpu_gradients[metadata.cpu_prim_index.0];
gradient.build_gpu_blocks_for_angle_radial(display_list,
request);
}
PrimitiveKind::RadialGradient => {
let gradient = &self.cpu_radial_gradients[metadata.cpu_prim_index.0];
gradient.build_gpu_blocks_for_angle_radial(display_list,
request);
}
PrimitiveKind::TextRun => {
let text = &self.cpu_text_runs[metadata.cpu_prim_index.0];
text.write_gpu_blocks(request);
}
PrimitiveKind::RadialGradient => {
let gradient = &mut self.cpu_radial_gradients[metadata.cpu_prim_index.0];
if gradient.cache_dirty {
let src_stops = display_list.get(gradient.stops_range);
let dest_gradient = self.gpu_gradient_data.get_mut(gradient.gpu_data_address);
dest_gradient.build(src_stops, false);
gradient.cache_dirty = false;
}
}
}
@ -1332,8 +1429,11 @@ macro_rules! define_gpu_block {
)
}
define_gpu_block!(GpuBlock16: [f32; 4] =
InstanceRect, GlyphPrimitive
);
define_gpu_block!(GpuBlock32: [f32; 8] =
ClipCorner, ClipRect, ImageMaskData,
GradientStopGpu, ClipCorner, ClipRect, ImageMaskData,
BorderCornerClipData, BorderCornerDashClipData, BorderCornerDotClipData
);

Просмотреть файл

@ -4,7 +4,7 @@
use debug_render::DebugRenderer;
use device::{Device, GpuMarker, GpuSample, NamedTag};
use euclid::{Point2D, Size2D, Rect, vec2};
use euclid::{Point2D, Size2D, Rect};
use std::collections::vec_deque::VecDeque;
use std::f32;
use std::mem;
@ -469,7 +469,7 @@ impl ProfileGraph {
let stats = self.stats();
let text_color = ColorF::new(1.0, 1.0, 0.0, 1.0);
let text_origin = rect.origin + vec2(rect.size.width, 20.0);
let text_origin = rect.origin + Point2D::new(rect.size.width, 20.0);
debug_renderer.add_text(text_origin.x,
text_origin.y,
description,

Просмотреть файл

@ -4,8 +4,7 @@
use frame::Frame;
use frame_builder::FrameBuilderConfig;
use gpu_cache::GpuCache;
use internal_types::{SourceTexture, ResultMsg, RendererFrame};
use internal_types::{FontTemplate, SourceTexture, ResultMsg, RendererFrame};
use profiler::{BackendProfileCounters, GpuCacheProfileCounters, TextureCacheProfileCounters};
use record::ApiRecordingReceiver;
use resource_cache::ResourceCache;
@ -24,7 +23,6 @@ use webrender_traits::{ApiMsg, BlobImageRenderer, BuiltDisplayList, DeviceIntPoi
use webrender_traits::{DeviceUintPoint, DeviceUintRect, DeviceUintSize, IdNamespace, ImageData};
use webrender_traits::{LayerPoint, PipelineId, RenderDispatcher, RenderNotifier};
use webrender_traits::{VRCompositorCommand, VRCompositorHandler, WebGLCommand, WebGLContextId};
use webrender_traits::{FontTemplate};
#[cfg(feature = "webgl")]
use offscreen_gl_context::GLContextDispatcher;
@ -51,7 +49,6 @@ pub struct RenderBackend {
inner_rect: DeviceUintRect,
next_namespace_id: IdNamespace,
gpu_cache: GpuCache,
resource_cache: ResourceCache,
scene: Scene,
@ -100,7 +97,6 @@ impl RenderBackend {
pinch_zoom_factor: 1.0,
pan: DeviceIntPoint::zero(),
resource_cache: resource_cache,
gpu_cache: GpuCache::new(),
scene: Scene::new(),
frame: Frame::new(config),
next_namespace_id: IdNamespace(1),
@ -498,7 +494,6 @@ impl RenderBackend {
let pan = LayerPoint::new(self.pan.x as f32 / accumulated_scale_factor,
self.pan.y as f32 / accumulated_scale_factor);
let frame = self.frame.build(&mut self.resource_cache,
&mut self.gpu_cache,
&self.scene.display_lists,
accumulated_scale_factor,
pan,

Просмотреть файл

@ -2,7 +2,7 @@
* 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 gpu_cache::GpuCacheHandle;
use gpu_store::GpuStoreAddress;
use internal_types::{HardwareCompositeOp, LowLevelFilterOp};
use mask_cache::{MaskBounds, MaskCacheInfo};
use prim_store::{PrimitiveCacheKey, PrimitiveIndex};
@ -55,7 +55,7 @@ pub enum AlphaRenderItem {
Primitive(Option<ClipScrollGroupIndex>, PrimitiveIndex, i32),
Blend(StackingContextIndex, RenderTaskId, LowLevelFilterOp, i32),
Composite(StackingContextIndex, RenderTaskId, RenderTaskId, MixBlendMode, i32),
SplitComposite(StackingContextIndex, RenderTaskId, GpuCacheHandle, i32),
SplitComposite(StackingContextIndex, RenderTaskId, GpuStoreAddress, i32),
HardwareComposite(StackingContextIndex, RenderTaskId, HardwareCompositeOp, i32),
}

Просмотреть файл

@ -14,7 +14,7 @@ use debug_render::DebugRenderer;
use device::{DepthFunction, Device, FrameId, ProgramId, TextureId, VertexFormat, GpuMarker, GpuProfiler};
use device::{GpuSample, TextureFilter, VAOId, VertexUsageHint, FileWatcherHandler, TextureTarget, ShaderError};
use device::get_gl_format_bgra;
use euclid::Transform3D;
use euclid::Matrix4D;
use fnv::FnvHasher;
use frame_builder::FrameBuilderConfig;
use gleam::gl;
@ -24,6 +24,7 @@ use internal_types::{CacheTextureId, RendererFrame, ResultMsg, TextureUpdateOp};
use internal_types::{TextureUpdateList, PackedVertex, RenderTargetMode};
use internal_types::{ORTHO_NEAR_PLANE, ORTHO_FAR_PLANE, SourceTexture};
use internal_types::{BatchTextures, TextureSampler};
use prim_store::{GradientData, SplitGeometry};
use profiler::{Profiler, BackendProfileCounters};
use profiler::{GpuProfileTag, RendererProfileTimers, RendererProfileCounters};
use record::ApiRecordingReceiver;
@ -54,7 +55,8 @@ use webgl_types::GLContextHandleWrapper;
use webrender_traits::{ColorF, Epoch, PipelineId, RenderNotifier, RenderDispatcher};
use webrender_traits::{ExternalImageId, ExternalImageType, ImageData, ImageFormat, RenderApiSender};
use webrender_traits::{DeviceIntRect, DeviceUintRect, DevicePoint, DeviceIntPoint, DeviceIntSize, DeviceUintSize};
use webrender_traits::{BlobImageRenderer, channel, FontRenderMode};
use webrender_traits::{ImageDescriptor, BlobImageRenderer};
use webrender_traits::{channel, FontRenderMode};
use webrender_traits::VRCompositorHandler;
use webrender_traits::{YuvColorSpace, YuvFormat};
use webrender_traits::{YUV_COLOR_SPACES, YUV_FORMATS};
@ -193,53 +195,37 @@ pub enum BlendMode {
/// The device-specific representation of the cache texture in gpu_cache.rs
struct CacheTexture {
current_id: TextureId,
next_id: TextureId,
id: TextureId,
}
impl CacheTexture {
fn new(device: &mut Device) -> CacheTexture {
let ids = device.create_texture_ids(2, TextureTarget::Default);
let id = device.create_texture_ids(1, TextureTarget::Default)[0];
CacheTexture {
current_id: ids[0],
next_id: ids[1],
id: id,
}
}
fn update(&mut self, device: &mut Device, updates: &GpuCacheUpdateList) {
// See if we need to create or resize the texture.
let current_dimensions = device.get_texture_dimensions(self.current_id);
let current_dimensions = device.get_texture_dimensions(self.id);
if updates.height > current_dimensions.height {
// TODO(gw): Handle resizing an existing cache texture.
if current_dimensions.height > 0 {
panic!("TODO: Implement texture copy!!!");
}
// Create a f32 texture that can be used for the vertex shader
// to fetch data from.
device.init_texture(self.next_id,
device.init_texture(self.id,
MAX_VERTEX_TEXTURE_WIDTH as u32,
updates.height as u32,
ImageFormat::RGBAF32,
TextureFilter::Nearest,
RenderTargetMode::SimpleRenderTarget,
RenderTargetMode::None,
None);
// Copy the current texture into the newly resized texture.
if current_dimensions.height > 0 {
device.bind_draw_target(Some((self.next_id, 0)), None);
let blit_rect = DeviceIntRect::new(DeviceIntPoint::zero(),
DeviceIntSize::new(MAX_VERTEX_TEXTURE_WIDTH as i32,
current_dimensions.height as i32));
// TODO(gw): Should probably switch this to glCopyTexSubImage2D, since we
// don't do any stretching here.
device.blit_render_target(Some((self.current_id, 0)),
Some(blit_rect),
blit_rect);
// Free the GPU memory for that texture until we need to resize again.
device.deinit_texture(self.current_id);
}
mem::swap(&mut self.current_id, &mut self.next_id);
}
for update in &updates.updates {
@ -258,7 +244,7 @@ impl CacheTexture {
.offset(block_index as isize);
slice::from_raw_parts(ptr as *const _, block_count * 16)
};
device.update_texture(self.current_id,
device.update_texture(self.id,
address.u as u32,
address.v as u32,
block_count as u32,
@ -340,6 +326,45 @@ impl GpuStoreLayout for VertexDataTextureLayout {
type VertexDataTexture = GpuDataTexture<VertexDataTextureLayout>;
pub type VertexDataStore<T> = GpuStore<T, VertexDataTextureLayout>;
pub struct GradientDataTextureLayout;
impl GpuStoreLayout for GradientDataTextureLayout {
fn image_format() -> ImageFormat {
ImageFormat::RGBA8
}
fn texture_width<T>() -> usize {
mem::size_of::<GradientData>() / Self::texel_size() / 2
}
fn texture_filter() -> TextureFilter {
TextureFilter::Linear
}
}
type GradientDataTexture = GpuDataTexture<GradientDataTextureLayout>;
pub type GradientDataStore = GpuStore<GradientData, GradientDataTextureLayout>;
pub struct SplitGeometryTextureLayout;
impl GpuStoreLayout for SplitGeometryTextureLayout {
fn image_format() -> ImageFormat {
//TODO: use normalized integers
ImageFormat::RGBAF32
}
fn texture_width<T>() -> usize {
MAX_VERTEX_TEXTURE_WIDTH - (MAX_VERTEX_TEXTURE_WIDTH % Self::texels_per_item::<T>())
}
fn texture_filter() -> TextureFilter {
TextureFilter::Nearest
}
}
type SplitGeometryTexture = GpuDataTexture<SplitGeometryTextureLayout>;
pub type SplitGeometryStore = GpuStore<SplitGeometry, SplitGeometryTextureLayout>;
const TRANSFORM_FEATURE: &'static str = "TRANSFORM";
const SUBPIXEL_AA_FEATURE: &'static str = "SUBPIXEL_AA";
const CLIP_FEATURE: &'static str = "CLIP";
@ -505,8 +530,12 @@ fn create_clip_shader(name: &'static str, device: &mut Device) -> Result<Program
struct GpuDataTextures {
layer_texture: VertexDataTexture,
render_task_texture: VertexDataTexture,
prim_geom_texture: VertexDataTexture,
data16_texture: VertexDataTexture,
data32_texture: VertexDataTexture,
resource_rects_texture: VertexDataTexture,
gradient_data_texture: GradientDataTexture,
split_geometry_texture: SplitGeometryTexture,
}
impl GpuDataTextures {
@ -514,21 +543,33 @@ impl GpuDataTextures {
GpuDataTextures {
layer_texture: VertexDataTexture::new(device),
render_task_texture: VertexDataTexture::new(device),
prim_geom_texture: VertexDataTexture::new(device),
data16_texture: VertexDataTexture::new(device),
data32_texture: VertexDataTexture::new(device),
resource_rects_texture: VertexDataTexture::new(device),
gradient_data_texture: GradientDataTexture::new(device),
split_geometry_texture: SplitGeometryTexture::new(device),
}
}
fn init_frame(&mut self, device: &mut Device, frame: &mut Frame) {
self.data16_texture.init(device, &mut frame.gpu_data16);
self.data32_texture.init(device, &mut frame.gpu_data32);
self.prim_geom_texture.init(device, &mut frame.gpu_geometry);
self.resource_rects_texture.init(device, &mut frame.gpu_resource_rects);
self.layer_texture.init(device, &mut frame.layer_texture_data);
self.render_task_texture.init(device, &mut frame.render_task_data);
self.gradient_data_texture.init(device, &mut frame.gpu_gradient_data);
self.split_geometry_texture.init(device, &mut frame.gpu_split_geometry);
device.bind_texture(TextureSampler::Layers, self.layer_texture.id);
device.bind_texture(TextureSampler::RenderTasks, self.render_task_texture.id);
device.bind_texture(TextureSampler::Geometry, self.prim_geom_texture.id);
device.bind_texture(TextureSampler::Data16, self.data16_texture.id);
device.bind_texture(TextureSampler::Data32, self.data32_texture.id);
device.bind_texture(TextureSampler::ResourceRects, self.resource_rects_texture.id);
device.bind_texture(TextureSampler::Gradients, self.gradient_data_texture.id);
device.bind_texture(TextureSampler::SplitGeometry, self.split_geometry_texture.id);
}
}
@ -951,8 +992,34 @@ impl Renderer {
let device_max_size = device.max_texture_size();
let max_texture_size = cmp::min(device_max_size, options.max_texture_size.unwrap_or(device_max_size));
let texture_cache = TextureCache::new(max_texture_size);
let backend_profile_counters = BackendProfileCounters::new();
let mut texture_cache = TextureCache::new(max_texture_size);
let mut backend_profile_counters = BackendProfileCounters::new();
let white_pixels: Vec<u8> = vec![
0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff,
];
let mask_pixels: Vec<u8> = vec![
0xff, 0xff,
0xff, 0xff,
];
// TODO: Ensure that the white texture can never get evicted when the cache supports LRU eviction!
let white_image_id = texture_cache.new_item_id();
texture_cache.insert(white_image_id,
ImageDescriptor::new(2, 2, ImageFormat::RGBA8, false),
TextureFilter::Linear,
ImageData::Raw(Arc::new(white_pixels)),
&mut backend_profile_counters.resources.texture_cache);
let dummy_mask_image_id = texture_cache.new_item_id();
texture_cache.insert(dummy_mask_image_id,
ImageDescriptor::new(2, 2, ImageFormat::A8, false),
TextureFilter::Linear,
ImageData::Raw(Arc::new(mask_pixels)),
&mut backend_profile_counters.resources.texture_cache);
let dummy_cache_texture_id = device.create_texture_ids(1, TextureTarget::Array)[0];
device.init_texture(dummy_cache_texture_id,
@ -1317,7 +1384,7 @@ impl Renderer {
self.update_texture_cache();
self.update_gpu_cache();
self.device.bind_texture(TextureSampler::ResourceCache, self.gpu_cache_texture.current_id);
self.device.bind_texture(TextureSampler::ResourceCache, self.gpu_cache_texture.id);
frame_id
};
@ -1519,7 +1586,7 @@ impl Renderer {
vao: VAOId,
shader: ProgramId,
textures: &BatchTextures,
projection: &Transform3D<f32>) {
projection: &Matrix4D<f32>) {
self.device.bind_vao(vao);
self.device.bind_program(shader, projection);
@ -1550,7 +1617,7 @@ impl Renderer {
fn submit_batch(&mut self,
batch: &PrimitiveBatch,
projection: &Transform3D<f32>,
projection: &Matrix4D<f32>,
render_task_data: &[RenderTaskData],
cache_texture: TextureId,
render_target: Option<(TextureId, i32)>,
@ -1714,7 +1781,7 @@ impl Renderer {
color_cache_texture: TextureId,
clear_color: Option<[f32; 4]>,
render_task_data: &[RenderTaskData],
projection: &Transform3D<f32>) {
projection: &Matrix4D<f32>) {
{
let _gm = self.gpu_profile.add_marker(GPU_TAG_SETUP_TARGET);
self.device.bind_draw_target(render_target, Some(target_size));
@ -1858,7 +1925,7 @@ impl Renderer {
render_target: (TextureId, i32),
target: &AlphaRenderTarget,
target_size: DeviceUintSize,
projection: &Transform3D<f32>) {
projection: &Matrix4D<f32>) {
{
let _gm = self.gpu_profile.add_marker(GPU_TAG_SETUP_TARGET);
self.device.bind_draw_target(Some(render_target), Some(target_size));
@ -2096,7 +2163,7 @@ impl Renderer {
None
};
size = framebuffer_size;
projection = Transform3D::ortho(0.0,
projection = Matrix4D::ortho(0.0,
size.width as f32,
size.height as f32,
0.0,
@ -2105,7 +2172,7 @@ impl Renderer {
} else {
size = &frame.cache_size;
clear_color = Some([0.0, 0.0, 0.0, 0.0]);
projection = Transform3D::ortho(0.0,
projection = Matrix4D::ortho(0.0,
size.width as f32,
0.0,
size.height as f32,

Просмотреть файл

@ -6,7 +6,8 @@ use app_units::Au;
use device::TextureFilter;
use fnv::FnvHasher;
use frame::FrameId;
use internal_types::{SourceTexture, TextureUpdateList};
use gpu_cache::GpuCache;
use internal_types::{FontTemplate, SourceTexture, TextureUpdateList};
use profiler::TextureCacheProfileCounters;
use std::collections::{HashMap, HashSet};
use std::collections::hash_map::Entry::{self, Occupied, Vacant};
@ -16,12 +17,11 @@ use std::hash::Hash;
use std::mem;
use std::sync::Arc;
use texture_cache::{TextureCache, TextureCacheItemId};
use webrender_traits::{Epoch, FontKey, FontTemplate, GlyphKey, ImageKey, ImageRendering};
use webrender_traits::{Epoch, FontKey, GlyphKey, ImageKey, ImageRendering};
use webrender_traits::{FontRenderMode, ImageData, GlyphDimensions, WebGLContextId};
use webrender_traits::{DevicePoint, DeviceIntSize, DeviceUintRect, ImageDescriptor, ColorF};
use webrender_traits::{GlyphOptions, GlyphInstance, TileOffset, TileSize};
use webrender_traits::{BlobImageRenderer, BlobImageDescriptor, BlobImageError, BlobImageRequest, BlobImageData};
use webrender_traits::BlobImageResources;
use webrender_traits::{BlobImageRenderer, BlobImageDescriptor, BlobImageError, BlobImageRequest, BlobImageData, ImageStore};
use webrender_traits::{ExternalImageData, ExternalImageType, LayoutPoint};
use rayon::ThreadPool;
use glyph_rasterizer::{GlyphRasterizer, GlyphCache, GlyphRequest};
@ -92,6 +92,12 @@ impl ImageTemplates {
}
}
impl ImageStore for ImageTemplates {
fn get_image(&self, key: ImageKey) -> Option<(&ImageData, &ImageDescriptor)> {
self.images.get(&key).map(|resource|{ (&resource.data, &resource.descriptor) })
}
}
struct CachedImageInfo {
texture_cache_id: TextureCacheItemId,
epoch: Epoch,
@ -180,20 +186,6 @@ struct WebGLTexture {
size: DeviceIntSize,
}
struct Resources {
font_templates: HashMap<FontKey, FontTemplate, BuildHasherDefault<FnvHasher>>,
image_templates: ImageTemplates,
}
impl BlobImageResources for Resources {
fn get_font_data(&self, key: FontKey) -> &FontTemplate {
self.font_templates.get(&key).unwrap()
}
fn get_image(&self, key: ImageKey) -> Option<(&ImageData, &ImageDescriptor)> {
self.image_templates.get(key).map(|resource| { (&resource.data, &resource.descriptor) })
}
}
pub struct ResourceCache {
cached_glyphs: GlyphCache,
cached_images: ResourceClassCache<ImageRequest, CachedImageInfo>,
@ -201,11 +193,13 @@ pub struct ResourceCache {
// TODO(pcwalton): Figure out the lifecycle of these.
webgl_textures: HashMap<WebGLContextId, WebGLTexture, BuildHasherDefault<FnvHasher>>,
resources: Resources,
font_templates: HashMap<FontKey, FontTemplate, BuildHasherDefault<FnvHasher>>,
image_templates: ImageTemplates,
state: State,
current_frame_id: FrameId,
texture_cache: TextureCache,
pub gpu_cache: GpuCache,
// TODO(gw): We should expire (parts of) this cache semi-regularly!
cached_glyph_dimensions: HashMap<GlyphKey, Option<GlyphDimensions>, BuildHasherDefault<FnvHasher>>,
@ -224,12 +218,11 @@ impl ResourceCache {
cached_glyphs: ResourceClassCache::new(),
cached_images: ResourceClassCache::new(),
webgl_textures: HashMap::default(),
resources: Resources {
font_templates: HashMap::default(),
image_templates: ImageTemplates::new(),
},
font_templates: HashMap::default(),
image_templates: ImageTemplates::new(),
cached_glyph_dimensions: HashMap::default(),
texture_cache: texture_cache,
gpu_cache: GpuCache::new(),
state: State::Idle,
current_frame_id: FrameId(0),
pending_image_requests: Vec::new(),
@ -261,15 +254,12 @@ impl ResourceCache {
// Push the new font to the font renderer, and also store
// it locally for glyph metric requests.
self.glyph_rasterizer.add_font(font_key, template.clone());
self.resources.font_templates.insert(font_key, template);
self.font_templates.insert(font_key, template);
}
pub fn delete_font_template(&mut self, font_key: FontKey) {
self.glyph_rasterizer.delete_font(font_key);
self.resources.font_templates.remove(&font_key);
if let Some(ref mut r) = self.blob_image_renderer {
r.delete_font(font_key);
}
self.font_templates.remove(&font_key);
}
pub fn add_image_template(&mut self,
@ -299,7 +289,7 @@ impl ResourceCache {
dirty_rect: None,
};
self.resources.image_templates.insert(image_key, resource);
self.image_templates.insert(image_key, resource);
}
pub fn update_image_template(&mut self,
@ -307,7 +297,7 @@ impl ResourceCache {
descriptor: ImageDescriptor,
mut data: ImageData,
dirty_rect: Option<DeviceUintRect>) {
let resource = if let Some(image) = self.resources.image_templates.get(image_key) {
let resource = if let Some(image) = self.image_templates.get(image_key) {
assert_eq!(image.descriptor.width, descriptor.width);
assert_eq!(image.descriptor.height, descriptor.height);
assert_eq!(image.descriptor.format, descriptor.format);
@ -341,11 +331,11 @@ impl ResourceCache {
panic!("Attempt to update non-existant image (key {:?}).", image_key);
};
self.resources.image_templates.insert(image_key, resource);
self.image_templates.insert(image_key, resource);
}
pub fn delete_image_template(&mut self, image_key: ImageKey) {
let value = self.resources.image_templates.remove(image_key);
let value = self.image_templates.remove(image_key);
match value {
Some(image) => {
@ -386,7 +376,7 @@ impl ResourceCache {
tile: tile,
};
let template = self.resources.image_templates.get(key).unwrap();
let template = self.image_templates.get(key).unwrap();
if template.data.uses_texture_cache() {
self.cached_images.mark_as_needed(&request, self.current_frame_id);
}
@ -415,7 +405,6 @@ impl ResourceCache {
};
renderer.request(
&self.resources,
request.into(),
&BlobImageDescriptor {
width: w,
@ -424,6 +413,7 @@ impl ResourceCache {
format: template.descriptor.format,
},
template.dirty_rect,
&self.image_templates,
);
}
}
@ -529,7 +519,7 @@ impl ResourceCache {
}
pub fn get_image_properties(&self, image_key: ImageKey) -> ImageProperties {
let image_template = &self.resources.image_templates.get(image_key).unwrap();
let image_template = &self.image_templates.get(image_key).unwrap();
let external_image = match image_template.data {
ImageData::External(ext_image) => {
@ -577,6 +567,7 @@ impl ResourceCache {
debug_assert_eq!(self.state, State::Idle);
self.state = State::AddResources;
self.current_frame_id = frame_id;
self.gpu_cache.begin_frame();
}
pub fn block_until_all_resources_added(&mut self,
@ -632,7 +623,7 @@ impl ResourceCache {
request: &ImageRequest,
image_data: Option<ImageData>,
texture_cache_profile: &mut TextureCacheProfileCounters) {
let image_template = self.resources.image_templates.get_mut(request.key).unwrap();
let image_template = self.image_templates.get_mut(request.key).unwrap();
let image_data = image_data.unwrap_or_else(||{
image_template.data.clone()
});
@ -689,15 +680,18 @@ impl ResourceCache {
}
}
Vacant(entry) => {
let image_id = self.texture_cache.new_item_id();
let filter = match request.rendering {
ImageRendering::Pixelated => TextureFilter::Nearest,
ImageRendering::Auto | ImageRendering::CrispEdges => TextureFilter::Linear,
};
let image_id = self.texture_cache.insert(descriptor,
filter,
image_data,
texture_cache_profile);
self.texture_cache.insert(image_id,
descriptor,
filter,
image_data,
texture_cache_profile);
entry.insert(CachedImageInfo {
texture_cache_id: image_id,
@ -710,7 +704,7 @@ impl ResourceCache {
request: ImageRequest,
image_data: Option<ImageData>,
texture_cache_profile: &mut TextureCacheProfileCounters) {
match self.resources.image_templates.get(request.key).unwrap().data {
match self.image_templates.get(request.key).unwrap().data {
ImageData::External(ext_image) => {
match ext_image.image_type {
ExternalImageType::Texture2DHandle |

Просмотреть файл

@ -445,6 +445,9 @@ pub struct TextureCacheItem {
// The texture coordinates for this item
pub pixel_rect: RectUv<i32, DevicePixel>,
// The size of the entire texture (not just the allocated rectangle)
pub texture_size: DeviceUintSize,
// The size of the allocated rectangle.
pub allocated_rect: DeviceUintRect,
}
@ -483,10 +486,12 @@ impl FreeListItem for TextureCacheItem {
impl TextureCacheItem {
fn new(texture_id: CacheTextureId,
rect: DeviceUintRect)
rect: DeviceUintRect,
texture_size: &DeviceUintSize)
-> TextureCacheItem {
TextureCacheItem {
texture_id: texture_id,
texture_size: *texture_size,
pixel_rect: RectUv {
top_left: DeviceIntPoint::new(rect.origin.x as i32,
rect.origin.y as i32),
@ -578,7 +583,6 @@ pub enum AllocationKind {
#[derive(Debug)]
pub struct AllocationResult {
image_id: TextureCacheItemId,
kind: AllocationKind,
item: TextureCacheItem,
}
@ -607,7 +611,18 @@ impl TextureCache {
mem::replace(&mut self.pending_updates, TextureUpdateList::new())
}
// TODO(gw): This API is a bit ugly (having to allocate an ID and
// then use it). But it has to be that way for now due to
// how the raster_jobs code works.
pub fn new_item_id(&mut self) -> TextureCacheItemId {
let new_item = TextureCacheItem::new(CacheTextureId(0),
DeviceUintRect::zero(),
&DeviceUintSize::zero());
self.items.insert(new_item)
}
pub fn allocate(&mut self,
image_id: TextureCacheItemId,
requested_width: u32,
requested_height: u32,
format: ImageFormat,
@ -626,13 +641,13 @@ impl TextureCache {
let texture_id = self.cache_id_list.allocate();
let cache_item = TextureCacheItem::new(
texture_id,
DeviceUintRect::new(DeviceUintPoint::zero(), requested_size));
let image_id = self.items.insert(cache_item);
DeviceUintRect::new(DeviceUintPoint::zero(), requested_size),
&requested_size);
*self.items.get_mut(image_id) = cache_item;
return AllocationResult {
item: self.items.get(image_id).clone(),
kind: AllocationKind::Standalone,
image_id: image_id,
}
}
@ -676,6 +691,12 @@ impl TextureCache {
page.grow(texture_size);
self.items.for_each_item(|item| {
if item.texture_id == page.texture_id {
item.texture_size = texture_size;
}
});
if page.can_allocate(&requested_size) {
page_id = Some(i);
break;
@ -722,13 +743,13 @@ impl TextureCache {
let location = page.allocate(&requested_size)
.expect("All the checks have passed till now, there is no way back.");
let cache_item = TextureCacheItem::new(page.texture_id,
DeviceUintRect::new(location, requested_size));
let image_id = self.items.insert(cache_item.clone());
DeviceUintRect::new(location, requested_size),
&page.texture_size);
*self.items.get_mut(image_id) = cache_item.clone();
AllocationResult {
item: cache_item,
kind: AllocationKind::TexturePage,
image_id: image_id,
}
}
@ -789,10 +810,11 @@ impl TextureCache {
}
pub fn insert(&mut self,
image_id: TextureCacheItemId,
descriptor: ImageDescriptor,
filter: TextureFilter,
data: ImageData,
profile: &mut TextureCacheProfileCounters) -> TextureCacheItemId {
profile: &mut TextureCacheProfileCounters) {
if let ImageData::Blob(..) = data {
panic!("must rasterize the vector image before adding to the cache");
}
@ -809,7 +831,8 @@ impl TextureCache {
assert!(vec.len() >= finish as usize);
}
let result = self.allocate(width,
let result = self.allocate(image_id,
width,
height,
format,
filter,
@ -906,8 +929,6 @@ impl TextureCache {
}
}
}
result.image_id
}
pub fn get(&self, id: TextureCacheItemId) -> &TextureCacheItem {

Просмотреть файл

@ -6,13 +6,13 @@ use app_units::Au;
use border::{BorderCornerInstance, BorderCornerSide};
use device::TextureId;
use fnv::FnvHasher;
use gpu_cache::{GpuCache, GpuCacheUpdateList};
use gpu_cache::GpuCacheUpdateList;
use gpu_store::GpuStoreAddress;
use internal_types::{ANGLE_FLOAT_TO_FIXED, BatchTextures, CacheTextureId, LowLevelFilterOp};
use internal_types::SourceTexture;
use mask_cache::MaskCacheInfo;
use prim_store::{CLIP_DATA_GPU_SIZE, DeferredResolve, GpuBlock32};
use prim_store::PrimitiveCacheKey;
use prim_store::{CLIP_DATA_GPU_SIZE, DeferredResolve, GpuBlock16, GpuBlock32};
use prim_store::{GradientData, SplitGeometry, PrimitiveCacheKey, PrimitiveGeometry};
use prim_store::{PrimitiveIndex, PrimitiveKind, PrimitiveMetadata, PrimitiveStore, TexelRect};
use profiler::FrameProfileCounters;
use render_task::{AlphaRenderItem, MaskGeometryKind, MaskSegment, RenderTask, RenderTaskData};
@ -28,9 +28,9 @@ use texture_cache::TexturePage;
use util::{TransformedRect, TransformedRectKind};
use webrender_traits::{BuiltDisplayList, ClipAndScrollInfo, ClipId, ColorF, DeviceIntPoint};
use webrender_traits::{DeviceIntRect, DeviceIntSize, DeviceUintPoint, DeviceUintSize};
use webrender_traits::{ExternalImageType, FontRenderMode, ImageRendering, LayerRect};
use webrender_traits::{ExternalImageType, FontRenderMode, ImageRendering, LayerPoint, LayerRect};
use webrender_traits::{LayerToWorldTransform, MixBlendMode, PipelineId, TransformStyle};
use webrender_traits::{WorldToLayerTransform, YuvColorSpace, YuvFormat, LayerVector2D};
use webrender_traits::{WorldToLayerTransform, YuvColorSpace, YuvFormat};
// Special sentinel value recognized by the shader. It is considered to be
// a dummy task that doesn't mask out anything.
@ -425,9 +425,10 @@ impl AlphaRenderItem {
let blend_mode = ctx.prim_store.get_blend_mode(needs_blending, prim_metadata);
let prim_cache_address = prim_metadata.gpu_location
.as_int(&ctx.gpu_cache);
.as_int(&ctx.resource_cache.gpu_cache);
let base_instance = SimplePrimitiveInstance::new(prim_cache_address,
let base_instance = SimplePrimitiveInstance::new(prim_index,
prim_cache_address,
task_index,
clip_task_index,
packed_layer_index,
@ -516,33 +517,38 @@ impl AlphaRenderItem {
None => 0,
};
let user_data1 = match batch_kind {
AlphaBatchKind::TextRun => text_cpu.resource_address.0,
AlphaBatchKind::CacheImage => cache_task_index,
_ => unreachable!(),
};
for glyph_index in 0..text_cpu.gpu_data_count {
let user_data1 = match batch_kind {
AlphaBatchKind::TextRun => text_cpu.resource_address.0 + glyph_index,
AlphaBatchKind::CacheImage => cache_task_index,
_ => unreachable!(),
};
for glyph_index in 0..text_cpu.glyph_instances.len() {
batch.add_instance(base_instance.build(glyph_index as i32, user_data1));
batch.add_instance(base_instance.build(text_cpu.gpu_data_address.0 + glyph_index,
user_data1));
}
}
PrimitiveKind::AlignedGradient => {
let gradient_cpu = &ctx.prim_store.cpu_gradients[prim_metadata.cpu_prim_index.0];
let key = AlphaBatchKey::new(AlphaBatchKind::AlignedGradient, flags, blend_mode, textures);
let batch = batch_list.get_suitable_batch(&key, item_bounding_rect);
for part_index in 0..(gradient_cpu.stops_count - 1) {
batch.add_instance(base_instance.build(part_index as i32, 0));
for part_index in 0..(gradient_cpu.gpu_data_count - 1) {
batch.add_instance(base_instance.build(gradient_cpu.gpu_data_address.0 + part_index, 0));
}
}
PrimitiveKind::AngleGradient => {
let gradient_cpu = &ctx.prim_store.cpu_gradients[prim_metadata.cpu_prim_index.0];
let key = AlphaBatchKey::new(AlphaBatchKind::AngleGradient, flags, blend_mode, textures);
let batch = batch_list.get_suitable_batch(&key, item_bounding_rect);
batch.add_instance(base_instance.build(0, 0));
batch.add_instance(base_instance.build(gradient_cpu.gpu_data_address.0,
0));
}
PrimitiveKind::RadialGradient => {
let gradient_cpu = &ctx.prim_store.cpu_radial_gradients[prim_metadata.cpu_prim_index.0];
let key = AlphaBatchKey::new(AlphaBatchKind::RadialGradient, flags, blend_mode, textures);
let batch = batch_list.get_suitable_batch(&key, item_bounding_rect);
batch.add_instance(base_instance.build(0, 0));
batch.add_instance(base_instance.build(gradient_cpu.gpu_data_address.0,
0));
}
PrimitiveKind::YuvImage => {
let image_yuv_cpu = &ctx.prim_store.cpu_yuv_images[prim_metadata.cpu_prim_index.0];
@ -598,7 +604,7 @@ impl AlphaRenderItem {
}
}
}
AlphaRenderItem::SplitComposite(sc_index, task_id, gpu_handle, z) => {
AlphaRenderItem::SplitComposite(sc_index, task_id, gpu_address, z) => {
let key = AlphaBatchKey::new(AlphaBatchKind::SplitComposite,
AlphaBatchKeyFlags::empty(),
BlendMode::PremultipliedAlpha,
@ -606,12 +612,11 @@ impl AlphaRenderItem {
let stacking_context = &ctx.stacking_context_store[sc_index.0];
let batch = batch_list.get_suitable_batch(&key, &stacking_context.screen_bounds);
let source_task = render_tasks.get_task_index(&task_id, child_pass_index);
let gpu_address = gpu_handle.as_int(ctx.gpu_cache);
let instance = CompositePrimitiveInstance::new(task_index,
source_task,
RenderTaskIndex(0),
gpu_address,
gpu_address.0,
0,
z);
@ -757,7 +762,6 @@ pub struct RenderTargetContext<'a> {
pub clip_scroll_group_store: &'a [ClipScrollGroup],
pub prim_store: &'a PrimitiveStore,
pub resource_cache: &'a ResourceCache,
pub gpu_cache: &'a GpuCache,
}
struct TextureAllocator {
@ -977,11 +981,12 @@ impl RenderTarget for ColorRenderTarget {
let prim_metadata = ctx.prim_store.get_metadata(prim_index);
let prim_address = prim_metadata.gpu_location
.as_int(&ctx.gpu_cache);
.as_int(&ctx.resource_cache.gpu_cache);
match prim_metadata.prim_kind {
PrimitiveKind::BoxShadow => {
let instance = SimplePrimitiveInstance::new(prim_address,
let instance = SimplePrimitiveInstance::new(prim_index,
prim_address,
render_tasks.get_task_index(&task.id, pass_index),
RenderTaskIndex(0),
PackedLayerIndex(0),
@ -1005,15 +1010,16 @@ impl RenderTarget for ColorRenderTarget {
self.text_run_textures.colors[0] == textures.colors[0]);
self.text_run_textures = textures;
let instance = SimplePrimitiveInstance::new(prim_address,
let instance = SimplePrimitiveInstance::new(prim_index,
prim_address,
render_tasks.get_task_index(&task.id, pass_index),
RenderTaskIndex(0),
PackedLayerIndex(0),
0); // z is disabled for rendering cache primitives
for glyph_index in 0..text.glyph_instances.len() {
self.text_run_cache_prims.push(instance.build(glyph_index as i32,
text.resource_address.0));
for glyph_index in 0..text.gpu_data_count {
self.text_run_cache_prims.push(instance.build(text.gpu_data_address.0 + glyph_index,
text.resource_address.0 + glyph_index));
}
}
_ => {
@ -1301,6 +1307,7 @@ pub struct PrimitiveInstance {
}
struct SimplePrimitiveInstance {
pub global_prim_index: i32,
// TODO(gw): specific_prim_address is encoded as an i32, since
// some primitives use GPU Cache and some still use
// GPU Store. Once everything is converted to use the
@ -1315,12 +1322,14 @@ struct SimplePrimitiveInstance {
}
impl SimplePrimitiveInstance {
fn new(specific_prim_address: i32,
fn new(prim_index: PrimitiveIndex,
specific_prim_address: i32,
task_index: RenderTaskIndex,
clip_task_index: RenderTaskIndex,
layer_index: PackedLayerIndex,
z_sort_index: i32) -> SimplePrimitiveInstance {
SimplePrimitiveInstance {
global_prim_index: prim_index.0 as i32,
specific_prim_address: specific_prim_address,
task_index: task_index.0 as i32,
clip_task_index: clip_task_index.0 as i32,
@ -1332,6 +1341,7 @@ impl SimplePrimitiveInstance {
fn build(&self, data0: i32, data1: i32) -> PrimitiveInstance {
PrimitiveInstance {
data: [
self.global_prim_index,
self.specific_prim_address,
self.task_index,
self.clip_task_index,
@ -1339,7 +1349,6 @@ impl SimplePrimitiveInstance {
self.z_sort_index,
data0,
data1,
0,
]
}
}
@ -1446,7 +1455,7 @@ pub struct StackingContext {
/// Offset in the parent reference frame to the origin of this stacking
/// context's coordinate system.
pub reference_frame_offset: LayerVector2D,
pub reference_frame_offset: LayerPoint,
/// The `ClipId` of the owning reference frame.
pub reference_frame_id: ClipId,
@ -1475,7 +1484,7 @@ pub struct StackingContext {
impl StackingContext {
pub fn new(pipeline_id: PipelineId,
reference_frame_offset: LayerVector2D,
reference_frame_offset: LayerPoint,
is_page_root: bool,
reference_frame_id: ClipId,
local_bounds: LayerRect,
@ -1603,8 +1612,9 @@ impl CompositeOps {
pub fn will_make_invisible(&self) -> bool {
for op in &self.filters {
if op == &LowLevelFilterOp::Opacity(Au(0)) {
return true;
match op {
&LowLevelFilterOp::Opacity(Au(0)) => return true,
_ => {}
}
}
false
@ -1632,7 +1642,11 @@ pub struct Frame {
pub layer_texture_data: Vec<PackedLayer>,
pub render_task_data: Vec<RenderTaskData>,
pub gpu_data16: Vec<GpuBlock16>,
pub gpu_data32: Vec<GpuBlock32>,
pub gpu_geometry: Vec<PrimitiveGeometry>,
pub gpu_gradient_data: Vec<GradientData>,
pub gpu_split_geometry: Vec<SplitGeometry>,
pub gpu_resource_rects: Vec<TexelRect>,
// List of updates that need to be pushed to the

Просмотреть файл

@ -4,9 +4,9 @@
use std::f32::consts::{FRAC_1_SQRT_2};
use euclid::{Point2D, Rect, Size2D};
use euclid::{TypedRect, TypedPoint2D, TypedSize2D, TypedTransform3D};
use euclid::{TypedRect, TypedPoint2D, TypedSize2D, TypedMatrix4D};
use webrender_traits::{DeviceIntRect, DeviceIntPoint, DeviceIntSize};
use webrender_traits::{LayerRect, WorldPoint3D, LayerToWorldTransform};
use webrender_traits::{LayerRect, WorldPoint4D, LayerPoint4D, LayerToWorldTransform};
use webrender_traits::{BorderRadius, ComplexClipRegion, LayoutRect};
use num_traits::Zero;
@ -20,17 +20,17 @@ pub trait MatrixHelpers<Src, Dst> {
fn preserves_2d_axis_alignment(&self) -> bool;
}
impl<Src, Dst> MatrixHelpers<Src, Dst> for TypedTransform3D<f32, Src, Dst> {
impl<Src, Dst> MatrixHelpers<Src, Dst> for TypedMatrix4D<f32, Src, Dst> {
fn transform_rect(&self, rect: &TypedRect<f32, Src>) -> TypedRect<f32, Dst> {
let top_left = self.transform_point2d(&rect.origin);
let top_right = self.transform_point2d(&rect.top_right());
let bottom_left = self.transform_point2d(&rect.bottom_left());
let bottom_right = self.transform_point2d(&rect.bottom_right());
let top_left = self.transform_point(&rect.origin);
let top_right = self.transform_point(&rect.top_right());
let bottom_left = self.transform_point(&rect.bottom_left());
let bottom_right = self.transform_point(&rect.bottom_right());
TypedRect::from_points(&[top_left, top_right, bottom_right, bottom_left])
}
fn is_identity(&self) -> bool {
*self == TypedTransform3D::identity()
*self == TypedMatrix4D::identity()
}
// A port of the preserves2dAxisAlignment function in Skia.
@ -171,7 +171,7 @@ pub struct TransformedRect {
pub local_rect: LayerRect,
pub bounding_rect: DeviceIntRect,
pub inner_rect: DeviceIntRect,
pub vertices: [WorldPoint3D; 4],
pub vertices: [WorldPoint4D; 4],
pub kind: TransformedRectKind,
}
@ -221,17 +221,30 @@ impl TransformedRect {
TransformedRectKind::Complex => {
*/
let vertices = [
transform.transform_point3d(&rect.origin.to_3d()),
transform.transform_point3d(&rect.bottom_left().to_3d()),
transform.transform_point3d(&rect.bottom_right().to_3d()),
transform.transform_point3d(&rect.top_right().to_3d()),
transform.transform_point4d(&LayerPoint4D::new(rect.origin.x,
rect.origin.y,
0.0,
1.0)),
transform.transform_point4d(&LayerPoint4D::new(rect.bottom_left().x,
rect.bottom_left().y,
0.0,
1.0)),
transform.transform_point4d(&LayerPoint4D::new(rect.bottom_right().x,
rect.bottom_right().y,
0.0,
1.0)),
transform.transform_point4d(&LayerPoint4D::new(rect.top_right().x,
rect.top_right().y,
0.0,
1.0)),
];
let (mut xs, mut ys) = ([0.0; 4], [0.0; 4]);
for (vertex, (x, y)) in vertices.iter().zip(xs.iter_mut().zip(ys.iter_mut())) {
*x = get_normal(vertex.x).unwrap_or(0.0);
*y = get_normal(vertex.y).unwrap_or(0.0);
let inv_w = 1.0 / vertex.w;
*x = get_normal(vertex.x * inv_w).unwrap_or(0.0);
*y = get_normal(vertex.y * inv_w).unwrap_or(0.0);
}
xs.sort_by(|a, b| a.partial_cmp(b).unwrap());

Просмотреть файл

@ -8,7 +8,7 @@ license = "MPL-2.0"
webrender_traits = {path = "../webrender_traits", version = "0.40.0"}
rayon = {version = "0.7", features = ["unstable"]}
thread_profiler = "0.1.1"
euclid = "0.14.4"
euclid = "0.13"
app_units = "0.4"
gleam = "0.4"

Просмотреть файл

@ -13,8 +13,7 @@ use webrender::{ApiRecordingReceiver, BinaryRecorder};
use thread_profiler::register_thread_with_profiler;
use moz2d_renderer::Moz2dImageRenderer;
use app_units::Au;
use euclid::{TypedPoint2D, TypedSize2D, TypedRect, TypedTransform3D, SideOffsets2D};
use euclid::TypedVector2D;
use euclid::{TypedPoint2D, TypedSize2D, TypedRect, TypedMatrix4D, SideOffsets2D};
use rayon;
extern crate webrender_traits;
@ -178,12 +177,6 @@ impl<U> Into<TypedPoint2D<f32, U>> for WrPoint {
}
}
impl<U> Into<TypedVector2D<f32, U>> for WrPoint {
fn into(self) -> TypedVector2D<f32, U> {
TypedVector2D::new(self.x, self.y)
}
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct WrSize {
@ -239,44 +232,44 @@ pub struct WrMatrix {
values: [f32; 16],
}
impl<'a, U, E> Into<TypedTransform3D<f32, U, E>> for &'a WrMatrix {
fn into(self) -> TypedTransform3D<f32, U, E> {
TypedTransform3D::row_major(self.values[0],
self.values[1],
self.values[2],
self.values[3],
self.values[4],
self.values[5],
self.values[6],
self.values[7],
self.values[8],
self.values[9],
self.values[10],
self.values[11],
self.values[12],
self.values[13],
self.values[14],
self.values[15])
impl<'a, U, E> Into<TypedMatrix4D<f32, U, E>> for &'a WrMatrix {
fn into(self) -> TypedMatrix4D<f32, U, E> {
TypedMatrix4D::row_major(self.values[0],
self.values[1],
self.values[2],
self.values[3],
self.values[4],
self.values[5],
self.values[6],
self.values[7],
self.values[8],
self.values[9],
self.values[10],
self.values[11],
self.values[12],
self.values[13],
self.values[14],
self.values[15])
}
}
impl<U, E> Into<TypedTransform3D<f32, U, E>> for WrMatrix {
fn into(self) -> TypedTransform3D<f32, U, E> {
TypedTransform3D::row_major(self.values[0],
self.values[1],
self.values[2],
self.values[3],
self.values[4],
self.values[5],
self.values[6],
self.values[7],
self.values[8],
self.values[9],
self.values[10],
self.values[11],
self.values[12],
self.values[13],
self.values[14],
self.values[15])
impl<U, E> Into<TypedMatrix4D<f32, U, E>> for WrMatrix {
fn into(self) -> TypedMatrix4D<f32, U, E> {
TypedMatrix4D::row_major(self.values[0],
self.values[1],
self.values[2],
self.values[3],
self.values[4],
self.values[5],
self.values[6],
self.values[7],
self.values[8],
self.values[9],
self.values[10],
self.values[11],
self.values[12],
self.values[13],
self.values[14],
self.values[15])
}
}

Просмотреть файл

@ -32,10 +32,10 @@ impl BlobImageRenderer for Moz2dImageRenderer {
}
fn request(&mut self,
_resources: &BlobImageResources,
request: BlobImageRequest,
descriptor: &BlobImageDescriptor,
_dirty_rect: Option<DeviceUintRect>) {
_dirty_rect: Option<DeviceUintRect>,
_images: &ImageStore) {
debug_assert!(!self.rendered_images.contains_key(&request));
// TODO: implement tiling.
assert!(request.tile.is_none());
@ -105,8 +105,6 @@ impl BlobImageRenderer for Moz2dImageRenderer {
// If we break out of the loop above it means the channel closed unexpectedly.
Err(BlobImageError::Other("Channel closed".into()))
}
fn delete_font(&mut self, _font: FontKey) {
}
}
impl Moz2dImageRenderer {

Просмотреть файл

@ -14,11 +14,11 @@ webgl = ["offscreen_gl_context"]
app_units = "0.4"
bincode = "1.0.0-alpha2"
byteorder = "1.0"
euclid = "0.14.4"
euclid = "0.13"
gleam = "0.4.5"
heapsize = ">= 0.3.6, < 0.5"
ipc-channel = {version = "0.7.2", optional = true}
offscreen_gl_context = {version = "0.9", features = ["serde"], optional = true}
offscreen_gl_context = {version = "0.8", features = ["serde"], optional = true}
serde = "0.9"
serde_derive = "0.9"
time = "0.1"

Просмотреть файл

@ -10,7 +10,7 @@ use std::fmt;
use std::marker::PhantomData;
use {BuiltDisplayList, BuiltDisplayListDescriptor, ClipId, ColorF, DeviceIntPoint, DeviceIntSize};
use {DeviceUintRect, DeviceUintSize, FontKey, GlyphDimensions, GlyphKey};
use {ImageData, ImageDescriptor, ImageKey, LayoutPoint, LayoutVector2D, LayoutSize, LayoutTransform};
use {ImageData, ImageDescriptor, ImageKey, LayoutPoint, LayoutSize, LayoutTransform};
use {NativeFontHandle, WorldPoint};
#[cfg(feature = "webgl")]
use {WebGLCommand, WebGLContextId};
@ -461,13 +461,13 @@ pub enum ScrollEventPhase {
#[derive(Clone, Deserialize, Serialize)]
pub struct ScrollLayerState {
pub id: ClipId,
pub scroll_offset: LayoutVector2D,
pub scroll_offset: LayoutPoint,
}
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub enum ScrollLocation {
/// Scroll by a certain amount.
Delta(LayoutVector2D),
Delta(LayoutPoint),
/// Scroll to very top of element.
Start,
/// Scroll to very bottom of element.

Просмотреть файл

@ -5,7 +5,7 @@
use app_units::Au;
use euclid::SideOffsets2D;
use {ColorF, FontKey, ImageKey, ItemRange, PipelineId, WebGLContextId};
use {LayoutPoint, LayoutRect, LayoutSize, LayoutTransform, LayoutVector2D};
use {LayoutPoint, LayoutRect, LayoutSize, LayoutTransform};
use {PropertyBinding};
// NOTE: some of these structs have an "IMPLICIT" comment.
@ -207,7 +207,7 @@ pub enum BoxShadowClipMode {
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
pub struct BoxShadowDisplayItem {
pub box_bounds: LayoutRect,
pub offset: LayoutVector2D,
pub offset: LayoutPoint,
pub color: ColorF,
pub blur_radius: f32,
pub spread_radius: f32,
@ -325,23 +325,6 @@ pub enum FilterOp {
Sepia(f32),
}
impl FilterOp {
pub fn is_noop(&self) -> bool {
match *self {
FilterOp::Blur(length) if length == Au(0) => true,
FilterOp::Brightness(amount) if amount == 1.0 => true,
FilterOp::Contrast(amount) if amount == 1.0 => true,
FilterOp::Grayscale(amount) if amount == 0.0 => true,
FilterOp::HueRotate(amount) if amount == 0.0 => true,
FilterOp::Invert(amount) if amount == 0.0 => true,
FilterOp::Opacity(amount) if amount == PropertyBinding::Value(1.0) => true,
FilterOp::Saturate(amount) if amount == 1.0 => true,
FilterOp::Sepia(amount) if amount == 0.0 => true,
_ => false,
}
}
}
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
pub struct IframeDisplayItem {
pub pipeline_id: PipelineId,
@ -583,7 +566,7 @@ impl ComplexClipRegion {
pub enum ClipId {
Clip(u64, PipelineId),
ClipExternalId(u64, PipelineId),
DynamicallyAddedNode(u64, PipelineId),
ReferenceFrame(u64, PipelineId),
}
impl ClipId {
@ -592,7 +575,7 @@ impl ClipId {
}
pub fn root_reference_frame(pipeline_id: PipelineId) -> ClipId {
ClipId::DynamicallyAddedNode(0, pipeline_id)
ClipId::ReferenceFrame(0, pipeline_id)
}
pub fn new(id: u64, pipeline_id: PipelineId) -> ClipId {
@ -609,7 +592,14 @@ impl ClipId {
match *self {
ClipId::Clip(_, pipeline_id) |
ClipId::ClipExternalId(_, pipeline_id) |
ClipId::DynamicallyAddedNode(_, pipeline_id) => pipeline_id,
ClipId::ReferenceFrame(_, pipeline_id) => pipeline_id,
}
}
pub fn is_reference_frame(&self) -> bool {
match *self {
ClipId::ReferenceFrame(..) => true,
_ => false,
}
}

Просмотреть файл

@ -15,7 +15,7 @@ use {ImageRendering, LayoutPoint, LayoutRect, LayoutSize, LayoutTransform, MixBl
use {PipelineId, PropertyBinding, PushStackingContextDisplayItem, RadialGradient};
use {RadialGradientDisplayItem, RectangleDisplayItem, ScrollPolicy, SpecificDisplayItem};
use {StackingContext, TextDisplayItem, TransformStyle, WebGLContextId, WebGLDisplayItem};
use {YuvColorSpace, YuvData, YuvImageDisplayItem, LayoutVector2D};
use {YuvColorSpace, YuvData, YuvImageDisplayItem};
use std::marker::PhantomData;
#[repr(C)]
@ -773,7 +773,7 @@ impl DisplayListBuilder {
rect: LayoutRect,
_token: ClipRegionToken,
box_bounds: LayoutRect,
offset: LayoutVector2D,
offset: LayoutPoint,
color: ColorF,
blur_radius: f32,
spread_radius: f32,

Просмотреть файл

@ -4,7 +4,6 @@
use app_units::Au;
use {ColorU, ColorF, LayoutPoint};
use std::sync::Arc;
#[cfg(target_os = "macos")] use core_foundation::string::CFString;
#[cfg(target_os = "macos")] use core_graphics::font::CGFont;
@ -64,13 +63,6 @@ impl FontKey {
}
}
#[derive(Clone)]
pub enum FontTemplate {
Raw(Arc<Vec<u8>>, u32),
Native(NativeFontHandle),
}
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Ord, PartialOrd)]
pub enum FontRenderMode {
Mono,

Просмотреть файл

@ -5,7 +5,6 @@
use std::sync::Arc;
use {DeviceUintRect, DevicePoint};
use {TileOffset, TileSize};
use font::{FontKey, FontTemplate};
#[repr(C)]
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
@ -136,11 +135,6 @@ impl ImageData {
}
}
pub trait BlobImageResources {
fn get_font_data(&self, key: FontKey) -> &FontTemplate;
fn get_image(&self, key: ImageKey) -> Option<(&ImageData, &ImageDescriptor)>;
}
pub trait BlobImageRenderer: Send {
fn add(&mut self, key: ImageKey, data: BlobImageData, tiling: Option<TileSize>);
@ -149,14 +143,12 @@ pub trait BlobImageRenderer: Send {
fn delete(&mut self, key: ImageKey);
fn request(&mut self,
services: &BlobImageResources,
key: BlobImageRequest,
descriptor: &BlobImageDescriptor,
dirty_rect: Option<DeviceUintRect>);
dirty_rect: Option<DeviceUintRect>,
images: &ImageStore);
fn resolve(&mut self, key: BlobImageRequest) -> BlobImageResult;
fn delete_font(&mut self, key: FontKey);
}
pub type BlobImageData = Vec<u8>;
@ -191,3 +183,7 @@ pub struct BlobImageRequest {
pub key: ImageKey,
pub tile: Option<TileOffset>,
}
pub trait ImageStore {
fn get_image(&self, key: ImageKey) -> Option<(&ImageData, &ImageDescriptor)>;
}

Просмотреть файл

@ -12,8 +12,8 @@
//! The terms "layer" and "stacking context" can be used interchangeably
//! in the context of coordinate systems.
use euclid::{Length, TypedTransform3D, TypedRect, TypedSize2D};
use euclid::{TypedPoint2D, TypedPoint3D, TypedVector2D, TypedVector3D};
use euclid::{Length, TypedMatrix4D, TypedRect, TypedSize2D};
use euclid::{TypedPoint2D, TypedPoint3D, TypedPoint4D};
/// Geometry in the coordinate system of the render target (screen or intermediate
/// surface) in physical pixels.
@ -31,7 +31,6 @@ pub type DeviceUintSize = TypedSize2D<u32, DevicePixel>;
pub type DeviceRect = TypedRect<f32, DevicePixel>;
pub type DevicePoint = TypedPoint2D<f32, DevicePixel>;
pub type DeviceVector2D = TypedVector2D<f32, DevicePixel>;
pub type DeviceSize = TypedSize2D<f32, DevicePixel>;
/// Geometry in a stacking context's local coordinate space (logical pixels).
@ -41,8 +40,6 @@ pub type LayoutPixel = LayerPixel;
pub type LayoutRect = LayerRect;
pub type LayoutPoint = LayerPoint;
pub type LayoutVector2D = LayerVector2D;
pub type LayoutVector3D = LayerVector3D;
pub type LayoutSize = LayerSize;
/// Geometry in a layer's local coordinate space (logical pixels).
@ -51,10 +48,8 @@ pub struct LayerPixel;
pub type LayerRect = TypedRect<f32, LayerPixel>;
pub type LayerPoint = TypedPoint2D<f32, LayerPixel>;
pub type LayerPoint3D = TypedPoint3D<f32, LayerPixel>;
pub type LayerVector2D = TypedVector2D<f32, LayerPixel>;
pub type LayerVector3D = TypedVector3D<f32, LayerPixel>;
pub type LayerSize = TypedSize2D<f32, LayerPixel>;
pub type LayerPoint4D = TypedPoint4D<f32, LayerPixel>;
/// Geometry in a layer's scrollable parent coordinate space (logical pixels).
///
@ -68,7 +63,6 @@ pub struct ScrollLayerPixel;
pub type ScrollLayerRect = TypedRect<f32, ScrollLayerPixel>;
pub type ScrollLayerPoint = TypedPoint2D<f32, ScrollLayerPixel>;
pub type ScrollLayerVector2D = TypedVector2D<f32, ScrollLayerPixel>;
pub type ScrollLayerSize = TypedSize2D<f32, ScrollLayerPixel>;
/// Geometry in the document's coordinate space (logical pixels).
@ -79,21 +73,20 @@ pub type WorldRect = TypedRect<f32, WorldPixel>;
pub type WorldPoint = TypedPoint2D<f32, WorldPixel>;
pub type WorldSize = TypedSize2D<f32, WorldPixel>;
pub type WorldPoint3D = TypedPoint3D<f32, WorldPixel>;
pub type WorldVector2D = TypedVector2D<f32, WorldPixel>;
pub type WorldVector3D = TypedVector3D<f32, WorldPixel>;
pub type WorldPoint4D = TypedPoint4D<f32, WorldPixel>;
/// Offset in number of tiles.
#[derive(Hash, Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub struct Tiles;
pub type TileOffset = TypedPoint2D<u16, Tiles>;
pub type LayoutTransform = TypedTransform3D<f32, LayoutPixel, LayoutPixel>;
pub type LayerTransform = TypedTransform3D<f32, LayerPixel, LayerPixel>;
pub type LayerToScrollTransform = TypedTransform3D<f32, LayerPixel, ScrollLayerPixel>;
pub type ScrollToLayerTransform = TypedTransform3D<f32, ScrollLayerPixel, LayerPixel>;
pub type LayerToWorldTransform = TypedTransform3D<f32, LayerPixel, WorldPixel>;
pub type WorldToLayerTransform = TypedTransform3D<f32, WorldPixel, LayerPixel>;
pub type ScrollToWorldTransform = TypedTransform3D<f32, ScrollLayerPixel, WorldPixel>;
pub type LayoutTransform = TypedMatrix4D<f32, LayoutPixel, LayoutPixel>;
pub type LayerTransform = TypedMatrix4D<f32, LayerPixel, LayerPixel>;
pub type LayerToScrollTransform = TypedMatrix4D<f32, LayerPixel, ScrollLayerPixel>;
pub type ScrollToLayerTransform = TypedMatrix4D<f32, ScrollLayerPixel, LayerPixel>;
pub type LayerToWorldTransform = TypedMatrix4D<f32, LayerPixel, WorldPixel>;
pub type WorldToLayerTransform = TypedMatrix4D<f32, WorldPixel, LayerPixel>;
pub type ScrollToWorldTransform = TypedMatrix4D<f32, ScrollLayerPixel, WorldPixel>;
pub fn device_length(value: f32, device_pixel_ratio: f32) -> DeviceIntLength {
@ -104,7 +97,3 @@ pub fn as_scroll_parent_rect(rect: &LayerRect) -> ScrollLayerRect {
ScrollLayerRect::from_untyped(&rect.to_untyped())
}
pub fn as_scroll_parent_vector(vector: &LayerVector2D) -> ScrollLayerVector2D {
ScrollLayerVector2D::from_untyped(&vector.to_untyped())
}

Просмотреть файл

@ -1 +0,0 @@
{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".gitignore":"118514fd9c4958df0d25584cda4917186c46011569f55ef350530c1ad3fbdb48",".travis.yml":"13d3e5a7bf83b04c8e8cfa14f0297bd8366d68391d977dd547f64707dffc275a","COPYRIGHT":"ec82b96487e9e778ee610c7ab245162464782cfa1f555c2299333f8dbe5c036a","Cargo.toml":"c91c98dc9510ef29a7ce0d7c78294f15cb139c9afecca38e5fda56b0a6984954","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3","README.md":"625bec69c76ce5423fdd05cfe46922b2680ec517f97c5854ce34798d1d8a9541","src/approxeq.rs":"6cf810ad389c73a27141a7a67454ed12d4b01c3c16605b9a7414b389bc0615dd","src/length.rs":"d7c6369f2fe2a17c845b57749bd48c471159f0571a7314d3bf90737d53f697d3","src/lib.rs":"e2e621f05304278d020429d0349acf7a4e7c7a9a72bd23fc0e55680267472ee9","src/macros.rs":"b63dabdb52df84ea170dc1dab5fe8d7a78c054562d1566bab416124708d2d7af","src/matrix2d.rs":"2361338f59813adf4eebaab76e4dd82be0fbfb9ff2461da8dd9ac9d43583b322","src/matrix4d.rs":"b8547bed6108b037192021c97169c00ad456120b849e9b7ac7bec40363edaec1","src/num.rs":"749b201289fc6663199160a2f9204e17925fd3053f8ab7779e7bfb377ad06227","src/point.rs":"dbf12a3ad35dc2502b7f2637856d8ee40f5a96e37ed00f3ee3272bf5752c060c","src/rect.rs":"0a255046dd11a6093d9a77e327e1df31802808536b4d87e4e3b80ff6b208de0f","src/scale_factor.rs":"df6dbd1f0f9f63210b92809f84a383dad982a74f09789cf22c7d8f9b62199d39","src/side_offsets.rs":"f85526a421ffda63ff01a3478d4162c8717eef68e942acfa2fd9a1adee02ebb2","src/size.rs":"ae1b647e300600b50a21dba8c1d915801782ebae82baeb5e49017e6d68a49b28","src/trig.rs":"ef290927af252ca90a29ba9f17158b591ed591604e66cb9df045dd47b9cfdca5"},"package":"6083f113c422ff9cd855a1cf6cc8ec0903606c0eb43a0c6a0ced3bdc9731e4c1"}

0
third_party/rust/euclid-0.13.0/.cargo-ok поставляемый
Просмотреть файл

2
third_party/rust/euclid-0.13.0/.gitignore поставляемый
Просмотреть файл

@ -1,2 +0,0 @@
Cargo.lock
/target/

19
third_party/rust/euclid-0.13.0/.travis.yml поставляемый
Просмотреть файл

@ -1,19 +0,0 @@
language: rust
notifications:
webhooks: http://build.servo.org:54856/travis
matrix:
include:
- rust: stable
env: FEATURES=""
- rust: beta
env: FEATURES=""
- rust: nightly
env: FEATURES=""
- rust: nightly
env: FEATURES="unstable"
script:
- cargo build --verbose --features "$FEATURES"
- cargo test --verbose --features "$FEATURES"

5
third_party/rust/euclid-0.13.0/COPYRIGHT поставляемый
Просмотреть файл

@ -1,5 +0,0 @@
Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
<LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
option. All files in the project carrying such notice may not be
copied, modified, or distributed except according to those terms.

24
third_party/rust/euclid-0.13.0/Cargo.toml поставляемый
Просмотреть файл

@ -1,24 +0,0 @@
[package]
name = "euclid"
version = "0.13.0"
authors = ["The Servo Project Developers"]
description = "Geometry primitives"
documentation = "https://docs.rs/euclid/"
repository = "https://github.com/servo/euclid"
keywords = ["matrix", "vector", "linear-algebra", "geometry"]
categories = ["science"]
license = "MIT / Apache-2.0"
[features]
unstable = []
[dependencies]
heapsize = "0.4"
rustc-serialize = "0.3.2"
num-traits = {version = "0.1.32", default-features = false}
log = "0.3.1"
serde = "0.9"
[dev-dependencies]
rand = "0.3.7"
serde_test = "0.9"

201
third_party/rust/euclid-0.13.0/LICENSE-APACHE поставляемый
Просмотреть файл

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

25
third_party/rust/euclid-0.13.0/LICENSE-MIT поставляемый
Просмотреть файл

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

8
third_party/rust/euclid-0.13.0/README.md поставляемый
Просмотреть файл

@ -1,8 +0,0 @@
# euclid
This is a small library for geometric types with a focus on 2d graphics and
layout.
* [Documentation](https://docs.rs/euclid/)
* [Release notes](https://github.com/servo/euclid/releases)
* [crates.io](https://crates.io/crates/euclid)

Просмотреть файл

@ -1,36 +0,0 @@
// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
/// Trait for testing approximate equality
pub trait ApproxEq<Eps> {
fn approx_epsilon() -> Eps;
fn approx_eq(&self, other: &Self) -> bool;
fn approx_eq_eps(&self, other: &Self, approx_epsilon: &Eps) -> bool;
}
macro_rules! approx_eq {
($ty:ty, $eps:expr) => (
impl ApproxEq<$ty> for $ty {
#[inline]
fn approx_epsilon() -> $ty { $eps }
#[inline]
fn approx_eq(&self, other: &$ty) -> bool {
self.approx_eq_eps(other, &$eps)
}
#[inline]
fn approx_eq_eps(&self, other: &$ty, approx_epsilon: &$ty) -> bool {
(*self - *other).abs() < *approx_epsilon
}
}
)
}
approx_eq!(f32, 1.0e-6);
approx_eq!(f64, 1.0e-6);

449
third_party/rust/euclid-0.13.0/src/length.rs поставляемый
Просмотреть файл

@ -1,449 +0,0 @@
// Copyright 2014 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! A one-dimensional length, tagged with its units.
use scale_factor::ScaleFactor;
use num::Zero;
use heapsize::HeapSizeOf;
use num_traits::{NumCast, Saturating};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::cmp::Ordering;
use std::ops::{Add, Sub, Mul, Div, Neg};
use std::ops::{AddAssign, SubAssign};
use std::marker::PhantomData;
use std::fmt;
/// A one-dimensional distance, with value represented by `T` and unit of measurement `Unit`.
///
/// `T` can be any numeric type, for example a primitive type like `u64` or `f32`.
///
/// `Unit` is not used in the representation of a `Length` value. It is used only at compile time
/// to ensure that a `Length` stored with one unit is converted explicitly before being used in an
/// expression that requires a different unit. It may be a type without values, such as an empty
/// enum.
///
/// You can multiply a `Length` by a `scale_factor::ScaleFactor` to convert it from one unit to
/// another. See the `ScaleFactor` docs for an example.
// Uncomment the derive, and remove the macro call, once heapsize gets
// PhantomData<T> support.
#[repr(C)]
#[derive(RustcDecodable, RustcEncodable)]
pub struct Length<T, Unit>(pub T, PhantomData<Unit>);
impl<T: Clone, Unit> Clone for Length<T, Unit> {
fn clone(&self) -> Self {
Length(self.0.clone(), PhantomData)
}
}
impl<T: Copy, Unit> Copy for Length<T, Unit> {}
impl<Unit, T: HeapSizeOf> HeapSizeOf for Length<T, Unit> {
fn heap_size_of_children(&self) -> usize {
self.0.heap_size_of_children()
}
}
impl<Unit, T> Deserialize for Length<T, Unit> where T: Deserialize {
fn deserialize<D>(deserializer: D) -> Result<Length<T, Unit>,D::Error>
where D: Deserializer {
Ok(Length(try!(Deserialize::deserialize(deserializer)), PhantomData))
}
}
impl<T, Unit> Serialize for Length<T, Unit> where T: Serialize {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
self.0.serialize(serializer)
}
}
impl<T, Unit> Length<T, Unit> {
pub fn new(x: T) -> Length<T, Unit> {
Length(x, PhantomData)
}
}
impl<Unit, T: Clone> Length<T, Unit> {
pub fn get(&self) -> T {
self.0.clone()
}
}
impl<T: fmt::Debug + Clone, U> fmt::Debug for Length<T, U> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.get().fmt(f)
}
}
impl<T: fmt::Display + Clone, U> fmt::Display for Length<T, U> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.get().fmt(f)
}
}
// length + length
impl<U, T: Clone + Add<T, Output=T>> Add for Length<T, U> {
type Output = Length<T, U>;
fn add(self, other: Length<T, U>) -> Length<T, U> {
Length::new(self.get() + other.get())
}
}
// length += length
impl<U, T: Clone + AddAssign<T>> AddAssign for Length<T, U> {
fn add_assign(&mut self, other: Length<T, U>) {
self.0 += other.get();
}
}
// length - length
impl<U, T: Clone + Sub<T, Output=T>> Sub<Length<T, U>> for Length<T, U> {
type Output = Length<T, U>;
fn sub(self, other: Length<T, U>) -> <Self as Sub>::Output {
Length::new(self.get() - other.get())
}
}
// length -= length
impl<U, T: Clone + SubAssign<T>> SubAssign for Length<T, U> {
fn sub_assign(&mut self, other: Length<T, U>) {
self.0 -= other.get();
}
}
// Saturating length + length and length - length.
impl<U, T: Clone + Saturating> Saturating for Length<T, U> {
fn saturating_add(self, other: Length<T, U>) -> Length<T, U> {
Length::new(self.get().saturating_add(other.get()))
}
fn saturating_sub(self, other: Length<T, U>) -> Length<T, U> {
Length::new(self.get().saturating_sub(other.get()))
}
}
// length / length
impl<Src, Dst, T: Clone + Div<T, Output=T>> Div<Length<T, Src>> for Length<T, Dst> {
type Output = ScaleFactor<T, Src, Dst>;
#[inline]
fn div(self, other: Length<T, Src>) -> ScaleFactor<T, Src, Dst> {
ScaleFactor::new(self.get() / other.get())
}
}
// length * scaleFactor
impl<Src, Dst, T: Clone + Mul<T, Output=T>> Mul<ScaleFactor<T, Src, Dst>> for Length<T, Src> {
type Output = Length<T, Dst>;
#[inline]
fn mul(self, scale: ScaleFactor<T, Src, Dst>) -> Length<T, Dst> {
Length::new(self.get() * scale.get())
}
}
// length / scaleFactor
impl<Src, Dst, T: Clone + Div<T, Output=T>> Div<ScaleFactor<T, Src, Dst>> for Length<T, Dst> {
type Output = Length<T, Src>;
#[inline]
fn div(self, scale: ScaleFactor<T, Src, Dst>) -> Length<T, Src> {
Length::new(self.get() / scale.get())
}
}
// -length
impl <U, T:Clone + Neg<Output=T>> Neg for Length<T, U> {
type Output = Length<T, U>;
#[inline]
fn neg(self) -> Length<T, U> {
Length::new(-self.get())
}
}
impl<Unit, T0: NumCast + Clone> Length<T0, Unit> {
/// Cast from one numeric representation to another, preserving the units.
pub fn cast<T1: NumCast + Clone>(&self) -> Option<Length<T1, Unit>> {
NumCast::from(self.get()).map(Length::new)
}
}
impl<Unit, T: Clone + PartialEq> PartialEq for Length<T, Unit> {
fn eq(&self, other: &Length<T, Unit>) -> bool { self.get().eq(&other.get()) }
}
impl<Unit, T: Clone + PartialOrd> PartialOrd for Length<T, Unit> {
fn partial_cmp(&self, other: &Length<T, Unit>) -> Option<Ordering> {
self.get().partial_cmp(&other.get())
}
}
impl<Unit, T: Clone + Eq> Eq for Length<T, Unit> {}
impl<Unit, T: Clone + Ord> Ord for Length<T, Unit> {
fn cmp(&self, other: &Length<T, Unit>) -> Ordering { self.get().cmp(&other.get()) }
}
impl<Unit, T: Zero> Zero for Length<T, Unit> {
fn zero() -> Length<T, Unit> {
Length::new(Zero::zero())
}
}
#[cfg(test)]
mod tests {
use super::Length;
use num::Zero;
use heapsize::HeapSizeOf;
use num_traits::Saturating;
use scale_factor::ScaleFactor;
use std::f32::INFINITY;
extern crate serde_test;
use self::serde_test::Token;
use self::serde_test::assert_tokens;
enum Inch {}
enum Mm {}
enum Cm {}
enum Second {}
#[test]
fn test_clone() {
// A cloned Length is a separate length with the state matching the
// original Length at the point it was cloned.
let mut variable_length: Length<f32, Inch> = Length::new(12.0);
let one_foot = variable_length.clone();
variable_length.0 = 24.0;
assert_eq!(one_foot.get(), 12.0);
assert_eq!(variable_length.get(), 24.0);
}
#[test]
fn test_heapsizeof_builtins() {
// Heap size of built-ins is zero by default.
let one_foot: Length<f32, Inch> = Length::new(12.0);
let heap_size_length_f32 = one_foot.heap_size_of_children();
assert_eq!(heap_size_length_f32, 0);
}
#[test]
fn test_heapsizeof_length_vector() {
// Heap size of any Length is just the heap size of the length value.
for n in 0..5 {
let length: Length<Vec<f32>, Inch> = Length::new(Vec::with_capacity(n));
assert_eq!(length.heap_size_of_children(), length.0.heap_size_of_children());
}
}
#[test]
fn test_length_serde() {
let one_cm: Length<f32, Mm> = Length::new(10.0);
assert_tokens(&one_cm, &[Token::F32(10.0)]);
}
#[test]
fn test_get_clones_length_value() {
// Calling get returns a clone of the Length's value.
// To test this, we need something clone-able - hence a vector.
let mut length: Length<Vec<i32>, Inch> = Length::new(vec![1, 2, 3]);
let value = length.get();
length.0.push(4);
assert_eq!(value, vec![1, 2, 3]);
assert_eq!(length.get(), vec![1, 2, 3, 4]);
}
#[test]
fn test_fmt_debug() {
// Debug and display format the value only.
let one_cm: Length<f32, Mm> = Length::new(10.0);
let result = format!("{:?}", one_cm);
assert_eq!(result, "10");
}
#[test]
fn test_fmt_display() {
// Debug and display format the value only.
let one_cm: Length<f32, Mm> = Length::new(10.0);
let result = format!("{}", one_cm);
assert_eq!(result, "10");
}
#[test]
fn test_add() {
let length1: Length<u8, Mm> = Length::new(250);
let length2: Length<u8, Mm> = Length::new(5);
let result = length1 + length2;
assert_eq!(result.get(), 255);
}
#[test]
fn test_addassign() {
let one_cm: Length<f32, Mm> = Length::new(10.0);
let mut measurement: Length<f32, Mm> = Length::new(5.0);
measurement += one_cm;
assert_eq!(measurement.get(), 15.0);
}
#[test]
fn test_sub() {
let length1: Length<u8, Mm> = Length::new(250);
let length2: Length<u8, Mm> = Length::new(5);
let result = length1 - length2;
assert_eq!(result.get(), 245);
}
#[test]
fn test_subassign() {
let one_cm: Length<f32, Mm> = Length::new(10.0);
let mut measurement: Length<f32, Mm> = Length::new(5.0);
measurement -= one_cm;
assert_eq!(measurement.get(), -5.0);
}
#[test]
fn test_saturating_add() {
let length1: Length<u8, Mm> = Length::new(250);
let length2: Length<u8, Mm> = Length::new(6);
let result = length1.saturating_add(length2);
assert_eq!(result.get(), 255);
}
#[test]
fn test_saturating_sub() {
let length1: Length<u8, Mm> = Length::new(5);
let length2: Length<u8, Mm> = Length::new(10);
let result = length1.saturating_sub(length2);
assert_eq!(result.get(), 0);
}
#[test]
fn test_division_by_length() {
// Division results in a ScaleFactor from denominator units
// to numerator units.
let length: Length<f32, Cm> = Length::new(5.0);
let duration: Length<f32, Second> = Length::new(10.0);
let result = length / duration;
let expected: ScaleFactor<f32, Second, Cm> = ScaleFactor::new(0.5);
assert_eq!(result, expected);
}
#[test]
fn test_multiplication() {
let length_mm: Length<f32, Mm> = Length::new(10.0);
let cm_per_mm: ScaleFactor<f32, Mm, Cm> = ScaleFactor::new(0.1);
let result = length_mm * cm_per_mm;
let expected: Length<f32, Cm> = Length::new(1.0);
assert_eq!(result, expected);
}
#[test]
fn test_division_by_scalefactor() {
let length: Length<f32, Cm> = Length::new(5.0);
let cm_per_second: ScaleFactor<f32, Second, Cm> = ScaleFactor::new(10.0);
let result = length / cm_per_second;
let expected: Length<f32, Second> = Length::new(0.5);
assert_eq!(result, expected);
}
#[test]
fn test_negation() {
let length: Length<f32, Cm> = Length::new(5.0);
let result = -length;
let expected: Length<f32, Cm> = Length::new(-5.0);
assert_eq!(result, expected);
}
#[test]
fn test_cast() {
let length_as_i32: Length<i32, Cm> = Length::new(5);
let result: Length<f32, Cm> = length_as_i32.cast().unwrap();
let length_as_f32: Length<f32, Cm> = Length::new(5.0);
assert_eq!(result, length_as_f32);
}
#[test]
fn test_equality() {
let length_5_point_0: Length<f32, Cm> = Length::new(5.0);
let length_5_point_1: Length<f32, Cm> = Length::new(5.1);
let length_0_point_1: Length<f32, Cm> = Length::new(0.1);
assert!(length_5_point_0 == length_5_point_1 - length_0_point_1);
assert!(length_5_point_0 != length_5_point_1);
}
#[test]
fn test_order() {
let length_5_point_0: Length<f32, Cm> = Length::new(5.0);
let length_5_point_1: Length<f32, Cm> = Length::new(5.1);
let length_0_point_1: Length<f32, Cm> = Length::new(0.1);
assert!(length_5_point_0 < length_5_point_1);
assert!(length_5_point_0 <= length_5_point_1);
assert!(length_5_point_0 <= length_5_point_1 - length_0_point_1);
assert!(length_5_point_1 > length_5_point_0);
assert!(length_5_point_1 >= length_5_point_0);
assert!(length_5_point_0 >= length_5_point_1 - length_0_point_1);
}
#[test]
fn test_zero_add() {
type LengthCm = Length<f32, Cm>;
let length: LengthCm = Length::new(5.0);
let result = length - LengthCm::zero();
assert_eq!(result, length);
}
#[test]
fn test_zero_division() {
type LengthCm = Length<f32, Cm>;
let length: LengthCm = Length::new(5.0);
let length_zero: LengthCm = Length::zero();
let result = length / length_zero;
let expected: ScaleFactor<f32, Cm, Cm> = ScaleFactor::new(INFINITY);
assert_eq!(result, expected);
}
}

113
third_party/rust/euclid-0.13.0/src/lib.rs поставляемый
Просмотреть файл

@ -1,113 +0,0 @@
// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![cfg_attr(feature = "unstable", feature(asm, repr_simd, test))]
//! A collection of strongly typed math tools for computer graphics with an inclination
//! towards 2d graphics and layout.
//!
//! All types are generic over the scalar type of their component (`f32`, `i32`, etc.),
//! and tagged with a generic Unit parameter which is useful to prevent mixing
//! values from different spaces. For example it should not be legal to translate
//! a screen-space position by a world-space vector and this can be expressed using
//! the generic Unit parameter.
//!
//! This unit system is not mandatory and all Typed* structures have an alias
//! with the default unit: `UnknownUnit`.
//! for example ```Point2D<T>``` is equivalent to ```TypedPoint2D<T, UnknownUnit>```.
//! Client code typically creates a set of aliases for each type and doesn't need
//! to deal with the specifics of typed units further. For example:
//!
//! All euclid types are marked `#[repr(C)]` in order to facilitate exposing them to
//! foreign function interfaces (provided the underlying scalar type is also `repr(C)`).
//!
//! ```rust
//! use euclid::*;
//! pub struct ScreenSpace;
//! pub type ScreenPoint = TypedPoint2D<f32, ScreenSpace>;
//! pub type ScreenSize = TypedSize2D<f32, ScreenSpace>;
//! pub struct WorldSpace;
//! pub type WorldPoint = TypedPoint3D<f32, WorldSpace>;
//! pub type ProjectionMatrix = TypedMatrix4D<f32, WorldSpace, ScreenSpace>;
//! // etc...
//! ```
//!
//! Components are accessed in their scalar form by default for convenience, and most
//! types additionally implement strongly typed accessors which return typed ```Length``` wrappers.
//! For example:
//!
//! ```rust
//! # use euclid::*;
//! # pub struct WorldSpace;
//! # pub type WorldPoint = TypedPoint3D<f32, WorldSpace>;
//! let p = WorldPoint::new(0.0, 1.0, 1.0);
//! // p.x is an f32.
//! println!("p.x = {:?} ", p.x);
//! // p.x is a Length<f32, WorldSpace>.
//! println!("p.x_typed() = {:?} ", p.x_typed());
//! // Length::get returns the scalar value (f32).
//! assert_eq!(p.x, p.x_typed().get());
//! ```
extern crate heapsize;
#[cfg_attr(test, macro_use)]
extern crate log;
extern crate rustc_serialize;
extern crate serde;
#[cfg(test)]
extern crate rand;
#[cfg(feature = "unstable")]
extern crate test;
extern crate num_traits;
pub use length::Length;
pub use scale_factor::ScaleFactor;
pub use matrix2d::{Matrix2D, TypedMatrix2D};
pub use matrix4d::{Matrix4D, TypedMatrix4D};
pub use point::{
Point2D, TypedPoint2D,
Point3D, TypedPoint3D,
Point4D, TypedPoint4D,
};
pub use rect::{Rect, TypedRect};
pub use side_offsets::{SideOffsets2D, TypedSideOffsets2D};
#[cfg(feature = "unstable")] pub use side_offsets::SideOffsets2DSimdI32;
pub use size::{Size2D, TypedSize2D};
pub mod approxeq;
pub mod length;
#[macro_use]
mod macros;
pub mod matrix2d;
pub mod matrix4d;
pub mod num;
pub mod point;
pub mod rect;
pub mod scale_factor;
pub mod side_offsets;
pub mod size;
pub mod trig;
/// The default unit.
#[derive(Clone, Copy, RustcDecodable, RustcEncodable)]
pub struct UnknownUnit;
/// Unit for angles in radians.
pub struct Rad;
/// Unit for angles in degrees.
pub struct Deg;
/// A value in radians.
pub type Radians<T> = Length<T, Rad>;
/// A value in Degrees.
pub type Degrees<T> = Length<T, Deg>;

87
third_party/rust/euclid-0.13.0/src/macros.rs поставляемый
Просмотреть файл

@ -1,87 +0,0 @@
// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
macro_rules! define_matrix {
(
$(#[$attr:meta])*
pub struct $name:ident<T, $($phantom:ident),+> {
$(pub $field:ident: T,)+
}
) => (
#[repr(C)]
$(#[$attr])*
pub struct $name<T, $($phantom),+> {
$(pub $field: T,)+
_unit: PhantomData<($($phantom),+)>
}
impl<T: Clone, $($phantom),+> Clone for $name<T, $($phantom),+> {
fn clone(&self) -> Self {
$name {
$($field: self.$field.clone(),)+
_unit: PhantomData,
}
}
}
impl<T: Copy, $($phantom),+> Copy for $name<T, $($phantom),+> {}
impl<T, $($phantom),+> ::heapsize::HeapSizeOf for $name<T, $($phantom),+>
where T: ::heapsize::HeapSizeOf
{
fn heap_size_of_children(&self) -> usize {
$(self.$field.heap_size_of_children() +)+ 0
}
}
impl<T, $($phantom),+> ::serde::Deserialize for $name<T, $($phantom),+>
where T: ::serde::Deserialize
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: ::serde::Deserializer
{
let ($($field,)+) =
try!(::serde::Deserialize::deserialize(deserializer));
Ok($name {
$($field: $field,)+
_unit: PhantomData,
})
}
}
impl<T, $($phantom),+> ::serde::Serialize for $name<T, $($phantom),+>
where T: ::serde::Serialize
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: ::serde::Serializer
{
($(&self.$field,)+).serialize(serializer)
}
}
impl<T, $($phantom),+> ::std::cmp::Eq for $name<T, $($phantom),+>
where T: ::std::cmp::Eq {}
impl<T, $($phantom),+> ::std::cmp::PartialEq for $name<T, $($phantom),+>
where T: ::std::cmp::PartialEq
{
fn eq(&self, other: &Self) -> bool {
true $(&& self.$field == other.$field)+
}
}
impl<T, $($phantom),+> ::std::hash::Hash for $name<T, $($phantom),+>
where T: ::std::hash::Hash
{
fn hash<H: ::std::hash::Hasher>(&self, h: &mut H) {
$(self.$field.hash(h);)+
}
}
)
}

77
third_party/rust/euclid-0.13.0/src/num.rs поставляемый
Просмотреть файл

@ -1,77 +0,0 @@
// Copyright 2014 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! A one-dimensional length, tagged with its units.
use num_traits;
pub trait Zero {
fn zero() -> Self;
}
impl<T: num_traits::Zero> Zero for T {
fn zero() -> T { num_traits::Zero::zero() }
}
pub trait One {
fn one() -> Self;
}
impl<T: num_traits::One> One for T {
fn one() -> T { num_traits::One::one() }
}
pub trait Round : Copy { fn round(self) -> Self; }
pub trait Floor : Copy { fn floor(self) -> Self; }
pub trait Ceil : Copy { fn ceil(self) -> Self; }
macro_rules! num_int {
($ty:ty) => (
impl Round for $ty {
#[inline]
fn round(self) -> $ty { self }
}
impl Floor for $ty {
#[inline]
fn floor(self) -> $ty { self }
}
impl Ceil for $ty {
#[inline]
fn ceil(self) -> $ty { self }
}
)
}
macro_rules! num_float {
($ty:ty) => (
impl Round for $ty {
#[inline]
fn round(self) -> $ty { self.round() }
}
impl Floor for $ty {
#[inline]
fn floor(self) -> $ty { self.floor() }
}
impl Ceil for $ty {
#[inline]
fn ceil(self) -> $ty { self.ceil() }
}
)
}
num_int!(i16);
num_int!(u16);
num_int!(i32);
num_int!(u32);
num_int!(i64);
num_int!(u64);
num_int!(isize);
num_int!(usize);
num_float!(f32);
num_float!(f64);

995
third_party/rust/euclid-0.13.0/src/point.rs поставляемый
Просмотреть файл

@ -1,995 +0,0 @@
// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use super::UnknownUnit;
use approxeq::ApproxEq;
use length::Length;
use scale_factor::ScaleFactor;
use size::TypedSize2D;
use num::*;
use num_traits::{Float, NumCast};
use std::fmt;
use std::ops::{Add, Neg, Mul, Sub, Div};
use std::marker::PhantomData;
define_matrix! {
/// A 2d Point tagged with a unit.
#[derive(RustcDecodable, RustcEncodable)]
pub struct TypedPoint2D<T, U> {
pub x: T,
pub y: T,
}
}
/// Default 2d point type with no unit.
///
/// `Point2D` provides the same methods as `TypedPoint2D`.
pub type Point2D<T> = TypedPoint2D<T, UnknownUnit>;
impl<T: Copy + Zero, U> TypedPoint2D<T, U> {
/// Constructor, setting all components to zero.
#[inline]
pub fn zero() -> TypedPoint2D<T, U> {
TypedPoint2D::new(Zero::zero(), Zero::zero())
}
/// Convert into a 3d point.
#[inline]
pub fn to_3d(&self) -> TypedPoint3D<T, U> {
TypedPoint3D::new(self.x, self.y, Zero::zero())
}
}
impl<T: fmt::Debug, U> fmt::Debug for TypedPoint2D<T, U> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({:?},{:?})", self.x, self.y)
}
}
impl<T: fmt::Display, U> fmt::Display for TypedPoint2D<T, U> {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "({},{})", self.x, self.y)
}
}
impl<T: Copy, U> TypedPoint2D<T, U> {
/// Constructor taking scalar values directly.
#[inline]
pub fn new(x: T, y: T) -> TypedPoint2D<T, U> {
TypedPoint2D { x: x, y: y, _unit: PhantomData }
}
/// Constructor taking properly typed Lengths instead of scalar values.
#[inline]
pub fn from_lengths(x: Length<T, U>, y: Length<T, U>) -> TypedPoint2D<T, U> {
TypedPoint2D::new(x.0, y.0)
}
/// Returns self.x as a Length carrying the unit.
#[inline]
pub fn x_typed(&self) -> Length<T, U> { Length::new(self.x) }
/// Returns self.y as a Length carrying the unit.
#[inline]
pub fn y_typed(&self) -> Length<T, U> { Length::new(self.y) }
/// Drop the units, preserving only the numeric value.
#[inline]
pub fn to_untyped(&self) -> Point2D<T> {
TypedPoint2D::new(self.x, self.y)
}
/// Tag a unitless value with units.
#[inline]
pub fn from_untyped(p: &Point2D<T>) -> TypedPoint2D<T, U> {
TypedPoint2D::new(p.x, p.y)
}
#[inline]
pub fn to_array(&self) -> [T; 2] {
[self.x, self.y]
}
}
impl<T, U> TypedPoint2D<T, U>
where T: Copy + Mul<T, Output=T> + Add<T, Output=T> + Sub<T, Output=T> {
/// Dot product.
#[inline]
pub fn dot(self, other: TypedPoint2D<T, U>) -> T {
self.x * other.x + self.y * other.y
}
/// Returns the norm of the cross product [self.x, self.y, 0] x [other.x, other.y, 0]..
#[inline]
pub fn cross(self, other: TypedPoint2D<T, U>) -> T {
self.x * other.y - self.y * other.x
}
#[inline]
pub fn normalize(self) -> Self where T: Float + ApproxEq<T> {
let dot = self.dot(self);
if dot.approx_eq(&T::zero()) {
self
} else {
self / dot.sqrt()
}
}
}
impl<T: Copy + Add<T, Output=T>, U> Add for TypedPoint2D<T, U> {
type Output = TypedPoint2D<T, U>;
fn add(self, other: TypedPoint2D<T, U>) -> TypedPoint2D<T, U> {
TypedPoint2D::new(self.x + other.x, self.y + other.y)
}
}
impl<T: Copy + Add<T, Output=T>, U> Add<TypedSize2D<T, U>> for TypedPoint2D<T, U> {
type Output = TypedPoint2D<T, U>;
fn add(self, other: TypedSize2D<T, U>) -> TypedPoint2D<T, U> {
TypedPoint2D::new(self.x + other.width, self.y + other.height)
}
}
impl<T: Copy + Add<T, Output=T>, U> TypedPoint2D<T, U> {
pub fn add_size(&self, other: &TypedSize2D<T, U>) -> TypedPoint2D<T, U> {
TypedPoint2D::new(self.x + other.width, self.y + other.height)
}
}
impl<T: Copy + Sub<T, Output=T>, U> Sub for TypedPoint2D<T, U> {
type Output = TypedPoint2D<T, U>;
fn sub(self, other: TypedPoint2D<T, U>) -> TypedPoint2D<T, U> {
TypedPoint2D::new(self.x - other.x, self.y - other.y)
}
}
impl <T: Copy + Neg<Output=T>, U> Neg for TypedPoint2D<T, U> {
type Output = TypedPoint2D<T, U>;
#[inline]
fn neg(self) -> TypedPoint2D<T, U> {
TypedPoint2D::new(-self.x, -self.y)
}
}
impl<T: Float, U> TypedPoint2D<T, U> {
pub fn min(self, other: TypedPoint2D<T, U>) -> TypedPoint2D<T, U> {
TypedPoint2D::new(self.x.min(other.x), self.y.min(other.y))
}
pub fn max(self, other: TypedPoint2D<T, U>) -> TypedPoint2D<T, U> {
TypedPoint2D::new(self.x.max(other.x), self.y.max(other.y))
}
}
impl<T: Copy + Mul<T, Output=T>, U> Mul<T> for TypedPoint2D<T, U> {
type Output = TypedPoint2D<T, U>;
#[inline]
fn mul(self, scale: T) -> TypedPoint2D<T, U> {
TypedPoint2D::new(self.x * scale, self.y * scale)
}
}
impl<T: Copy + Div<T, Output=T>, U> Div<T> for TypedPoint2D<T, U> {
type Output = TypedPoint2D<T, U>;
#[inline]
fn div(self, scale: T) -> TypedPoint2D<T, U> {
TypedPoint2D::new(self.x / scale, self.y / scale)
}
}
impl<T: Copy + Mul<T, Output=T>, U1, U2> Mul<ScaleFactor<T, U1, U2>> for TypedPoint2D<T, U1> {
type Output = TypedPoint2D<T, U2>;
#[inline]
fn mul(self, scale: ScaleFactor<T, U1, U2>) -> TypedPoint2D<T, U2> {
TypedPoint2D::new(self.x * scale.get(), self.y * scale.get())
}
}
impl<T: Copy + Div<T, Output=T>, U1, U2> Div<ScaleFactor<T, U1, U2>> for TypedPoint2D<T, U2> {
type Output = TypedPoint2D<T, U1>;
#[inline]
fn div(self, scale: ScaleFactor<T, U1, U2>) -> TypedPoint2D<T, U1> {
TypedPoint2D::new(self.x / scale.get(), self.y / scale.get())
}
}
impl<T: Round, U> TypedPoint2D<T, U> {
/// Rounds each component to the nearest integer value.
///
/// This behavior is preserved for negative values (unlike the basic cast).
/// For example `{ -0.1, -0.8 }.round() == { 0.0, -1.0 }`.
pub fn round(&self) -> Self {
TypedPoint2D::new(self.x.round(), self.y.round())
}
}
impl<T: Ceil, U> TypedPoint2D<T, U> {
/// Rounds each component to the smallest integer equal or greater than the original value.
///
/// This behavior is preserved for negative values (unlike the basic cast).
/// For example `{ -0.1, -0.8 }.ceil() == { 0.0, 0.0 }`.
pub fn ceil(&self) -> Self {
TypedPoint2D::new(self.x.ceil(), self.y.ceil())
}
}
impl<T: Floor, U> TypedPoint2D<T, U> {
/// Rounds each component to the biggest integer equal or lower than the original value.
///
/// This behavior is preserved for negative values (unlike the basic cast).
/// For example `{ -0.1, -0.8 }.floor() == { -1.0, -1.0 }`.
pub fn floor(&self) -> Self {
TypedPoint2D::new(self.x.floor(), self.y.floor())
}
}
impl<T: NumCast + Copy, U> TypedPoint2D<T, U> {
/// Cast from one numeric representation to another, preserving the units.
///
/// When casting from floating point to integer coordinates, the decimals are truncated
/// as one would expect from a simple cast, but this behavior does not always make sense
/// geometrically. Consider using `round()`, `ceil()` or `floor()` before casting.
pub fn cast<NewT: NumCast + Copy>(&self) -> Option<TypedPoint2D<NewT, U>> {
match (NumCast::from(self.x), NumCast::from(self.y)) {
(Some(x), Some(y)) => Some(TypedPoint2D::new(x, y)),
_ => None
}
}
// Convenience functions for common casts
/// Cast into an `f32` point.
pub fn to_f32(&self) -> TypedPoint2D<f32, U> {
self.cast().unwrap()
}
/// Cast into an `usize` point, truncating decimals if any.
///
/// When casting from floating point points, it is worth considering whether
/// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
/// the desired conversion behavior.
pub fn to_usize(&self) -> TypedPoint2D<usize, U> {
self.cast().unwrap()
}
/// Cast into an i32 point, truncating decimals if any.
///
/// When casting from floating point points, it is worth considering whether
/// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
/// the desired conversion behavior.
pub fn to_i32(&self) -> TypedPoint2D<i32, U> {
self.cast().unwrap()
}
/// Cast into an i64 point, truncating decimals if any.
///
/// When casting from floating point points, it is worth considering whether
/// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
/// the desired conversion behavior.
pub fn to_i64(&self) -> TypedPoint2D<i64, U> {
self.cast().unwrap()
}
}
impl<T: Copy+ApproxEq<T>, U> ApproxEq<TypedPoint2D<T, U>> for TypedPoint2D<T, U> {
#[inline]
fn approx_epsilon() -> Self {
TypedPoint2D::new(T::approx_epsilon(), T::approx_epsilon())
}
#[inline]
fn approx_eq(&self, other: &Self) -> bool {
self.x.approx_eq(&other.x) && self.y.approx_eq(&other.y)
}
#[inline]
fn approx_eq_eps(&self, other: &Self, eps: &Self) -> bool {
self.x.approx_eq_eps(&other.x, &eps.x) && self.y.approx_eq_eps(&other.y, &eps.y)
}
}
define_matrix! {
/// A 3d Point tagged with a unit.
#[derive(RustcDecodable, RustcEncodable)]
pub struct TypedPoint3D<T, U> {
pub x: T,
pub y: T,
pub z: T,
}
}
/// Default 3d point type with no unit.
///
/// `Point3D` provides the same methods as `TypedPoint3D`.
pub type Point3D<T> = TypedPoint3D<T, UnknownUnit>;
impl<T: Copy + Zero, U> TypedPoint3D<T, U> {
/// Constructor, setting all copmonents to zero.
#[inline]
pub fn zero() -> TypedPoint3D<T, U> {
TypedPoint3D::new(Zero::zero(), Zero::zero(), Zero::zero())
}
}
impl<T: fmt::Debug, U> fmt::Debug for TypedPoint3D<T, U> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({:?},{:?},{:?})", self.x, self.y, self.z)
}
}
impl<T: fmt::Display, U> fmt::Display for TypedPoint3D<T, U> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({},{},{})", self.x, self.y, self.z)
}
}
impl<T: Copy, U> TypedPoint3D<T, U> {
/// Constructor taking scalar values directly.
#[inline]
pub fn new(x: T, y: T, z: T) -> TypedPoint3D<T, U> {
TypedPoint3D { x: x, y: y, z: z, _unit: PhantomData }
}
/// Constructor taking properly typed Lengths instead of scalar values.
#[inline]
pub fn from_lengths(x: Length<T, U>, y: Length<T, U>, z: Length<T, U>) -> TypedPoint3D<T, U> {
TypedPoint3D::new(x.0, y.0, z.0)
}
/// Returns self.x as a Length carrying the unit.
#[inline]
pub fn x_typed(&self) -> Length<T, U> { Length::new(self.x) }
/// Returns self.y as a Length carrying the unit.
#[inline]
pub fn y_typed(&self) -> Length<T, U> { Length::new(self.y) }
/// Returns self.z as a Length carrying the unit.
#[inline]
pub fn z_typed(&self) -> Length<T, U> { Length::new(self.z) }
#[inline]
pub fn to_array(&self) -> [T; 3] { [self.x, self.y, self.z] }
/// Drop the units, preserving only the numeric value.
#[inline]
pub fn to_untyped(&self) -> Point3D<T> {
TypedPoint3D::new(self.x, self.y, self.z)
}
/// Tag a unitless value with units.
#[inline]
pub fn from_untyped(p: &Point3D<T>) -> TypedPoint3D<T, U> {
TypedPoint3D::new(p.x, p.y, p.z)
}
/// Convert into a 2d point.
#[inline]
pub fn to_2d(&self) -> TypedPoint2D<T, U> {
TypedPoint2D::new(self.x, self.y)
}
}
impl<T: Mul<T, Output=T> +
Add<T, Output=T> +
Sub<T, Output=T> +
Copy, U> TypedPoint3D<T, U> {
// Dot product.
#[inline]
pub fn dot(self, other: TypedPoint3D<T, U>) -> T {
self.x * other.x +
self.y * other.y +
self.z * other.z
}
// Cross product.
#[inline]
pub fn cross(self, other: TypedPoint3D<T, U>) -> TypedPoint3D<T, U> {
TypedPoint3D::new(self.y * other.z - self.z * other.y,
self.z * other.x - self.x * other.z,
self.x * other.y - self.y * other.x)
}
#[inline]
pub fn normalize(self) -> Self where T: Float + ApproxEq<T> {
let dot = self.dot(self);
if dot.approx_eq(&T::zero()) {
self
} else {
self / dot.sqrt()
}
}
}
impl<T: Copy + Add<T, Output=T>, U> Add for TypedPoint3D<T, U> {
type Output = TypedPoint3D<T, U>;
fn add(self, other: TypedPoint3D<T, U>) -> TypedPoint3D<T, U> {
TypedPoint3D::new(self.x + other.x,
self.y + other.y,
self.z + other.z)
}
}
impl<T: Copy + Sub<T, Output=T>, U> Sub for TypedPoint3D<T, U> {
type Output = TypedPoint3D<T, U>;
fn sub(self, other: TypedPoint3D<T, U>) -> TypedPoint3D<T, U> {
TypedPoint3D::new(self.x - other.x,
self.y - other.y,
self.z - other.z)
}
}
impl <T: Copy + Neg<Output=T>, U> Neg for TypedPoint3D<T, U> {
type Output = TypedPoint3D<T, U>;
#[inline]
fn neg(self) -> TypedPoint3D<T, U> {
TypedPoint3D::new(-self.x, -self.y, -self.z)
}
}
impl<T: Copy + Mul<T, Output=T>, U> Mul<T> for TypedPoint3D<T, U> {
type Output = Self;
#[inline]
fn mul(self, scale: T) -> Self {
Self::new(self.x * scale, self.y * scale, self.z * scale)
}
}
impl<T: Copy + Div<T, Output=T>, U> Div<T> for TypedPoint3D<T, U> {
type Output = Self;
#[inline]
fn div(self, scale: T) -> Self {
Self::new(self.x / scale, self.y / scale, self.z / scale)
}
}
impl<T: Float, U> TypedPoint3D<T, U> {
pub fn min(self, other: TypedPoint3D<T, U>) -> TypedPoint3D<T, U> {
TypedPoint3D::new(self.x.min(other.x),
self.y.min(other.y),
self.z.min(other.z))
}
pub fn max(self, other: TypedPoint3D<T, U>) -> TypedPoint3D<T, U> {
TypedPoint3D::new(self.x.max(other.x), self.y.max(other.y),
self.z.max(other.z))
}
}
impl<T: Round, U> TypedPoint3D<T, U> {
/// Rounds each component to the nearest integer value.
///
/// This behavior is preserved for negative values (unlike the basic cast).
pub fn round(&self) -> Self {
TypedPoint3D::new(self.x.round(), self.y.round(), self.z.round())
}
}
impl<T: Ceil, U> TypedPoint3D<T, U> {
/// Rounds each component to the smallest integer equal or greater than the original value.
///
/// This behavior is preserved for negative values (unlike the basic cast).
pub fn ceil(&self) -> Self {
TypedPoint3D::new(self.x.ceil(), self.y.ceil(), self.z.ceil())
}
}
impl<T: Floor, U> TypedPoint3D<T, U> {
/// Rounds each component to the biggest integer equal or lower than the original value.
///
/// This behavior is preserved for negative values (unlike the basic cast).
pub fn floor(&self) -> Self {
TypedPoint3D::new(self.x.floor(), self.y.floor(), self.z.floor())
}
}
impl<T: NumCast + Copy, U> TypedPoint3D<T, U> {
/// Cast from one numeric representation to another, preserving the units.
///
/// When casting from floating point to integer coordinates, the decimals are truncated
/// as one would expect from a simple cast, but this behavior does not always make sense
/// geometrically. Consider using round(), ceil or floor() before casting.
pub fn cast<NewT: NumCast + Copy>(&self) -> Option<TypedPoint3D<NewT, U>> {
match (NumCast::from(self.x),
NumCast::from(self.y),
NumCast::from(self.z)) {
(Some(x), Some(y), Some(z)) => Some(TypedPoint3D::new(x, y, z)),
_ => None
}
}
// Convenience functions for common casts
/// Cast into an `f32` point.
pub fn to_f32(&self) -> TypedPoint3D<f32, U> {
self.cast().unwrap()
}
/// Cast into an `usize` point, truncating decimals if any.
///
/// When casting from floating point points, it is worth considering whether
/// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
/// the desired conversion behavior.
pub fn to_usize(&self) -> TypedPoint3D<usize, U> {
self.cast().unwrap()
}
/// Cast into an `i32` point, truncating decimals if any.
///
/// When casting from floating point points, it is worth considering whether
/// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
/// the desired conversion behavior.
pub fn to_i32(&self) -> TypedPoint3D<i32, U> {
self.cast().unwrap()
}
/// Cast into an `i64` point, truncating decimals if any.
///
/// When casting from floating point points, it is worth considering whether
/// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
/// the desired conversion behavior.
pub fn to_i64(&self) -> TypedPoint3D<i64, U> {
self.cast().unwrap()
}
}
impl<T: Copy+ApproxEq<T>, U> ApproxEq<TypedPoint3D<T, U>> for TypedPoint3D<T, U> {
#[inline]
fn approx_epsilon() -> Self {
TypedPoint3D::new(T::approx_epsilon(), T::approx_epsilon(), T::approx_epsilon())
}
#[inline]
fn approx_eq(&self, other: &Self) -> bool {
self.x.approx_eq(&other.x)
&& self.y.approx_eq(&other.y)
&& self.z.approx_eq(&other.z)
}
#[inline]
fn approx_eq_eps(&self, other: &Self, eps: &Self) -> bool {
self.x.approx_eq_eps(&other.x, &eps.x)
&& self.y.approx_eq_eps(&other.y, &eps.y)
&& self.z.approx_eq_eps(&other.z, &eps.z)
}
}
define_matrix! {
/// A 4d Point tagged with a unit.
#[derive(RustcDecodable, RustcEncodable)]
pub struct TypedPoint4D<T, U> {
pub x: T,
pub y: T,
pub z: T,
pub w: T,
}
}
/// Default 4d point with no unit.
///
/// `Point4D` provides the same methods as `TypedPoint4D`.
pub type Point4D<T> = TypedPoint4D<T, UnknownUnit>;
impl<T: Copy + Zero, U> TypedPoint4D<T, U> {
/// Constructor, setting all copmonents to zero.
#[inline]
pub fn zero() -> TypedPoint4D<T, U> {
TypedPoint4D::new(Zero::zero(), Zero::zero(), Zero::zero(), Zero::zero())
}
}
impl<T: fmt::Debug, U> fmt::Debug for TypedPoint4D<T, U> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({:?},{:?},{:?},{:?})", self.x, self.y, self.z, self.w)
}
}
impl<T: fmt::Display, U> fmt::Display for TypedPoint4D<T, U> {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "({},{},{},{})", self.x, self.y, self.z, self.w)
}
}
impl<T: Copy, U> TypedPoint4D<T, U> {
/// Constructor taking scalar values directly.
#[inline]
pub fn new(x: T, y: T, z: T, w: T) -> TypedPoint4D<T, U> {
TypedPoint4D { x: x, y: y, z: z, w: w, _unit: PhantomData }
}
/// Constructor taking properly typed Lengths instead of scalar values.
#[inline]
pub fn from_lengths(x: Length<T, U>,
y: Length<T, U>,
z: Length<T, U>,
w: Length<T, U>) -> TypedPoint4D<T, U> {
TypedPoint4D::new(x.0, y.0, z.0, w.0)
}
/// Returns self.x as a Length carrying the unit.
#[inline]
pub fn x_typed(&self) -> Length<T, U> { Length::new(self.x) }
/// Returns self.y as a Length carrying the unit.
#[inline]
pub fn y_typed(&self) -> Length<T, U> { Length::new(self.y) }
/// Returns self.z as a Length carrying the unit.
#[inline]
pub fn z_typed(&self) -> Length<T, U> { Length::new(self.z) }
/// Returns self.w as a Length carrying the unit.
#[inline]
pub fn w_typed(&self) -> Length<T, U> { Length::new(self.w) }
/// Drop the units, preserving only the numeric value.
#[inline]
pub fn to_untyped(&self) -> Point4D<T> {
TypedPoint4D::new(self.x, self.y, self.z, self.w)
}
/// Tag a unitless value with units.
#[inline]
pub fn from_untyped(p: &Point4D<T>) -> TypedPoint4D<T, U> {
TypedPoint4D::new(p.x, p.y, p.z, p.w)
}
#[inline]
pub fn to_array(&self) -> [T; 4] {
[self.x, self.y, self.z, self.w]
}
}
impl<T: Copy + Div<T, Output=T>, U> TypedPoint4D<T, U> {
/// Convert into a 2d point.
#[inline]
pub fn to_2d(self) -> TypedPoint2D<T, U> {
TypedPoint2D::new(self.x / self.w, self.y / self.w)
}
/// Convert into a 3d point.
#[inline]
pub fn to_3d(self) -> TypedPoint3D<T, U> {
TypedPoint3D::new(self.x / self.w, self.y / self.w, self.z / self.w)
}
}
impl<T: Copy + Add<T, Output=T>, U> Add for TypedPoint4D<T, U> {
type Output = TypedPoint4D<T, U>;
fn add(self, other: TypedPoint4D<T, U>) -> TypedPoint4D<T, U> {
TypedPoint4D::new(self.x + other.x,
self.y + other.y,
self.z + other.z,
self.w + other.w)
}
}
impl<T: Copy + Sub<T, Output=T>, U> Sub for TypedPoint4D<T, U> {
type Output = TypedPoint4D<T, U>;
fn sub(self, other: TypedPoint4D<T, U>) -> TypedPoint4D<T, U> {
TypedPoint4D::new(self.x - other.x,
self.y - other.y,
self.z - other.z,
self.w - other.w)
}
}
impl <T: Copy + Neg<Output=T>, U> Neg for TypedPoint4D<T, U> {
type Output = TypedPoint4D<T, U>;
#[inline]
fn neg(self) -> TypedPoint4D<T, U> {
TypedPoint4D::new(-self.x, -self.y, -self.z, -self.w)
}
}
impl<T: Float, U> TypedPoint4D<T, U> {
pub fn min(self, other: TypedPoint4D<T, U>) -> TypedPoint4D<T, U> {
TypedPoint4D::new(self.x.min(other.x), self.y.min(other.y),
self.z.min(other.z), self.w.min(other.w))
}
pub fn max(self, other: TypedPoint4D<T, U>) -> TypedPoint4D<T, U> {
TypedPoint4D::new(self.x.max(other.x), self.y.max(other.y),
self.z.max(other.z), self.w.max(other.w))
}
}
impl<T: Round, U> TypedPoint4D<T, U> {
/// Rounds each component to the nearest integer value.
///
/// This behavior is preserved for negative values (unlike the basic cast).
pub fn round(&self) -> Self {
TypedPoint4D::new(self.x.round(), self.y.round(), self.z.round(), self.w.round())
}
}
impl<T: Ceil, U> TypedPoint4D<T, U> {
/// Rounds each component to the smallest integer equal or greater than the original value.
///
/// This behavior is preserved for negative values (unlike the basic cast).
pub fn ceil(&self) -> Self {
TypedPoint4D::new(self.x.ceil(), self.y.ceil(), self.z.ceil(), self.w.ceil())
}
}
impl<T: Floor, U> TypedPoint4D<T, U> {
/// Rounds each component to the biggest integer equal or lower than the original value.
///
/// This behavior is preserved for negative values (unlike the basic cast).
pub fn floor(&self) -> Self {
TypedPoint4D::new(self.x.floor(), self.y.floor(), self.z.floor(), self.w.floor())
}
}
impl<T: NumCast + Copy, U> TypedPoint4D<T, U> {
/// Cast from one numeric representation to another, preserving the units.
///
/// When casting from floating point to integer coordinates, the decimals are truncated
/// as one would expect from a simple cast, but this behavior does not always make sense
/// geometrically. Consider using `round()`, `ceil()` or `floor()` before casting.
pub fn cast<NewT: NumCast + Copy>(&self) -> Option<TypedPoint4D<NewT, U>> {
match (NumCast::from(self.x),
NumCast::from(self.y),
NumCast::from(self.z),
NumCast::from(self.w)) {
(Some(x), Some(y), Some(z), Some(w)) => Some(TypedPoint4D::new(x, y, z, w)),
_ => None
}
}
// Convenience functions for common casts
/// Cast into an `f32` point.
pub fn to_f32(&self) -> TypedPoint4D<f32, U> {
self.cast().unwrap()
}
/// Cast into an `usize` point, truncating decimals if any.
///
/// When casting from floating point points, it is worth considering whether
/// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
/// the desired conversion behavior.
pub fn to_usize(&self) -> TypedPoint4D<usize, U> {
self.cast().unwrap()
}
/// Cast into an `i32` point, truncating decimals if any.
///
/// When casting from floating point points, it is worth considering whether
/// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
/// the desired conversion behavior.
pub fn to_i32(&self) -> TypedPoint4D<i32, U> {
self.cast().unwrap()
}
/// Cast into an `i64` point, truncating decimals if any.
///
/// When casting from floating point points, it is worth considering whether
/// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
/// the desired conversion behavior.
pub fn to_i64(&self) -> TypedPoint4D<i64, U> {
self.cast().unwrap()
}
}
impl<T: ApproxEq<T>, U> ApproxEq<T> for TypedPoint4D<T, U> {
fn approx_epsilon() -> T {
T::approx_epsilon()
}
fn approx_eq_eps(&self, other: &Self, approx_epsilon: &T) -> bool {
self.x.approx_eq_eps(&other.x, approx_epsilon)
&& self.y.approx_eq_eps(&other.y, approx_epsilon)
&& self.z.approx_eq_eps(&other.z, approx_epsilon)
&& self.w.approx_eq_eps(&other.w, approx_epsilon)
}
fn approx_eq(&self, other: &Self) -> bool {
self.approx_eq_eps(&other, &Self::approx_epsilon())
}
}
pub fn point2<T: Copy, U>(x: T, y: T) -> TypedPoint2D<T, U> {
TypedPoint2D::new(x, y)
}
pub fn point3<T: Copy, U>(x: T, y: T, z: T) -> TypedPoint3D<T, U> {
TypedPoint3D::new(x, y, z)
}
pub fn point4<T: Copy, U>(x: T, y: T, z: T, w: T) -> TypedPoint4D<T, U> {
TypedPoint4D::new(x, y, z, w)
}
#[cfg(test)]
mod point2d {
use super::Point2D;
#[test]
pub fn test_scalar_mul() {
let p1: Point2D<f32> = Point2D::new(3.0, 5.0);
let result = p1 * 5.0;
assert_eq!(result, Point2D::new(15.0, 25.0));
}
#[test]
pub fn test_dot() {
let p1: Point2D<f32> = Point2D::new(2.0, 7.0);
let p2: Point2D<f32> = Point2D::new(13.0, 11.0);
assert_eq!(p1.dot(p2), 103.0);
}
#[test]
pub fn test_cross() {
let p1: Point2D<f32> = Point2D::new(4.0, 7.0);
let p2: Point2D<f32> = Point2D::new(13.0, 8.0);
let r = p1.cross(p2);
assert_eq!(r, -59.0);
}
#[test]
pub fn test_normalize() {
let p0: Point2D<f32> = Point2D::zero();
let p1: Point2D<f32> = Point2D::new(4.0, 0.0);
let p2: Point2D<f32> = Point2D::new(3.0, -4.0);
assert_eq!(p0.normalize(), p0);
assert_eq!(p1.normalize(), Point2D::new(1.0, 0.0));
assert_eq!(p2.normalize(), Point2D::new(0.6, -0.8));
}
#[test]
pub fn test_min() {
let p1 = Point2D::new(1.0, 3.0);
let p2 = Point2D::new(2.0, 2.0);
let result = p1.min(p2);
assert_eq!(result, Point2D::new(1.0, 2.0));
}
#[test]
pub fn test_max() {
let p1 = Point2D::new(1.0, 3.0);
let p2 = Point2D::new(2.0, 2.0);
let result = p1.max(p2);
assert_eq!(result, Point2D::new(2.0, 3.0));
}
}
#[cfg(test)]
mod typedpoint2d {
use super::TypedPoint2D;
use scale_factor::ScaleFactor;
pub enum Mm {}
pub enum Cm {}
pub type Point2DMm<T> = TypedPoint2D<T, Mm>;
pub type Point2DCm<T> = TypedPoint2D<T, Cm>;
#[test]
pub fn test_add() {
let p1 = Point2DMm::new(1.0, 2.0);
let p2 = Point2DMm::new(3.0, 4.0);
let result = p1 + p2;
assert_eq!(result, Point2DMm::new(4.0, 6.0));
}
#[test]
pub fn test_scalar_mul() {
let p1 = Point2DMm::new(1.0, 2.0);
let cm_per_mm: ScaleFactor<f32, Mm, Cm> = ScaleFactor::new(0.1);
let result = p1 * cm_per_mm;
assert_eq!(result, Point2DCm::new(0.1, 0.2));
}
}
#[cfg(test)]
mod point3d {
use super::Point3D;
#[test]
pub fn test_dot() {
let p1 = Point3D::new(7.0, 21.0, 32.0);
let p2 = Point3D::new(43.0, 5.0, 16.0);
assert_eq!(p1.dot(p2), 918.0);
}
#[test]
pub fn test_cross() {
let p1 = Point3D::new(4.0, 7.0, 9.0);
let p2 = Point3D::new(13.0, 8.0, 3.0);
let p3 = p1.cross(p2);
assert_eq!(p3, Point3D::new(-51.0, 105.0, -59.0));
}
#[test]
pub fn test_normalize() {
let p0: Point3D<f32> = Point3D::zero();
let p1: Point3D<f32> = Point3D::new(0.0, -6.0, 0.0);
let p2: Point3D<f32> = Point3D::new(1.0, 2.0, -2.0);
assert_eq!(p0.normalize(), p0);
assert_eq!(p1.normalize(), Point3D::new(0.0, -1.0, 0.0));
assert_eq!(p2.normalize(), Point3D::new(1.0/3.0, 2.0/3.0, -2.0/3.0));
}
#[test]
pub fn test_min() {
let p1 = Point3D::new(1.0, 3.0, 5.0);
let p2 = Point3D::new(2.0, 2.0, -1.0);
let result = p1.min(p2);
assert_eq!(result, Point3D::new(1.0, 2.0, -1.0));
}
#[test]
pub fn test_max() {
let p1 = Point3D::new(1.0, 3.0, 5.0);
let p2 = Point3D::new(2.0, 2.0, -1.0);
let result = p1.max(p2);
assert_eq!(result, Point3D::new(2.0, 3.0, 5.0));
}
}
#[cfg(test)]
mod point4d {
use super::Point4D;
#[test]
pub fn test_add() {
let p1 = Point4D::new(7.0, 21.0, 32.0, 1.0);
let p2 = Point4D::new(43.0, 5.0, 16.0, 2.0);
let result = p1 + p2;
assert_eq!(result, Point4D::new(50.0, 26.0, 48.0, 3.0));
}
#[test]
pub fn test_sub() {
let p1 = Point4D::new(7.0, 21.0, 32.0, 1.0);
let p2 = Point4D::new(43.0, 5.0, 16.0, 2.0);
let result = p1 - p2;
assert_eq!(result, Point4D::new(-36.0, 16.0, 16.0, -1.0));
}
#[test]
pub fn test_min() {
let p1 = Point4D::new(1.0, 3.0, 5.0, 7.0);
let p2 = Point4D::new(2.0, 2.0, -1.0, 10.0);
let result = p1.min(p2);
assert_eq!(result, Point4D::new(1.0, 2.0, -1.0, 7.0));
}
#[test]
pub fn test_max() {
let p1 = Point4D::new(1.0, 3.0, 5.0, 7.0);
let p2 = Point4D::new(2.0, 2.0, -1.0, 10.0);
let result = p1.max(p2);
assert_eq!(result, Point4D::new(2.0, 3.0, 5.0, 10.0));
}
}

671
third_party/rust/euclid-0.13.0/src/rect.rs поставляемый
Просмотреть файл

@ -1,671 +0,0 @@
// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use super::UnknownUnit;
use length::Length;
use scale_factor::ScaleFactor;
use num::*;
use point::TypedPoint2D;
use size::TypedSize2D;
use heapsize::HeapSizeOf;
use num_traits::NumCast;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::cmp::PartialOrd;
use std::fmt;
use std::ops::{Add, Sub, Mul, Div};
/// A 2d Rectangle optionally tagged with a unit.
#[derive(RustcDecodable, RustcEncodable)]
pub struct TypedRect<T, U = UnknownUnit> {
pub origin: TypedPoint2D<T, U>,
pub size: TypedSize2D<T, U>,
}
/// The default rectangle type with no unit.
pub type Rect<T> = TypedRect<T, UnknownUnit>;
impl<T: HeapSizeOf, U> HeapSizeOf for TypedRect<T, U> {
fn heap_size_of_children(&self) -> usize {
self.origin.heap_size_of_children() + self.size.heap_size_of_children()
}
}
impl<T: Copy + Deserialize, U> Deserialize for TypedRect<T, U> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer
{
let (origin, size) = try!(Deserialize::deserialize(deserializer));
Ok(TypedRect::new(origin, size))
}
}
impl<T: Serialize, U> Serialize for TypedRect<T, U> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
(&self.origin, &self.size).serialize(serializer)
}
}
impl<T: Copy, U> Copy for TypedRect<T, U> {}
impl<T: Copy, U> Clone for TypedRect<T, U> {
fn clone(&self) -> TypedRect<T, U> { *self }
}
impl<T: PartialEq, U> PartialEq<TypedRect<T, U>> for TypedRect<T, U> {
fn eq(&self, other: &TypedRect<T, U>) -> bool {
self.origin.eq(&other.origin) && self.size.eq(&other.size)
}
}
impl<T: Eq, U> Eq for TypedRect<T, U> {}
impl<T: fmt::Debug, U> fmt::Debug for TypedRect<T, U> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "TypedRect({:?} at {:?})", self.size, self.origin)
}
}
impl<T: fmt::Display, U> fmt::Display for TypedRect<T, U> {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "Rect({} at {})", self.size, self.origin)
}
}
impl<T, U> TypedRect<T, U> {
/// Constructor.
pub fn new(origin: TypedPoint2D<T, U>, size: TypedSize2D<T, U>) -> TypedRect<T, U> {
TypedRect {
origin: origin,
size: size,
}
}
}
impl<T, U> TypedRect<T, U>
where T: Copy + Clone + Zero + PartialOrd + PartialEq + Add<T, Output=T> + Sub<T, Output=T> {
#[inline]
pub fn intersects(&self, other: &TypedRect<T, U>) -> bool {
self.origin.x < other.origin.x + other.size.width &&
other.origin.x < self.origin.x + self.size.width &&
self.origin.y < other.origin.y + other.size.height &&
other.origin.y < self.origin.y + self.size.height
}
#[inline]
pub fn max_x(&self) -> T {
self.origin.x + self.size.width
}
#[inline]
pub fn min_x(&self) -> T {
self.origin.x
}
#[inline]
pub fn max_y(&self) -> T {
self.origin.y + self.size.height
}
#[inline]
pub fn min_y(&self) -> T {
self.origin.y
}
#[inline]
pub fn max_x_typed(&self) -> Length<T, U> {
Length::new(self.max_x())
}
#[inline]
pub fn min_x_typed(&self) -> Length<T, U> {
Length::new(self.min_x())
}
#[inline]
pub fn max_y_typed(&self) -> Length<T, U> {
Length::new(self.max_y())
}
#[inline]
pub fn min_y_typed(&self) -> Length<T, U> {
Length::new(self.min_y())
}
#[inline]
pub fn intersection(&self, other: &TypedRect<T, U>) -> Option<TypedRect<T, U>> {
if !self.intersects(other) {
return None;
}
let upper_left = TypedPoint2D::new(max(self.min_x(), other.min_x()),
max(self.min_y(), other.min_y()));
let lower_right_x = min(self.max_x(), other.max_x());
let lower_right_y = min(self.max_y(), other.max_y());
Some(TypedRect::new(upper_left, TypedSize2D::new(lower_right_x - upper_left.x,
lower_right_y - upper_left.y)))
}
/// Translates the rect by a vector.
#[inline]
pub fn translate(&self, other: &TypedPoint2D<T, U>) -> TypedRect<T, U> {
TypedRect::new(
TypedPoint2D::new(self.origin.x + other.x, self.origin.y + other.y),
self.size
)
}
/// Returns true if this rectangle contains the point. Points are considered
/// in the rectangle if they are on the left or top edge, but outside if they
/// are on the right or bottom edge.
#[inline]
pub fn contains(&self, other: &TypedPoint2D<T, U>) -> bool {
self.origin.x <= other.x && other.x < self.origin.x + self.size.width &&
self.origin.y <= other.y && other.y < self.origin.y + self.size.height
}
/// Returns true if this rectangle contains the interior of rect. Always
/// returns true if rect is empty, and always returns false if rect is
/// nonempty but this rectangle is empty.
#[inline]
pub fn contains_rect(&self, rect: &TypedRect<T, U>) -> bool {
rect.is_empty() ||
(self.min_x() <= rect.min_x() && rect.max_x() <= self.max_x() &&
self.min_y() <= rect.min_y() && rect.max_y() <= self.max_y())
}
#[inline]
pub fn inflate(&self, width: T, height: T) -> TypedRect<T, U> {
TypedRect::new(
TypedPoint2D::new(self.origin.x - width, self.origin.y - height),
TypedSize2D::new(self.size.width + width + width, self.size.height + height + height),
)
}
#[inline]
pub fn inflate_typed(&self, width: Length<T, U>, height: Length<T, U>) -> TypedRect<T, U> {
self.inflate(width.get(), height.get())
}
#[inline]
pub fn top_right(&self) -> TypedPoint2D<T, U> {
TypedPoint2D::new(self.max_x(), self.origin.y)
}
#[inline]
pub fn bottom_left(&self) -> TypedPoint2D<T, U> {
TypedPoint2D::new(self.origin.x, self.max_y())
}
#[inline]
pub fn bottom_right(&self) -> TypedPoint2D<T, U> {
TypedPoint2D::new(self.max_x(), self.max_y())
}
#[inline]
pub fn translate_by_size(&self, size: &TypedSize2D<T, U>) -> TypedRect<T, U> {
self.translate(&TypedPoint2D::new(size.width, size.height))
}
/// Returns the smallest rectangle containing the four points.
pub fn from_points(points: &[TypedPoint2D<T, U>]) -> Self {
if points.len() == 0 {
return TypedRect::zero();
}
let (mut min_x, mut min_y) = (points[0].x, points[0].y);
let (mut max_x, mut max_y) = (min_x, min_y);
for point in &points[1..] {
if point.x < min_x {
min_x = point.x
}
if point.x > max_x {
max_x = point.x
}
if point.y < min_y {
min_y = point.y
}
if point.y > max_y {
max_y = point.y
}
}
TypedRect::new(TypedPoint2D::new(min_x, min_y),
TypedSize2D::new(max_x - min_x, max_y - min_y))
}
}
impl<T, U> TypedRect<T, U>
where T: Copy + Clone + PartialOrd + Add<T, Output=T> + Sub<T, Output=T> + Zero {
#[inline]
pub fn union(&self, other: &TypedRect<T, U>) -> TypedRect<T, U> {
if self.size == Zero::zero() {
return *other;
}
if other.size == Zero::zero() {
return *self;
}
let upper_left = TypedPoint2D::new(min(self.min_x(), other.min_x()),
min(self.min_y(), other.min_y()));
let lower_right_x = max(self.max_x(), other.max_x());
let lower_right_y = max(self.max_y(), other.max_y());
TypedRect::new(
upper_left,
TypedSize2D::new(lower_right_x - upper_left.x, lower_right_y - upper_left.y)
)
}
}
impl<T, U> TypedRect<T, U> {
#[inline]
pub fn scale<Scale: Copy>(&self, x: Scale, y: Scale) -> TypedRect<T, U>
where T: Copy + Clone + Mul<Scale, Output=T> {
TypedRect::new(
TypedPoint2D::new(self.origin.x * x, self.origin.y * y),
TypedSize2D::new(self.size.width * x, self.size.height * y)
)
}
}
impl<T: Copy + PartialEq + Zero, U> TypedRect<T, U> {
/// Constructor, setting all sides to zero.
pub fn zero() -> TypedRect<T, U> {
TypedRect::new(
TypedPoint2D::zero(),
TypedSize2D::zero(),
)
}
/// Returns true if the size is zero, regardless of the origin's value.
pub fn is_empty(&self) -> bool {
self.size.width == Zero::zero() || self.size.height == Zero::zero()
}
}
pub fn min<T: Clone + PartialOrd>(x: T, y: T) -> T {
if x <= y { x } else { y }
}
pub fn max<T: Clone + PartialOrd>(x: T, y: T) -> T {
if x >= y { x } else { y }
}
impl<T: Copy + Mul<T, Output=T>, U> Mul<T> for TypedRect<T, U> {
type Output = TypedRect<T, U>;
#[inline]
fn mul(self, scale: T) -> TypedRect<T, U> {
TypedRect::new(self.origin * scale, self.size * scale)
}
}
impl<T: Copy + Div<T, Output=T>, U> Div<T> for TypedRect<T, U> {
type Output = TypedRect<T, U>;
#[inline]
fn div(self, scale: T) -> TypedRect<T, U> {
TypedRect::new(self.origin / scale, self.size / scale)
}
}
impl<T: Copy + Mul<T, Output=T>, U1, U2> Mul<ScaleFactor<T, U1, U2>> for TypedRect<T, U1> {
type Output = TypedRect<T, U2>;
#[inline]
fn mul(self, scale: ScaleFactor<T, U1, U2>) -> TypedRect<T, U2> {
TypedRect::new(self.origin * scale, self.size * scale)
}
}
impl<T: Copy + Div<T, Output=T>, U1, U2> Div<ScaleFactor<T, U1, U2>> for TypedRect<T, U2> {
type Output = TypedRect<T, U1>;
#[inline]
fn div(self, scale: ScaleFactor<T, U1, U2>) -> TypedRect<T, U1> {
TypedRect::new(self.origin / scale, self.size / scale)
}
}
impl<T: Copy, Unit> TypedRect<T, Unit> {
/// Drop the units, preserving only the numeric value.
pub fn to_untyped(&self) -> Rect<T> {
TypedRect::new(self.origin.to_untyped(), self.size.to_untyped())
}
/// Tag a unitless value with units.
pub fn from_untyped(r: &Rect<T>) -> TypedRect<T, Unit> {
TypedRect::new(TypedPoint2D::from_untyped(&r.origin), TypedSize2D::from_untyped(&r.size))
}
}
impl<T0: NumCast + Copy, Unit> TypedRect<T0, Unit> {
/// Cast from one numeric representation to another, preserving the units.
///
/// When casting from floating point to integer coordinates, the decimals are truncated
/// as one would expect from a simple cast, but this behavior does not always make sense
/// geometrically. Consider using round(), round_in or round_out() before casting.
pub fn cast<T1: NumCast + Copy>(&self) -> Option<TypedRect<T1, Unit>> {
match (self.origin.cast(), self.size.cast()) {
(Some(origin), Some(size)) => Some(TypedRect::new(origin, size)),
_ => None
}
}
}
impl<T: Floor + Ceil + Round + Add<T, Output=T> + Sub<T, Output=T>, U> TypedRect<T, U> {
/// Return a rectangle with edges rounded to integer coordinates, such that
/// the returned rectangle has the same set of pixel centers as the original
/// one.
/// Edges at offset 0.5 round up.
/// Suitable for most places where integral device coordinates
/// are needed, but note that any translation should be applied first to
/// avoid pixel rounding errors.
/// Note that this is *not* rounding to nearest integer if the values are negative.
/// They are always rounding as floor(n + 0.5).
pub fn round(&self) -> Self {
let origin = self.origin.round();
let size = self.origin.add_size(&self.size).round() - origin;
TypedRect::new(origin, TypedSize2D::new(size.x, size.y))
}
/// Return a rectangle with edges rounded to integer coordinates, such that
/// the original rectangle contains the resulting rectangle.
pub fn round_in(&self) -> Self {
let origin = self.origin.ceil();
let size = self.origin.add_size(&self.size).floor() - origin;
TypedRect::new(origin, TypedSize2D::new(size.x, size.y))
}
/// Return a rectangle with edges rounded to integer coordinates, such that
/// the original rectangle is contained in the resulting rectangle.
pub fn round_out(&self) -> Self {
let origin = self.origin.floor();
let size = self.origin.add_size(&self.size).ceil() - origin;
TypedRect::new(origin, TypedSize2D::new(size.x, size.y))
}
}
// Convenience functions for common casts
impl<T: NumCast + Copy, Unit> TypedRect<T, Unit> {
/// Cast into an `f32` rectangle.
pub fn to_f32(&self) -> TypedRect<f32, Unit> {
self.cast().unwrap()
}
/// Cast into an `usize` rectangle, truncating decimals if any.
///
/// When casting from floating point rectangles, it is worth considering whether
/// to `round()`, `round_in()` or `round_out()` before the cast in order to
/// obtain the desired conversion behavior.
pub fn to_usize(&self) -> TypedRect<usize, Unit> {
self.cast().unwrap()
}
/// Cast into an `i32` rectangle, truncating decimals if any.
///
/// When casting from floating point rectangles, it is worth considering whether
/// to `round()`, `round_in()` or `round_out()` before the cast in order to
/// obtain the desired conversion behavior.
pub fn to_i32(&self) -> TypedRect<i32, Unit> {
self.cast().unwrap()
}
/// Cast into an `i64` rectangle, truncating decimals if any.
///
/// When casting from floating point rectangles, it is worth considering whether
/// to `round()`, `round_in()` or `round_out()` before the cast in order to
/// obtain the desired conversion behavior.
pub fn to_i64(&self) -> TypedRect<i64, Unit> {
self.cast().unwrap()
}
}
/// Shorthand for `TypedRect::new(TypedPoint2D::new(x, y), TypedSize2D::new(w, h))`.
pub fn rect<T: Copy, U>(x: T, y: T, w: T, h: T) -> TypedRect<T, U> {
TypedRect::new(TypedPoint2D::new(x, y), TypedSize2D::new(w, h))
}
#[cfg(test)]
mod tests {
use point::Point2D;
use size::Size2D;
use super::*;
#[test]
fn test_min_max() {
assert!(min(0u32, 1u32) == 0u32);
assert!(min(-1.0f32, 0.0f32) == -1.0f32);
assert!(max(0u32, 1u32) == 1u32);
assert!(max(-1.0f32, 0.0f32) == 0.0f32);
}
#[test]
fn test_translate() {
let p = Rect::new(Point2D::new(0u32, 0u32), Size2D::new(50u32, 40u32));
let pp = p.translate(&Point2D::new(10,15));
assert!(pp.size.width == 50);
assert!(pp.size.height == 40);
assert!(pp.origin.x == 10);
assert!(pp.origin.y == 15);
let r = Rect::new(Point2D::new(-10, -5), Size2D::new(50, 40));
let rr = r.translate(&Point2D::new(0,-10));
assert!(rr.size.width == 50);
assert!(rr.size.height == 40);
assert!(rr.origin.x == -10);
assert!(rr.origin.y == -15);
}
#[test]
fn test_translate_by_size() {
let p = Rect::new(Point2D::new(0u32, 0u32), Size2D::new(50u32, 40u32));
let pp = p.translate_by_size(&Size2D::new(10,15));
assert!(pp.size.width == 50);
assert!(pp.size.height == 40);
assert!(pp.origin.x == 10);
assert!(pp.origin.y == 15);
let r = Rect::new(Point2D::new(-10, -5), Size2D::new(50, 40));
let rr = r.translate_by_size(&Size2D::new(0,-10));
assert!(rr.size.width == 50);
assert!(rr.size.height == 40);
assert!(rr.origin.x == -10);
assert!(rr.origin.y == -15);
}
#[test]
fn test_union() {
let p = Rect::new(Point2D::new(0, 0), Size2D::new(50, 40));
let q = Rect::new(Point2D::new(20,20), Size2D::new(5, 5));
let r = Rect::new(Point2D::new(-15, -30), Size2D::new(200, 15));
let s = Rect::new(Point2D::new(20, -15), Size2D::new(250, 200));
let pq = p.union(&q);
assert!(pq.origin == Point2D::new(0, 0));
assert!(pq.size == Size2D::new(50, 40));
let pr = p.union(&r);
assert!(pr.origin == Point2D::new(-15, -30));
assert!(pr.size == Size2D::new(200, 70));
let ps = p.union(&s);
assert!(ps.origin == Point2D::new(0, -15));
assert!(ps.size == Size2D::new(270, 200));
}
#[test]
fn test_intersection() {
let p = Rect::new(Point2D::new(0, 0), Size2D::new(10, 20));
let q = Rect::new(Point2D::new(5, 15), Size2D::new(10, 10));
let r = Rect::new(Point2D::new(-5, -5), Size2D::new(8, 8));
let pq = p.intersection(&q);
assert!(pq.is_some());
let pq = pq.unwrap();
assert!(pq.origin == Point2D::new(5, 15));
assert!(pq.size == Size2D::new(5, 5));
let pr = p.intersection(&r);
assert!(pr.is_some());
let pr = pr.unwrap();
assert!(pr.origin == Point2D::new(0, 0));
assert!(pr.size == Size2D::new(3, 3));
let qr = q.intersection(&r);
assert!(qr.is_none());
}
#[test]
fn test_contains() {
let r = Rect::new(Point2D::new(-20, 15), Size2D::new(100, 200));
assert!(r.contains(&Point2D::new(0, 50)));
assert!(r.contains(&Point2D::new(-10, 200)));
// The `contains` method is inclusive of the top/left edges, but not the
// bottom/right edges.
assert!(r.contains(&Point2D::new(-20, 15)));
assert!(!r.contains(&Point2D::new(80, 15)));
assert!(!r.contains(&Point2D::new(80, 215)));
assert!(!r.contains(&Point2D::new(-20, 215)));
// Points beyond the top-left corner.
assert!(!r.contains(&Point2D::new(-25, 15)));
assert!(!r.contains(&Point2D::new(-15, 10)));
// Points beyond the top-right corner.
assert!(!r.contains(&Point2D::new(85, 20)));
assert!(!r.contains(&Point2D::new(75, 10)));
// Points beyond the bottom-right corner.
assert!(!r.contains(&Point2D::new(85, 210)));
assert!(!r.contains(&Point2D::new(75, 220)));
// Points beyond the bottom-left corner.
assert!(!r.contains(&Point2D::new(-25, 210)));
assert!(!r.contains(&Point2D::new(-15, 220)));
let r = Rect::new(Point2D::new(-20.0, 15.0), Size2D::new(100.0, 200.0));
assert!(r.contains_rect(&r));
assert!(!r.contains_rect(&r.translate(&Point2D::new( 0.1, 0.0))));
assert!(!r.contains_rect(&r.translate(&Point2D::new(-0.1, 0.0))));
assert!(!r.contains_rect(&r.translate(&Point2D::new( 0.0, 0.1))));
assert!(!r.contains_rect(&r.translate(&Point2D::new( 0.0, -0.1))));
// Empty rectangles are always considered as contained in other rectangles,
// even if their origin is not.
let p = Point2D::new(1.0, 1.0);
assert!(!r.contains(&p));
assert!(r.contains_rect(&Rect::new(p, Size2D::zero())));
}
#[test]
fn test_scale() {
let p = Rect::new(Point2D::new(0u32, 0u32), Size2D::new(50u32, 40u32));
let pp = p.scale(10, 15);
assert!(pp.size.width == 500);
assert!(pp.size.height == 600);
assert!(pp.origin.x == 0);
assert!(pp.origin.y == 0);
let r = Rect::new(Point2D::new(-10, -5), Size2D::new(50, 40));
let rr = r.scale(1, 20);
assert!(rr.size.width == 50);
assert!(rr.size.height == 800);
assert!(rr.origin.x == -10);
assert!(rr.origin.y == -100);
}
#[test]
fn test_inflate() {
let p = Rect::new(Point2D::new(0, 0), Size2D::new(10, 10));
let pp = p.inflate(10, 20);
assert!(pp.size.width == 30);
assert!(pp.size.height == 50);
assert!(pp.origin.x == -10);
assert!(pp.origin.y == -20);
let r = Rect::new(Point2D::new(0, 0), Size2D::new(10, 20));
let rr = r.inflate(-2, -5);
assert!(rr.size.width == 6);
assert!(rr.size.height == 10);
assert!(rr.origin.x == 2);
assert!(rr.origin.y == 5);
}
#[test]
fn test_min_max_x_y() {
let p = Rect::new(Point2D::new(0u32, 0u32), Size2D::new(50u32, 40u32));
assert!(p.max_y() == 40);
assert!(p.min_y() == 0);
assert!(p.max_x() == 50);
assert!(p.min_x() == 0);
let r = Rect::new(Point2D::new(-10, -5), Size2D::new(50, 40));
assert!(r.max_y() == 35);
assert!(r.min_y() == -5);
assert!(r.max_x() == 40);
assert!(r.min_x() == -10);
}
#[test]
fn test_is_empty() {
assert!(Rect::new(Point2D::new(0u32, 0u32), Size2D::new(0u32, 0u32)).is_empty());
assert!(Rect::new(Point2D::new(0u32, 0u32), Size2D::new(10u32, 0u32)).is_empty());
assert!(Rect::new(Point2D::new(0u32, 0u32), Size2D::new(0u32, 10u32)).is_empty());
assert!(!Rect::new(Point2D::new(0u32, 0u32), Size2D::new(1u32, 1u32)).is_empty());
assert!(Rect::new(Point2D::new(10u32, 10u32), Size2D::new(0u32, 0u32)).is_empty());
assert!(Rect::new(Point2D::new(10u32, 10u32), Size2D::new(10u32, 0u32)).is_empty());
assert!(Rect::new(Point2D::new(10u32, 10u32), Size2D::new(0u32, 10u32)).is_empty());
assert!(!Rect::new(Point2D::new(10u32, 10u32), Size2D::new(1u32, 1u32)).is_empty());
}
#[test]
fn test_round() {
let mut x = -2.0;
let mut y = -2.0;
let mut w = -2.0;
let mut h = -2.0;
while x < 2.0 {
while y < 2.0 {
while w < 2.0 {
while h < 2.0 {
let rect = Rect::new(Point2D::new(x, y), Size2D::new(w, h));
assert!(rect.contains_rect(&rect.round_in()));
assert!(rect.round_in().inflate(1.0, 1.0).contains_rect(&rect));
assert!(rect.round_out().contains_rect(&rect));
assert!(rect.inflate(1.0, 1.0).contains_rect(&rect.round_out()));
assert!(rect.inflate(1.0, 1.0).contains_rect(&rect.round()));
assert!(rect.round().inflate(1.0, 1.0).contains_rect(&rect));
h += 0.1;
}
w += 0.1;
}
y += 0.1;
}
x += 0.1
}
}
}

Просмотреть файл

@ -1,172 +0,0 @@
// Copyright 2014 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! A type-checked scaling factor between units.
use num::One;
use heapsize::HeapSizeOf;
use num_traits::NumCast;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::fmt;
use std::ops::{Add, Mul, Sub, Div};
use std::marker::PhantomData;
/// A scaling factor between two different units of measurement.
///
/// This is effectively a type-safe float, intended to be used in combination with other types like
/// `length::Length` to enforce conversion between systems of measurement at compile time.
///
/// `Src` and `Dst` represent the units before and after multiplying a value by a `ScaleFactor`. They
/// may be types without values, such as empty enums. For example:
///
/// ```rust
/// use euclid::scale_factor::ScaleFactor;
/// use euclid::length::Length;
/// enum Mm {};
/// enum Inch {};
///
/// let mm_per_inch: ScaleFactor<f32, Inch, Mm> = ScaleFactor::new(25.4);
///
/// let one_foot: Length<f32, Inch> = Length::new(12.0);
/// let one_foot_in_mm: Length<f32, Mm> = one_foot * mm_per_inch;
/// ```
#[repr(C)]
#[derive(RustcDecodable, RustcEncodable)]
pub struct ScaleFactor<T, Src, Dst>(pub T, PhantomData<(Src, Dst)>);
impl<T: HeapSizeOf, Src, Dst> HeapSizeOf for ScaleFactor<T, Src, Dst> {
fn heap_size_of_children(&self) -> usize {
self.0.heap_size_of_children()
}
}
impl<T, Src, Dst> Deserialize for ScaleFactor<T, Src, Dst> where T: Deserialize {
fn deserialize<D>(deserializer: D) -> Result<ScaleFactor<T, Src, Dst>, D::Error>
where D: Deserializer {
Ok(ScaleFactor(try!(Deserialize::deserialize(deserializer)), PhantomData))
}
}
impl<T, Src, Dst> Serialize for ScaleFactor<T, Src, Dst> where T: Serialize {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
self.0.serialize(serializer)
}
}
impl<T, Src, Dst> ScaleFactor<T, Src, Dst> {
pub fn new(x: T) -> ScaleFactor<T, Src, Dst> {
ScaleFactor(x, PhantomData)
}
}
impl<T: Clone, Src, Dst> ScaleFactor<T, Src, Dst> {
pub fn get(&self) -> T {
self.0.clone()
}
}
impl<T: Clone + One + Div<T, Output=T>, Src, Dst> ScaleFactor<T, Src, Dst> {
/// The inverse ScaleFactor (1.0 / self).
pub fn inv(&self) -> ScaleFactor<T, Dst, Src> {
let one: T = One::one();
ScaleFactor::new(one / self.get())
}
}
// scale0 * scale1
impl<T: Clone + Mul<T, Output=T>, A, B, C>
Mul<ScaleFactor<T, B, C>> for ScaleFactor<T, A, B> {
type Output = ScaleFactor<T, A, C>;
#[inline]
fn mul(self, other: ScaleFactor<T, B, C>) -> ScaleFactor<T, A, C> {
ScaleFactor::new(self.get() * other.get())
}
}
// scale0 + scale1
impl<T: Clone + Add<T, Output=T>, Src, Dst> Add for ScaleFactor<T, Src, Dst> {
type Output = ScaleFactor<T, Src, Dst>;
#[inline]
fn add(self, other: ScaleFactor<T, Src, Dst>) -> ScaleFactor<T, Src, Dst> {
ScaleFactor::new(self.get() + other.get())
}
}
// scale0 - scale1
impl<T: Clone + Sub<T, Output=T>, Src, Dst> Sub for ScaleFactor<T, Src, Dst> {
type Output = ScaleFactor<T, Src, Dst>;
#[inline]
fn sub(self, other: ScaleFactor<T, Src, Dst>) -> ScaleFactor<T, Src, Dst> {
ScaleFactor::new(self.get() - other.get())
}
}
impl<T: NumCast + Clone, Src, Dst0> ScaleFactor<T, Src, Dst0> {
/// Cast from one numeric representation to another, preserving the units.
pub fn cast<T1: NumCast + Clone>(&self) -> Option<ScaleFactor<T1, Src, Dst0>> {
NumCast::from(self.get()).map(ScaleFactor::new)
}
}
// FIXME: Switch to `derive(PartialEq, Clone)` after this Rust issue is fixed:
// https://github.com/mozilla/rust/issues/7671
impl<T: PartialEq, Src, Dst> PartialEq for ScaleFactor<T, Src, Dst> {
fn eq(&self, other: &ScaleFactor<T, Src, Dst>) -> bool {
self.0 == other.0
}
}
impl<T: Clone, Src, Dst> Clone for ScaleFactor<T, Src, Dst> {
fn clone(&self) -> ScaleFactor<T, Src, Dst> {
ScaleFactor::new(self.get())
}
}
impl<T: Copy, Src, Dst> Copy for ScaleFactor<T, Src, Dst> {}
impl<T: fmt::Debug, Src, Dst> fmt::Debug for ScaleFactor<T, Src, Dst> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.0.fmt(f)
}
}
impl<T: fmt::Display, Src, Dst> fmt::Display for ScaleFactor<T, Src, Dst> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.0.fmt(f)
}
}
#[cfg(test)]
mod tests {
use super::ScaleFactor;
enum Inch {}
enum Cm {}
enum Mm {}
#[test]
fn test_scale_factor() {
let mm_per_inch: ScaleFactor<f32, Inch, Mm> = ScaleFactor::new(25.4);
let cm_per_mm: ScaleFactor<f32, Mm, Cm> = ScaleFactor::new(0.1);
let mm_per_cm: ScaleFactor<f32, Cm, Mm> = cm_per_mm.inv();
assert_eq!(mm_per_cm.get(), 10.0);
let cm_per_inch: ScaleFactor<f32, Inch, Cm> = mm_per_inch * cm_per_mm;
assert_eq!(cm_per_inch, ScaleFactor::new(2.54));
let a: ScaleFactor<isize, Inch, Inch> = ScaleFactor::new(2);
let b: ScaleFactor<isize, Inch, Inch> = ScaleFactor::new(3);
assert!(a != b);
assert_eq!(a, a.clone());
assert_eq!(a.clone() + b.clone(), ScaleFactor::new(5));
assert_eq!(a - b, ScaleFactor::new(-1));
}
}

Просмотреть файл

@ -1,283 +0,0 @@
// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! A group of side offsets, which correspond to top/left/bottom/right for borders, padding,
//! and margins in CSS.
use super::UnknownUnit;
use length::Length;
use num::Zero;
use std::fmt;
use std::ops::Add;
use std::marker::PhantomData;
#[cfg(feature = "unstable")]
use heapsize::HeapSizeOf;
/// A group of side offsets, which correspond to top/left/bottom/right for borders, padding,
/// and margins in CSS, optionally tagged with a unit.
define_matrix! {
pub struct TypedSideOffsets2D<T, U> {
pub top: T,
pub right: T,
pub bottom: T,
pub left: T,
}
}
impl<T: fmt::Debug, U> fmt::Debug for TypedSideOffsets2D<T, U> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({:?},{:?},{:?},{:?})",
self.top, self.right, self.bottom, self.left)
}
}
/// The default side offset type with no unit.
pub type SideOffsets2D<T> = TypedSideOffsets2D<T, UnknownUnit>;
impl<T: Copy, U> TypedSideOffsets2D<T, U> {
/// Constructor taking a scalar for each side.
pub fn new(top: T, right: T, bottom: T, left: T) -> TypedSideOffsets2D<T, U> {
TypedSideOffsets2D {
top: top,
right: right,
bottom: bottom,
left: left,
_unit: PhantomData,
}
}
/// Constructor taking a typed Length for each side.
pub fn from_lengths(top: Length<T, U>,
right: Length<T, U>,
bottom: Length<T, U>,
left: Length<T, U>) -> TypedSideOffsets2D<T, U> {
TypedSideOffsets2D::new(top.0, right.0, bottom.0, left.0)
}
/// Access self.top as a typed Length instead of a scalar value.
pub fn top_typed(&self) -> Length<T, U> { Length::new(self.top) }
/// Access self.right as a typed Length instead of a scalar value.
pub fn right_typed(&self) -> Length<T, U> { Length::new(self.right) }
/// Access self.bottom as a typed Length instead of a scalar value.
pub fn bottom_typed(&self) -> Length<T, U> { Length::new(self.bottom) }
/// Access self.left as a typed Length instead of a scalar value.
pub fn left_typed(&self) -> Length<T, U> { Length::new(self.left) }
/// Constructor setting the same value to all sides, taking a scalar value directly.
pub fn new_all_same(all: T) -> TypedSideOffsets2D<T, U> {
TypedSideOffsets2D::new(all, all, all, all)
}
/// Constructor setting the same value to all sides, taking a typed Length.
pub fn from_length_all_same(all: Length<T, U>) -> TypedSideOffsets2D<T, U> {
TypedSideOffsets2D::new_all_same(all.0)
}
}
impl<T, U> TypedSideOffsets2D<T, U> where T: Add<T, Output=T> + Copy {
pub fn horizontal(&self) -> T {
self.left + self.right
}
pub fn vertical(&self) -> T {
self.top + self.bottom
}
pub fn horizontal_typed(&self) -> Length<T, U> {
Length::new(self.horizontal())
}
pub fn vertical_typed(&self) -> Length<T, U> {
Length::new(self.vertical())
}
}
impl<T, U> Add for TypedSideOffsets2D<T, U> where T : Copy + Add<T, Output=T> {
type Output = TypedSideOffsets2D<T, U>;
fn add(self, other: TypedSideOffsets2D<T, U>) -> TypedSideOffsets2D<T, U> {
TypedSideOffsets2D::new(
self.top + other.top,
self.right + other.right,
self.bottom + other.bottom,
self.left + other.left,
)
}
}
impl<T: Copy + Zero, U> TypedSideOffsets2D<T, U> {
/// Constructor, setting all sides to zero.
pub fn zero() -> TypedSideOffsets2D<T, U> {
TypedSideOffsets2D::new(
Zero::zero(),
Zero::zero(),
Zero::zero(),
Zero::zero(),
)
}
}
/// A SIMD enabled version of TypedSideOffsets2D specialized for i32.
#[cfg(feature = "unstable")]
#[derive(Clone, Copy, PartialEq)]
#[repr(simd)]
pub struct SideOffsets2DSimdI32 {
pub top: i32,
pub bottom: i32,
pub right: i32,
pub left: i32,
}
#[cfg(feature = "unstable")]
impl HeapSizeOf for SideOffsets2DSimdI32 {
fn heap_size_of_children(&self) -> usize { 0 }
}
#[cfg(feature = "unstable")]
impl SideOffsets2DSimdI32 {
#[inline]
pub fn new(top: i32, right: i32, bottom: i32, left: i32) -> SideOffsets2DSimdI32 {
SideOffsets2DSimdI32 {
top: top,
bottom: bottom,
right: right,
left: left,
}
}
}
#[cfg(feature = "unstable")]
impl SideOffsets2DSimdI32 {
#[inline]
pub fn new_all_same(all: i32) -> SideOffsets2DSimdI32 {
SideOffsets2DSimdI32::new(all.clone(), all.clone(), all.clone(), all.clone())
}
}
#[cfg(feature = "unstable")]
impl SideOffsets2DSimdI32 {
#[inline]
pub fn horizontal(&self) -> i32 {
self.left + self.right
}
#[inline]
pub fn vertical(&self) -> i32 {
self.top + self.bottom
}
}
/*impl Add for SideOffsets2DSimdI32 {
type Output = SideOffsets2DSimdI32;
#[inline]
fn add(self, other: SideOffsets2DSimdI32) -> SideOffsets2DSimdI32 {
self + other // Use SIMD addition
}
}*/
#[cfg(feature = "unstable")]
impl SideOffsets2DSimdI32 {
#[inline]
pub fn zero() -> SideOffsets2DSimdI32 {
SideOffsets2DSimdI32 {
top: 0,
bottom: 0,
right: 0,
left: 0,
}
}
#[cfg(not(target_arch = "x86_64"))]
#[inline]
pub fn is_zero(&self) -> bool {
self.top == 0 && self.right == 0 && self.bottom == 0 && self.left == 0
}
#[cfg(target_arch = "x86_64")]
#[inline]
pub fn is_zero(&self) -> bool {
let is_zero: bool;
unsafe {
asm! {
"ptest $1, $1
setz $0"
: "=r"(is_zero)
: "x"(*self)
:
: "intel"
};
}
is_zero
}
}
#[cfg(feature = "unstable")]
#[cfg(test)]
mod tests {
use super::SideOffsets2DSimdI32;
#[test]
fn test_is_zero() {
assert!(SideOffsets2DSimdI32::new_all_same(0).is_zero());
assert!(!SideOffsets2DSimdI32::new_all_same(1).is_zero());
assert!(!SideOffsets2DSimdI32::new(1, 0, 0, 0).is_zero());
assert!(!SideOffsets2DSimdI32::new(0, 1, 0, 0).is_zero());
assert!(!SideOffsets2DSimdI32::new(0, 0, 1, 0).is_zero());
assert!(!SideOffsets2DSimdI32::new(0, 0, 0, 1).is_zero());
}
}
#[cfg(feature = "unstable")]
#[cfg(bench)]
mod bench {
use test::BenchHarness;
use std::num::Zero;
use rand::{XorShiftRng, Rng};
use super::SideOffsets2DSimdI32;
#[cfg(target_arch = "x86")]
#[cfg(target_arch = "x86_64")]
#[bench]
fn bench_naive_is_zero(bh: &mut BenchHarness) {
fn is_zero(x: &SideOffsets2DSimdI32) -> bool {
x.top.is_zero() && x.right.is_zero() && x.bottom.is_zero() && x.left.is_zero()
}
let mut rng = XorShiftRng::new().unwrap();
bh.iter(|| is_zero(&rng.gen::<SideOffsets2DSimdI32>()))
}
#[bench]
fn bench_is_zero(bh: &mut BenchHarness) {
let mut rng = XorShiftRng::new().unwrap();
bh.iter(|| rng.gen::<SideOffsets2DSimdI32>().is_zero())
}
#[bench]
fn bench_naive_add(bh: &mut BenchHarness) {
fn add(x: &SideOffsets2DSimdI32, y: &SideOffsets2DSimdI32) -> SideOffsets2DSimdI32 {
SideOffsets2DSimdI32 {
top: x.top + y.top,
right: x.right + y.right,
bottom: x.bottom + y.bottom,
left: x.left + y.left,
}
}
let mut rng = XorShiftRng::new().unwrap();
bh.iter(|| add(&rng.gen::<SideOffsets2DSimdI32>(), &rng.gen::<SideOffsets2DSimdI32>()))
}
#[bench]
fn bench_add(bh: &mut BenchHarness) {
let mut rng = XorShiftRng::new().unwrap();
bh.iter(|| rng.gen::<SideOffsets2DSimdI32>() + rng.gen::<SideOffsets2DSimdI32>())
}
}

276
third_party/rust/euclid-0.13.0/src/size.rs поставляемый
Просмотреть файл

@ -1,276 +0,0 @@
// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use super::UnknownUnit;
use length::Length;
use scale_factor::ScaleFactor;
use num::*;
use num_traits::NumCast;
use std::fmt;
use std::ops::{Add, Div, Mul, Sub};
use std::marker::PhantomData;
/// A 2d size tagged with a unit.
define_matrix! {
#[derive(RustcDecodable, RustcEncodable)]
pub struct TypedSize2D<T, U> {
pub width: T,
pub height: T,
}
}
/// Default 2d size type with no unit.
///
/// `Size2D` provides the same methods as `TypedSize2D`.
pub type Size2D<T> = TypedSize2D<T, UnknownUnit>;
impl<T: fmt::Debug, U> fmt::Debug for TypedSize2D<T, U> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}×{:?}", self.width, self.height)
}
}
impl<T: fmt::Display, U> fmt::Display for TypedSize2D<T, U> {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "({}x{})", self.width, self.height)
}
}
impl<T, U> TypedSize2D<T, U> {
/// Constructor taking scalar values.
pub fn new(width: T, height: T) -> TypedSize2D<T, U> {
TypedSize2D {
width: width,
height: height,
_unit: PhantomData,
}
}
}
impl<T: Clone, U> TypedSize2D<T, U> {
/// Constructor taking scalar strongly typed lengths.
pub fn from_lengths(width: Length<T, U>, height: Length<T, U>) -> TypedSize2D<T, U> {
TypedSize2D::new(width.get(), height.get())
}
}
impl<T: Round, U> TypedSize2D<T, U> {
/// Rounds each component to the nearest integer value.
///
/// This behavior is preserved for negative values (unlike the basic cast).
pub fn round(&self) -> Self {
TypedSize2D::new(self.width.round(), self.height.round())
}
}
impl<T: Ceil, U> TypedSize2D<T, U> {
/// Rounds each component to the smallest integer equal or greater than the original value.
///
/// This behavior is preserved for negative values (unlike the basic cast).
pub fn ceil(&self) -> Self {
TypedSize2D::new(self.width.ceil(), self.height.ceil())
}
}
impl<T: Floor, U> TypedSize2D<T, U> {
/// Rounds each component to the biggest integer equal or lower than the original value.
///
/// This behavior is preserved for negative values (unlike the basic cast).
pub fn floor(&self) -> Self {
TypedSize2D::new(self.width.floor(), self.height.floor())
}
}
impl<T: Copy + Add<T, Output=T>, U> Add for TypedSize2D<T, U> {
type Output = TypedSize2D<T, U>;
fn add(self, other: TypedSize2D<T, U>) -> TypedSize2D<T, U> {
TypedSize2D::new(self.width + other.width, self.height + other.height)
}
}
impl<T: Copy + Sub<T, Output=T>, U> Sub for TypedSize2D<T, U> {
type Output = TypedSize2D<T, U>;
fn sub(self, other: TypedSize2D<T, U>) -> TypedSize2D<T, U> {
TypedSize2D::new(self.width - other.width, self.height - other.height)
}
}
impl<T: Copy + Clone + Mul<T, Output=U>, U> TypedSize2D<T, U> {
pub fn area(&self) -> U { self.width * self.height }
}
impl<T: Zero, U> TypedSize2D<T, U> {
pub fn zero() -> TypedSize2D<T, U> {
TypedSize2D::new(
Zero::zero(),
Zero::zero(),
)
}
}
impl<T: Zero, U> Zero for TypedSize2D<T, U> {
fn zero() -> TypedSize2D<T, U> {
TypedSize2D::new(
Zero::zero(),
Zero::zero(),
)
}
}
impl<T: Copy + Mul<T, Output=T>, U> Mul<T> for TypedSize2D<T, U> {
type Output = TypedSize2D<T, U>;
#[inline]
fn mul(self, scale: T) -> TypedSize2D<T, U> {
TypedSize2D::new(self.width * scale, self.height * scale)
}
}
impl<T: Copy + Div<T, Output=T>, U> Div<T> for TypedSize2D<T, U> {
type Output = TypedSize2D<T, U>;
#[inline]
fn div(self, scale: T) -> TypedSize2D<T, U> {
TypedSize2D::new(self.width / scale, self.height / scale)
}
}
impl<T: Copy + Mul<T, Output=T>, U1, U2> Mul<ScaleFactor<T, U1, U2>> for TypedSize2D<T, U1> {
type Output = TypedSize2D<T, U2>;
#[inline]
fn mul(self, scale: ScaleFactor<T, U1, U2>) -> TypedSize2D<T, U2> {
TypedSize2D::new(self.width * scale.get(), self.height * scale.get())
}
}
impl<T: Copy + Div<T, Output=T>, U1, U2> Div<ScaleFactor<T, U1, U2>> for TypedSize2D<T, U2> {
type Output = TypedSize2D<T, U1>;
#[inline]
fn div(self, scale: ScaleFactor<T, U1, U2>) -> TypedSize2D<T, U1> {
TypedSize2D::new(self.width / scale.get(), self.height / scale.get())
}
}
impl<T: Copy, U> TypedSize2D<T, U> {
/// Returns self.width as a Length carrying the unit.
#[inline]
pub fn width_typed(&self) -> Length<T, U> { Length::new(self.width) }
/// Returns self.height as a Length carrying the unit.
#[inline]
pub fn height_typed(&self) -> Length<T, U> { Length::new(self.height) }
#[inline]
pub fn to_array(&self) -> [T; 2] { [self.width, self.height] }
/// Drop the units, preserving only the numeric value.
pub fn to_untyped(&self) -> Size2D<T> {
TypedSize2D::new(self.width, self.height)
}
/// Tag a unitless value with units.
pub fn from_untyped(p: &Size2D<T>) -> TypedSize2D<T, U> {
TypedSize2D::new(p.width, p.height)
}
}
impl<T: NumCast + Copy, Unit> TypedSize2D<T, Unit> {
/// Cast from one numeric representation to another, preserving the units.
///
/// When casting from floating point to integer coordinates, the decimals are truncated
/// as one would expect from a simple cast, but this behavior does not always make sense
/// geometrically. Consider using `round()`, `ceil()` or `floor()` before casting.
pub fn cast<NewT: NumCast + Copy>(&self) -> Option<TypedSize2D<NewT, Unit>> {
match (NumCast::from(self.width), NumCast::from(self.height)) {
(Some(w), Some(h)) => Some(TypedSize2D::new(w, h)),
_ => None
}
}
// Convenience functions for common casts
/// Cast into an `f32` size.
pub fn to_f32(&self) -> TypedSize2D<f32, Unit> {
self.cast().unwrap()
}
/// Cast into an `uint` size, truncating decimals if any.
///
/// When casting from floating point sizes, it is worth considering whether
/// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
/// the desired conversion behavior.
pub fn to_usize(&self) -> TypedSize2D<usize, Unit> {
self.cast().unwrap()
}
/// Cast into an `i32` size, truncating decimals if any.
///
/// When casting from floating point sizes, it is worth considering whether
/// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
/// the desired conversion behavior.
pub fn to_i32(&self) -> TypedSize2D<i32, Unit> {
self.cast().unwrap()
}
/// Cast into an `i64` size, truncating decimals if any.
///
/// When casting from floating point sizes, it is worth considering whether
/// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
/// the desired conversion behavior.
pub fn to_i64(&self) -> TypedSize2D<i64, Unit> {
self.cast().unwrap()
}
}
/// Shorthand for `TypedSize2D::new(w, h)`.
pub fn size2<T, U>(w: T, h: T) -> TypedSize2D<T, U> {
TypedSize2D::new(w, h)
}
#[cfg(test)]
mod size2d {
use super::Size2D;
#[test]
pub fn test_add() {
let p1 = Size2D::new(1.0, 2.0);
let p2 = Size2D::new(3.0, 4.0);
assert_eq!(p1 + p2, Size2D::new(4.0, 6.0));
let p1 = Size2D::new(1.0, 2.0);
let p2 = Size2D::new(0.0, 0.0);
assert_eq!(p1 + p2, Size2D::new(1.0, 2.0));
let p1 = Size2D::new(1.0, 2.0);
let p2 = Size2D::new(-3.0, -4.0);
assert_eq!(p1 + p2, Size2D::new(-2.0, -2.0));
let p1 = Size2D::new(0.0, 0.0);
let p2 = Size2D::new(0.0, 0.0);
assert_eq!(p1 + p2, Size2D::new(0.0, 0.0));
}
#[test]
pub fn test_sub() {
let p1 = Size2D::new(1.0, 2.0);
let p2 = Size2D::new(3.0, 4.0);
assert_eq!(p1 - p2, Size2D::new(-2.0, -2.0));
let p1 = Size2D::new(1.0, 2.0);
let p2 = Size2D::new(0.0, 0.0);
assert_eq!(p1 - p2, Size2D::new(1.0, 2.0));
let p1 = Size2D::new(1.0, 2.0);
let p2 = Size2D::new(-3.0, -4.0);
assert_eq!(p1 - p2, Size2D::new(4.0, 6.0));
let p1 = Size2D::new(0.0, 0.0);
let p2 = Size2D::new(0.0, 0.0);
assert_eq!(p1 - p2, Size2D::new(0.0, 0.0));
}
}

32
third_party/rust/euclid-0.13.0/src/trig.rs поставляемый
Просмотреть файл

@ -1,32 +0,0 @@
// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
/// Trait for basic trigonometry functions, so they can be used on generic numeric types
pub trait Trig {
fn sin(self) -> Self;
fn cos(self) -> Self;
fn tan(self) -> Self;
}
macro_rules! trig {
($ty:ty) => (
impl Trig for $ty {
#[inline]
fn sin(self) -> $ty { self.sin() }
#[inline]
fn cos(self) -> $ty { self.cos() }
#[inline]
fn tan(self) -> $ty { self.tan() }
}
)
}
trig!(f32);
trig!(f64);

Просмотреть файл

@ -1 +1 @@
{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".gitignore":"118514fd9c4958df0d25584cda4917186c46011569f55ef350530c1ad3fbdb48",".travis.yml":"56843ecfd2b71797b648b8e537623e84af3c638ea4b8472ed27c55f097bce3dc","COPYRIGHT":"ec82b96487e9e778ee610c7ab245162464782cfa1f555c2299333f8dbe5c036a","Cargo.toml":"596d3bcfc1684713b5c557e84b35b98250bebb3d4715e44741d227ab246a16ab","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3","README.md":"625bec69c76ce5423fdd05cfe46922b2680ec517f97c5854ce34798d1d8a9541","src/approxeq.rs":"6cf810ad389c73a27141a7a67454ed12d4b01c3c16605b9a7414b389bc0615dd","src/length.rs":"d7877ebc7ee2e85df2a1f5b9376011bdeeaa5cd7fa2fbdba0934df7456c0821e","src/lib.rs":"77b97c1d7889f037180b68344471ecf7c46b5412fe7c92504debc422c8739b61","src/macros.rs":"b63dabdb52df84ea170dc1dab5fe8d7a78c054562d1566bab416124708d2d7af","src/num.rs":"749b201289fc6663199160a2f9204e17925fd3053f8ab7779e7bfb377ad06227","src/point.rs":"42c1ee0997598d3482ac4c58f255e31b56a97a3a0aa1871b61f55074eecf1ae2","src/rect.rs":"e18811e3be9dba41976b611d52dbe13c5a27dc7db3e3e779daabeed7670b658f","src/scale_factor.rs":"61f979384316ae8a70e836b0d4b016ec5c26a952776037a65801152af4a247cb","src/side_offsets.rs":"fd95ffc9a74e9e84314875c388e763d0780486eb7f9034423e3a22048361e379","src/size.rs":"d9a6fb1f080a06e1332b2e804f8334e086e6d6f17a4288f35133d80b2e2da765","src/transform2d.rs":"4fe4fef7266b06b7790cd400d990ad02e6e605499a1a33c8e39b5e00364389ba","src/transform3d.rs":"cd8a08dd341fcea4c5b10e00d029424e382f3b0002dd8341f302be7f1c12c4fc","src/trig.rs":"ef290927af252ca90a29ba9f17158b591ed591604e66cb9df045dd47b9cfdca5","src/vector.rs":"c087700ad35c3e18e0f5722573f6a24ed2b0452e044c1f0bbb6466c993c560f1"},"package":"995b21c36b37e0f18ed9ba1714378a337e3ff19a6e5e952ea94b0f3dd4e12fbc"}
{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".gitignore":"118514fd9c4958df0d25584cda4917186c46011569f55ef350530c1ad3fbdb48",".travis.yml":"13d3e5a7bf83b04c8e8cfa14f0297bd8366d68391d977dd547f64707dffc275a","COPYRIGHT":"ec82b96487e9e778ee610c7ab245162464782cfa1f555c2299333f8dbe5c036a","Cargo.toml":"c91c98dc9510ef29a7ce0d7c78294f15cb139c9afecca38e5fda56b0a6984954","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3","README.md":"625bec69c76ce5423fdd05cfe46922b2680ec517f97c5854ce34798d1d8a9541","src/approxeq.rs":"6cf810ad389c73a27141a7a67454ed12d4b01c3c16605b9a7414b389bc0615dd","src/length.rs":"d7c6369f2fe2a17c845b57749bd48c471159f0571a7314d3bf90737d53f697d3","src/lib.rs":"e2e621f05304278d020429d0349acf7a4e7c7a9a72bd23fc0e55680267472ee9","src/macros.rs":"b63dabdb52df84ea170dc1dab5fe8d7a78c054562d1566bab416124708d2d7af","src/matrix2d.rs":"2361338f59813adf4eebaab76e4dd82be0fbfb9ff2461da8dd9ac9d43583b322","src/matrix4d.rs":"b8547bed6108b037192021c97169c00ad456120b849e9b7ac7bec40363edaec1","src/num.rs":"749b201289fc6663199160a2f9204e17925fd3053f8ab7779e7bfb377ad06227","src/point.rs":"dbf12a3ad35dc2502b7f2637856d8ee40f5a96e37ed00f3ee3272bf5752c060c","src/rect.rs":"0a255046dd11a6093d9a77e327e1df31802808536b4d87e4e3b80ff6b208de0f","src/scale_factor.rs":"df6dbd1f0f9f63210b92809f84a383dad982a74f09789cf22c7d8f9b62199d39","src/side_offsets.rs":"f85526a421ffda63ff01a3478d4162c8717eef68e942acfa2fd9a1adee02ebb2","src/size.rs":"ae1b647e300600b50a21dba8c1d915801782ebae82baeb5e49017e6d68a49b28","src/trig.rs":"ef290927af252ca90a29ba9f17158b591ed591604e66cb9df045dd47b9cfdca5"},"package":"6083f113c422ff9cd855a1cf6cc8ec0903606c0eb43a0c6a0ced3bdc9731e4c1"}

5
third_party/rust/euclid/.travis.yml поставляемый
Просмотреть файл

@ -1,9 +1,4 @@
language: rust
rust:
- 1.15.1
- stable
- beta
- nightly
notifications:
webhooks: http://build.servo.org:54856/travis

3
third_party/rust/euclid/Cargo.toml поставляемый
Просмотреть файл

@ -1,6 +1,6 @@
[package]
name = "euclid"
version = "0.14.4"
version = "0.13.0"
authors = ["The Servo Project Developers"]
description = "Geometry primitives"
documentation = "https://docs.rs/euclid/"
@ -14,6 +14,7 @@ unstable = []
[dependencies]
heapsize = "0.4"
rustc-serialize = "0.3.2"
num-traits = {version = "0.1.32", default-features = false}
log = "0.3.1"
serde = "0.9"

26
third_party/rust/euclid/src/length.rs поставляемый
Просмотреть файл

@ -13,7 +13,6 @@ use num::Zero;
use heapsize::HeapSizeOf;
use num_traits::{NumCast, Saturating};
use num::One;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::cmp::Ordering;
use std::ops::{Add, Sub, Mul, Div, Neg};
@ -35,6 +34,7 @@ use std::fmt;
// Uncomment the derive, and remove the macro call, once heapsize gets
// PhantomData<T> support.
#[repr(C)]
#[derive(RustcDecodable, RustcEncodable)]
pub struct Length<T, Unit>(pub T, PhantomData<Unit>);
impl<T: Clone, Unit> Clone for Length<T, Unit> {
@ -52,7 +52,7 @@ impl<Unit, T: HeapSizeOf> HeapSizeOf for Length<T, Unit> {
}
impl<Unit, T> Deserialize for Length<T, Unit> where T: Deserialize {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
fn deserialize<D>(deserializer: D) -> Result<Length<T, Unit>,D::Error>
where D: Deserializer {
Ok(Length(try!(Deserialize::deserialize(deserializer)), PhantomData))
}
@ -65,7 +65,7 @@ impl<T, Unit> Serialize for Length<T, Unit> where T: Serialize {
}
impl<T, Unit> Length<T, Unit> {
pub fn new(x: T) -> Self {
pub fn new(x: T) -> Length<T, Unit> {
Length(x, PhantomData)
}
}
@ -173,11 +173,11 @@ impl<Unit, T0: NumCast + Clone> Length<T0, Unit> {
}
impl<Unit, T: Clone + PartialEq> PartialEq for Length<T, Unit> {
fn eq(&self, other: &Self) -> bool { self.get().eq(&other.get()) }
fn eq(&self, other: &Length<T, Unit>) -> bool { self.get().eq(&other.get()) }
}
impl<Unit, T: Clone + PartialOrd> PartialOrd for Length<T, Unit> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
fn partial_cmp(&self, other: &Length<T, Unit>) -> Option<Ordering> {
self.get().partial_cmp(&other.get())
}
}
@ -185,27 +185,15 @@ impl<Unit, T: Clone + PartialOrd> PartialOrd for Length<T, Unit> {
impl<Unit, T: Clone + Eq> Eq for Length<T, Unit> {}
impl<Unit, T: Clone + Ord> Ord for Length<T, Unit> {
fn cmp(&self, other: &Self) -> Ordering { self.get().cmp(&other.get()) }
fn cmp(&self, other: &Length<T, Unit>) -> Ordering { self.get().cmp(&other.get()) }
}
impl<Unit, T: Zero> Zero for Length<T, Unit> {
fn zero() -> Self {
fn zero() -> Length<T, Unit> {
Length::new(Zero::zero())
}
}
impl<T, U> Length<T, U>
where T: Copy + One + Add<Output=T> + Sub<Output=T> + Mul<Output=T> {
/// Linearly interpolate between this length and another length.
///
/// `t` is expected to be between zero and one.
#[inline]
pub fn lerp(&self, other: Self, t: T) -> Self {
let one_t = T::one() - t;
Length::new(one_t * self.get() + t * other.get())
}
}
#[cfg(test)]
mod tests {
use super::Length;

60
third_party/rust/euclid/src/lib.rs поставляемый
Просмотреть файл

@ -59,6 +59,7 @@ extern crate heapsize;
#[cfg_attr(test, macro_use)]
extern crate log;
extern crate rustc_serialize;
extern crate serde;
#[cfg(test)]
@ -69,40 +70,34 @@ extern crate num_traits;
pub use length::Length;
pub use scale_factor::ScaleFactor;
pub use transform2d::{Transform2D, TypedTransform2D};
pub use transform3d::{Transform3D, TypedTransform3D};
pub use matrix2d::{Matrix2D, TypedMatrix2D};
pub use matrix4d::{Matrix4D, TypedMatrix4D};
pub use point::{
Point2D, TypedPoint2D, point2,
Point3D, TypedPoint3D, point3,
Point2D, TypedPoint2D,
Point3D, TypedPoint3D,
Point4D, TypedPoint4D,
};
pub use vector::{
Vector2D, TypedVector2D, vec2,
Vector3D, TypedVector3D, vec3,
};
pub use rect::{Rect, TypedRect, rect};
pub use rect::{Rect, TypedRect};
pub use side_offsets::{SideOffsets2D, TypedSideOffsets2D};
#[cfg(feature = "unstable")] pub use side_offsets::SideOffsets2DSimdI32;
pub use size::{Size2D, TypedSize2D, size2};
pub use trig::Trig;
pub use size::{Size2D, TypedSize2D};
pub mod approxeq;
pub mod num;
mod length;
pub mod length;
#[macro_use]
mod macros;
mod transform2d;
mod transform3d;
mod point;
mod rect;
mod scale_factor;
mod side_offsets;
mod size;
mod trig;
mod vector;
pub mod matrix2d;
pub mod matrix4d;
pub mod num;
pub mod point;
pub mod rect;
pub mod scale_factor;
pub mod side_offsets;
pub mod size;
pub mod trig;
/// The default unit.
#[derive(Clone, Copy)]
#[derive(Clone, Copy, RustcDecodable, RustcEncodable)]
pub struct UnknownUnit;
/// Unit for angles in radians.
@ -116,20 +111,3 @@ pub type Radians<T> = Length<T, Rad>;
/// A value in Degrees.
pub type Degrees<T> = Length<T, Deg>;
/// Temporary alias to facilitate the transition to the new naming scheme
#[deprecated]
pub type Matrix2D<T> = Transform2D<T>;
/// Temporary alias to facilitate the transition to the new naming scheme
#[deprecated]
pub type TypedMatrix2D<T, Src, Dst> = TypedTransform2D<T, Src, Dst>;
/// Temporary alias to facilitate the transition to the new naming scheme
#[deprecated]
pub type Matrix4D<T> = Transform3D<T>;
/// Temporary alias to facilitate the transition to the new naming scheme
#[deprecated]
pub type TypedMatrix4D<T, Src, Dst> = TypedTransform3D<T, Src, Dst>;

Просмотреть файл

Просмотреть файл

723
third_party/rust/euclid/src/point.rs поставляемый

Разница между файлами не показана из-за своего большого размера Загрузить разницу

90
third_party/rust/euclid/src/rect.rs поставляемый
Просмотреть файл

@ -12,7 +12,6 @@ use length::Length;
use scale_factor::ScaleFactor;
use num::*;
use point::TypedPoint2D;
use vector::TypedVector2D;
use size::TypedSize2D;
use heapsize::HeapSizeOf;
@ -20,10 +19,10 @@ use num_traits::NumCast;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::cmp::PartialOrd;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::ops::{Add, Sub, Mul, Div};
/// A 2d Rectangle optionally tagged with a unit.
#[derive(RustcDecodable, RustcEncodable)]
pub struct TypedRect<T, U = UnknownUnit> {
pub origin: TypedPoint2D<T, U>,
pub size: TypedSize2D<T, U>,
@ -55,22 +54,14 @@ impl<T: Serialize, U> Serialize for TypedRect<T, U> {
}
}
impl<T: Hash, U> Hash for TypedRect<T, U>
{
fn hash<H: Hasher>(&self, h: &mut H) {
self.origin.hash(h);
self.size.hash(h);
}
}
impl<T: Copy, U> Copy for TypedRect<T, U> {}
impl<T: Copy, U> Clone for TypedRect<T, U> {
fn clone(&self) -> Self { *self }
fn clone(&self) -> TypedRect<T, U> { *self }
}
impl<T: PartialEq, U> PartialEq<TypedRect<T, U>> for TypedRect<T, U> {
fn eq(&self, other: &Self) -> bool {
fn eq(&self, other: &TypedRect<T, U>) -> bool {
self.origin.eq(&other.origin) && self.size.eq(&other.size)
}
}
@ -91,7 +82,7 @@ impl<T: fmt::Display, U> fmt::Display for TypedRect<T, U> {
impl<T, U> TypedRect<T, U> {
/// Constructor.
pub fn new(origin: TypedPoint2D<T, U>, size: TypedSize2D<T, U>) -> Self {
pub fn new(origin: TypedPoint2D<T, U>, size: TypedSize2D<T, U>) -> TypedRect<T, U> {
TypedRect {
origin: origin,
size: size,
@ -102,7 +93,7 @@ impl<T, U> TypedRect<T, U> {
impl<T, U> TypedRect<T, U>
where T: Copy + Clone + Zero + PartialOrd + PartialEq + Add<T, Output=T> + Sub<T, Output=T> {
#[inline]
pub fn intersects(&self, other: &Self) -> bool {
pub fn intersects(&self, other: &TypedRect<T, U>) -> bool {
self.origin.x < other.origin.x + other.size.width &&
other.origin.x < self.origin.x + self.size.width &&
self.origin.y < other.origin.y + other.size.height &&
@ -150,7 +141,7 @@ where T: Copy + Clone + Zero + PartialOrd + PartialEq + Add<T, Output=T> + Sub<T
}
#[inline]
pub fn intersection(&self, other: &Self) -> Option<Self> {
pub fn intersection(&self, other: &TypedRect<T, U>) -> Option<TypedRect<T, U>> {
if !self.intersects(other) {
return None;
}
@ -164,11 +155,13 @@ where T: Copy + Clone + Zero + PartialOrd + PartialEq + Add<T, Output=T> + Sub<T
lower_right_y - upper_left.y)))
}
/// Returns the same rectangle, translated by a vector.
/// Translates the rect by a vector.
#[inline]
#[must_use]
pub fn translate(&self, by: &TypedVector2D<T, U>) -> Self {
Self::new(self.origin + *by, self.size)
pub fn translate(&self, other: &TypedPoint2D<T, U>) -> TypedRect<T, U> {
TypedRect::new(
TypedPoint2D::new(self.origin.x + other.x, self.origin.y + other.y),
self.size
)
}
/// Returns true if this rectangle contains the point. Points are considered
@ -184,15 +177,14 @@ where T: Copy + Clone + Zero + PartialOrd + PartialEq + Add<T, Output=T> + Sub<T
/// returns true if rect is empty, and always returns false if rect is
/// nonempty but this rectangle is empty.
#[inline]
pub fn contains_rect(&self, rect: &Self) -> bool {
pub fn contains_rect(&self, rect: &TypedRect<T, U>) -> bool {
rect.is_empty() ||
(self.min_x() <= rect.min_x() && rect.max_x() <= self.max_x() &&
self.min_y() <= rect.min_y() && rect.max_y() <= self.max_y())
}
#[inline]
#[must_use]
pub fn inflate(&self, width: T, height: T) -> Self {
pub fn inflate(&self, width: T, height: T) -> TypedRect<T, U> {
TypedRect::new(
TypedPoint2D::new(self.origin.x - width, self.origin.y - height),
TypedSize2D::new(self.size.width + width + width, self.size.height + height + height),
@ -200,8 +192,7 @@ where T: Copy + Clone + Zero + PartialOrd + PartialEq + Add<T, Output=T> + Sub<T
}
#[inline]
#[must_use]
pub fn inflate_typed(&self, width: Length<T, U>, height: Length<T, U>) -> Self {
pub fn inflate_typed(&self, width: Length<T, U>, height: Length<T, U>) -> TypedRect<T, U> {
self.inflate(width.get(), height.get())
}
@ -221,9 +212,8 @@ where T: Copy + Clone + Zero + PartialOrd + PartialEq + Add<T, Output=T> + Sub<T
}
#[inline]
#[must_use]
pub fn translate_by_size(&self, size: &TypedSize2D<T, U>) -> Self {
self.translate(&size.to_vector())
pub fn translate_by_size(&self, size: &TypedSize2D<T, U>) -> TypedRect<T, U> {
self.translate(&TypedPoint2D::new(size.width, size.height))
}
/// Returns the smallest rectangle containing the four points.
@ -252,24 +242,10 @@ where T: Copy + Clone + Zero + PartialOrd + PartialEq + Add<T, Output=T> + Sub<T
}
}
impl<T, U> TypedRect<T, U>
where T: Copy + One + Add<Output=T> + Sub<Output=T> + Mul<Output=T> {
/// Linearly interpolate between this rectangle and another rectange.
///
/// `t` is expected to be between zero and one.
#[inline]
pub fn lerp(&self, other: Self, t: T) -> Self {
Self::new(
self.origin.lerp(other.origin, t),
self.size.lerp(other.size, t),
)
}
}
impl<T, U> TypedRect<T, U>
where T: Copy + Clone + PartialOrd + Add<T, Output=T> + Sub<T, Output=T> + Zero {
#[inline]
pub fn union(&self, other: &Self) -> Self {
pub fn union(&self, other: &TypedRect<T, U>) -> TypedRect<T, U> {
if self.size == Zero::zero() {
return *other;
}
@ -292,7 +268,7 @@ where T: Copy + Clone + PartialOrd + Add<T, Output=T> + Sub<T, Output=T> + Zero
impl<T, U> TypedRect<T, U> {
#[inline]
pub fn scale<Scale: Copy>(&self, x: Scale, y: Scale) -> Self
pub fn scale<Scale: Copy>(&self, x: Scale, y: Scale) -> TypedRect<T, U>
where T: Copy + Clone + Mul<Scale, Output=T> {
TypedRect::new(
TypedPoint2D::new(self.origin.x * x, self.origin.y * y),
@ -303,9 +279,9 @@ impl<T, U> TypedRect<T, U> {
impl<T: Copy + PartialEq + Zero, U> TypedRect<T, U> {
/// Constructor, setting all sides to zero.
pub fn zero() -> Self {
pub fn zero() -> TypedRect<T, U> {
TypedRect::new(
TypedPoint2D::origin(),
TypedPoint2D::zero(),
TypedSize2D::zero(),
)
}
@ -326,17 +302,17 @@ pub fn max<T: Clone + PartialOrd>(x: T, y: T) -> T {
}
impl<T: Copy + Mul<T, Output=T>, U> Mul<T> for TypedRect<T, U> {
type Output = Self;
type Output = TypedRect<T, U>;
#[inline]
fn mul(self, scale: T) -> Self {
fn mul(self, scale: T) -> TypedRect<T, U> {
TypedRect::new(self.origin * scale, self.size * scale)
}
}
impl<T: Copy + Div<T, Output=T>, U> Div<T> for TypedRect<T, U> {
type Output = Self;
type Output = TypedRect<T, U>;
#[inline]
fn div(self, scale: T) -> Self {
fn div(self, scale: T) -> TypedRect<T, U> {
TypedRect::new(self.origin / scale, self.size / scale)
}
}
@ -393,7 +369,6 @@ impl<T: Floor + Ceil + Round + Add<T, Output=T> + Sub<T, Output=T>, U> TypedRect
/// avoid pixel rounding errors.
/// Note that this is *not* rounding to nearest integer if the values are negative.
/// They are always rounding as floor(n + 0.5).
#[must_use]
pub fn round(&self) -> Self {
let origin = self.origin.round();
let size = self.origin.add_size(&self.size).round() - origin;
@ -402,7 +377,6 @@ impl<T: Floor + Ceil + Round + Add<T, Output=T> + Sub<T, Output=T>, U> TypedRect
/// Return a rectangle with edges rounded to integer coordinates, such that
/// the original rectangle contains the resulting rectangle.
#[must_use]
pub fn round_in(&self) -> Self {
let origin = self.origin.ceil();
let size = self.origin.add_size(&self.size).floor() - origin;
@ -411,7 +385,6 @@ impl<T: Floor + Ceil + Round + Add<T, Output=T> + Sub<T, Output=T>, U> TypedRect
/// Return a rectangle with edges rounded to integer coordinates, such that
/// the original rectangle is contained in the resulting rectangle.
#[must_use]
pub fn round_out(&self) -> Self {
let origin = self.origin.floor();
let size = self.origin.add_size(&self.size).ceil() - origin;
@ -462,7 +435,6 @@ pub fn rect<T: Copy, U>(x: T, y: T, w: T, h: T) -> TypedRect<T, U> {
#[cfg(test)]
mod tests {
use point::Point2D;
use vector::vec2;
use size::Size2D;
use super::*;
@ -478,7 +450,7 @@ mod tests {
#[test]
fn test_translate() {
let p = Rect::new(Point2D::new(0u32, 0u32), Size2D::new(50u32, 40u32));
let pp = p.translate(&vec2(10,15));
let pp = p.translate(&Point2D::new(10,15));
assert!(pp.size.width == 50);
assert!(pp.size.height == 40);
@ -487,7 +459,7 @@ mod tests {
let r = Rect::new(Point2D::new(-10, -5), Size2D::new(50, 40));
let rr = r.translate(&vec2(0,-10));
let rr = r.translate(&Point2D::new(0,-10));
assert!(rr.size.width == 50);
assert!(rr.size.height == 40);
@ -590,10 +562,10 @@ mod tests {
let r = Rect::new(Point2D::new(-20.0, 15.0), Size2D::new(100.0, 200.0));
assert!(r.contains_rect(&r));
assert!(!r.contains_rect(&r.translate(&vec2( 0.1, 0.0))));
assert!(!r.contains_rect(&r.translate(&vec2(-0.1, 0.0))));
assert!(!r.contains_rect(&r.translate(&vec2( 0.0, 0.1))));
assert!(!r.contains_rect(&r.translate(&vec2( 0.0, -0.1))));
assert!(!r.contains_rect(&r.translate(&Point2D::new( 0.1, 0.0))));
assert!(!r.contains_rect(&r.translate(&Point2D::new(-0.1, 0.0))));
assert!(!r.contains_rect(&r.translate(&Point2D::new( 0.0, 0.1))));
assert!(!r.contains_rect(&r.translate(&Point2D::new( 0.0, -0.1))));
// Empty rectangles are always considered as contained in other rectangles,
// even if their origin is not.
let p = Point2D::new(1.0, 1.0);

5
third_party/rust/euclid/src/scale_factor.rs поставляемый
Просмотреть файл

@ -26,8 +26,8 @@ use std::marker::PhantomData;
/// may be types without values, such as empty enums. For example:
///
/// ```rust
/// use euclid::ScaleFactor;
/// use euclid::Length;
/// use euclid::scale_factor::ScaleFactor;
/// use euclid::length::Length;
/// enum Mm {};
/// enum Inch {};
///
@ -37,6 +37,7 @@ use std::marker::PhantomData;
/// let one_foot_in_mm: Length<f32, Mm> = one_foot * mm_per_inch;
/// ```
#[repr(C)]
#[derive(RustcDecodable, RustcEncodable)]
pub struct ScaleFactor<T, Src, Dst>(pub T, PhantomData<(Src, Dst)>);
impl<T: HeapSizeOf, Src, Dst> HeapSizeOf for ScaleFactor<T, Src, Dst> {

14
third_party/rust/euclid/src/side_offsets.rs поставляемый
Просмотреть файл

@ -43,7 +43,7 @@ pub type SideOffsets2D<T> = TypedSideOffsets2D<T, UnknownUnit>;
impl<T: Copy, U> TypedSideOffsets2D<T, U> {
/// Constructor taking a scalar for each side.
pub fn new(top: T, right: T, bottom: T, left: T) -> Self {
pub fn new(top: T, right: T, bottom: T, left: T) -> TypedSideOffsets2D<T, U> {
TypedSideOffsets2D {
top: top,
right: right,
@ -57,7 +57,7 @@ impl<T: Copy, U> TypedSideOffsets2D<T, U> {
pub fn from_lengths(top: Length<T, U>,
right: Length<T, U>,
bottom: Length<T, U>,
left: Length<T, U>) -> Self {
left: Length<T, U>) -> TypedSideOffsets2D<T, U> {
TypedSideOffsets2D::new(top.0, right.0, bottom.0, left.0)
}
@ -74,12 +74,12 @@ impl<T: Copy, U> TypedSideOffsets2D<T, U> {
pub fn left_typed(&self) -> Length<T, U> { Length::new(self.left) }
/// Constructor setting the same value to all sides, taking a scalar value directly.
pub fn new_all_same(all: T) -> Self {
pub fn new_all_same(all: T) -> TypedSideOffsets2D<T, U> {
TypedSideOffsets2D::new(all, all, all, all)
}
/// Constructor setting the same value to all sides, taking a typed Length.
pub fn from_length_all_same(all: Length<T, U>) -> Self {
pub fn from_length_all_same(all: Length<T, U>) -> TypedSideOffsets2D<T, U> {
TypedSideOffsets2D::new_all_same(all.0)
}
}
@ -103,8 +103,8 @@ impl<T, U> TypedSideOffsets2D<T, U> where T: Add<T, Output=T> + Copy {
}
impl<T, U> Add for TypedSideOffsets2D<T, U> where T : Copy + Add<T, Output=T> {
type Output = Self;
fn add(self, other: Self) -> Self {
type Output = TypedSideOffsets2D<T, U>;
fn add(self, other: TypedSideOffsets2D<T, U>) -> TypedSideOffsets2D<T, U> {
TypedSideOffsets2D::new(
self.top + other.top,
self.right + other.right,
@ -116,7 +116,7 @@ impl<T, U> Add for TypedSideOffsets2D<T, U> where T : Copy + Add<T, Output=T> {
impl<T: Copy + Zero, U> TypedSideOffsets2D<T, U> {
/// Constructor, setting all sides to zero.
pub fn zero() -> Self {
pub fn zero() -> TypedSideOffsets2D<T, U> {
TypedSideOffsets2D::new(
Zero::zero(),
Zero::zero(),

46
third_party/rust/euclid/src/size.rs поставляемый
Просмотреть файл

@ -10,7 +10,6 @@
use super::UnknownUnit;
use length::Length;
use scale_factor::ScaleFactor;
use vector::{TypedVector2D, vec2};
use num::*;
use num_traits::NumCast;
@ -20,6 +19,7 @@ use std::marker::PhantomData;
/// A 2d size tagged with a unit.
define_matrix! {
#[derive(RustcDecodable, RustcEncodable)]
pub struct TypedSize2D<T, U> {
pub width: T,
pub height: T,
@ -45,7 +45,7 @@ impl<T: fmt::Display, U> fmt::Display for TypedSize2D<T, U> {
impl<T, U> TypedSize2D<T, U> {
/// Constructor taking scalar values.
pub fn new(width: T, height: T) -> Self {
pub fn new(width: T, height: T) -> TypedSize2D<T, U> {
TypedSize2D {
width: width,
height: height,
@ -56,7 +56,7 @@ impl<T, U> TypedSize2D<T, U> {
impl<T: Clone, U> TypedSize2D<T, U> {
/// Constructor taking scalar strongly typed lengths.
pub fn from_lengths(width: Length<T, U>, height: Length<T, U>) -> Self {
pub fn from_lengths(width: Length<T, U>, height: Length<T, U>) -> TypedSize2D<T, U> {
TypedSize2D::new(width.get(), height.get())
}
}
@ -89,15 +89,15 @@ impl<T: Floor, U> TypedSize2D<T, U> {
}
impl<T: Copy + Add<T, Output=T>, U> Add for TypedSize2D<T, U> {
type Output = Self;
fn add(self, other: Self) -> Self {
type Output = TypedSize2D<T, U>;
fn add(self, other: TypedSize2D<T, U>) -> TypedSize2D<T, U> {
TypedSize2D::new(self.width + other.width, self.height + other.height)
}
}
impl<T: Copy + Sub<T, Output=T>, U> Sub for TypedSize2D<T, U> {
type Output = Self;
fn sub(self, other: Self) -> Self {
type Output = TypedSize2D<T, U>;
fn sub(self, other: TypedSize2D<T, U>) -> TypedSize2D<T, U> {
TypedSize2D::new(self.width - other.width, self.height - other.height)
}
}
@ -106,23 +106,8 @@ impl<T: Copy + Clone + Mul<T, Output=U>, U> TypedSize2D<T, U> {
pub fn area(&self) -> U { self.width * self.height }
}
impl<T, U> TypedSize2D<T, U>
where T: Copy + One + Add<Output=T> + Sub<Output=T> + Mul<Output=T> {
/// Linearly interpolate between this size and another size.
///
/// `t` is expected to be between zero and one.
#[inline]
pub fn lerp(&self, other: Self, t: T) -> Self {
let one_t = T::one() - t;
size2(
one_t * self.width + t * other.width,
one_t * self.height + t * other.height,
)
}
}
impl<T: Zero, U> TypedSize2D<T, U> {
pub fn zero() -> Self {
pub fn zero() -> TypedSize2D<T, U> {
TypedSize2D::new(
Zero::zero(),
Zero::zero(),
@ -131,7 +116,7 @@ impl<T: Zero, U> TypedSize2D<T, U> {
}
impl<T: Zero, U> Zero for TypedSize2D<T, U> {
fn zero() -> Self {
fn zero() -> TypedSize2D<T, U> {
TypedSize2D::new(
Zero::zero(),
Zero::zero(),
@ -140,17 +125,17 @@ impl<T: Zero, U> Zero for TypedSize2D<T, U> {
}
impl<T: Copy + Mul<T, Output=T>, U> Mul<T> for TypedSize2D<T, U> {
type Output = Self;
type Output = TypedSize2D<T, U>;
#[inline]
fn mul(self, scale: T) -> Self {
fn mul(self, scale: T) -> TypedSize2D<T, U> {
TypedSize2D::new(self.width * scale, self.height * scale)
}
}
impl<T: Copy + Div<T, Output=T>, U> Div<T> for TypedSize2D<T, U> {
type Output = Self;
type Output = TypedSize2D<T, U>;
#[inline]
fn div(self, scale: T) -> Self {
fn div(self, scale: T) -> TypedSize2D<T, U> {
TypedSize2D::new(self.width / scale, self.height / scale)
}
}
@ -183,16 +168,13 @@ impl<T: Copy, U> TypedSize2D<T, U> {
#[inline]
pub fn to_array(&self) -> [T; 2] { [self.width, self.height] }
#[inline]
pub fn to_vector(&self) -> TypedVector2D<T, U> { vec2(self.width, self.height) }
/// Drop the units, preserving only the numeric value.
pub fn to_untyped(&self) -> Size2D<T> {
TypedSize2D::new(self.width, self.height)
}
/// Tag a unitless value with units.
pub fn from_untyped(p: &Size2D<T>) -> Self {
pub fn from_untyped(p: &Size2D<T>) -> TypedSize2D<T, U> {
TypedSize2D::new(p.width, p.height)
}
}

488
third_party/rust/euclid/src/transform2d.rs поставляемый
Просмотреть файл

@ -1,488 +0,0 @@
// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use super::{UnknownUnit, Radians};
use num::{One, Zero};
use point::TypedPoint2D;
use vector::{TypedVector2D, vec2};
use rect::TypedRect;
use std::ops::{Add, Mul, Div, Sub};
use std::marker::PhantomData;
use approxeq::ApproxEq;
use trig::Trig;
use std::fmt;
define_matrix! {
/// A 2d transform stored as a 2 by 3 matrix in row-major order in memory.
///
/// Transforms can be parametrized over the source and destination units, to describe a
/// transformation from a space to another.
/// For example, `TypedTransform2D<f32, WordSpace, ScreenSpace>::transform_point4d`
/// takes a `TypedPoint2D<f32, WordSpace>` and returns a `TypedPoint2D<f32, ScreenSpace>`.
///
/// Transforms expose a set of convenience methods for pre- and post-transformations.
/// A pre-transformation corresponds to adding an operation that is applied before
/// the rest of the transformation, while a post-transformation adds an operation
/// that is applied after.
pub struct TypedTransform2D<T, Src, Dst> {
pub m11: T, pub m12: T,
pub m21: T, pub m22: T,
pub m31: T, pub m32: T,
}
}
/// The default 2d transform type with no units.
pub type Transform2D<T> = TypedTransform2D<T, UnknownUnit, UnknownUnit>;
impl<T: Copy, Src, Dst> TypedTransform2D<T, Src, Dst> {
/// Create a transform specifying its matrix elements in row-major order.
pub fn row_major(m11: T, m12: T, m21: T, m22: T, m31: T, m32: T) -> Self {
TypedTransform2D {
m11: m11, m12: m12,
m21: m21, m22: m22,
m31: m31, m32: m32,
_unit: PhantomData,
}
}
/// Create a transform specifying its matrix elements in column-major order.
pub fn column_major(m11: T, m21: T, m31: T, m12: T, m22: T, m32: T) -> Self {
TypedTransform2D {
m11: m11, m12: m12,
m21: m21, m22: m22,
m31: m31, m32: m32,
_unit: PhantomData,
}
}
/// Returns an array containing this transform's terms in row-major order (the order
/// in which the transform is actually laid out in memory).
pub fn to_row_major_array(&self) -> [T; 6] {
[
self.m11, self.m12,
self.m21, self.m22,
self.m31, self.m32
]
}
/// Returns an array containing this transform's terms in column-major order.
pub fn to_column_major_array(&self) -> [T; 6] {
[
self.m11, self.m21, self.m31,
self.m12, self.m22, self.m32
]
}
/// Returns an array containing this transform's 3 rows in (in row-major order)
/// as arrays.
///
/// This is a convenience method to interface with other libraries like glium.
pub fn to_row_arrays(&self) -> [[T; 2]; 3] {
[
[self.m11, self.m12],
[self.m21, self.m22],
[self.m31, self.m32],
]
}
/// Creates a transform from an array of 6 elements in row-major order.
pub fn from_row_major_array(array: [T; 6]) -> Self {
Self::row_major(
array[0], array[1],
array[2], array[3],
array[4], array[5],
)
}
/// Creates a transform from 3 rows of 2 elements (row-major order).
pub fn from_row_arrays(array: [[T; 2]; 3]) -> Self {
Self::row_major(
array[0][0], array[0][1],
array[1][0], array[1][1],
array[2][0], array[2][1],
)
}
/// Drop the units, preserving only the numeric value.
pub fn to_untyped(&self) -> Transform2D<T> {
Transform2D::row_major(
self.m11, self.m12,
self.m21, self.m22,
self.m31, self.m32
)
}
/// Tag a unitless value with units.
pub fn from_untyped(p: &Transform2D<T>) -> Self {
TypedTransform2D::row_major(
p.m11, p.m12,
p.m21, p.m22,
p.m31, p.m32
)
}
}
impl<T, Src, Dst> TypedTransform2D<T, Src, Dst>
where T: Copy +
PartialEq +
One + Zero {
pub fn identity() -> Self {
let (_0, _1) = (Zero::zero(), One::one());
TypedTransform2D::row_major(
_1, _0,
_0, _1,
_0, _0
)
}
// Intentional not public, because it checks for exact equivalence
// while most consumers will probably want some sort of approximate
// equivalence to deal with floating-point errors.
fn is_identity(&self) -> bool {
*self == TypedTransform2D::identity()
}
}
impl<T, Src, Dst> TypedTransform2D<T, Src, Dst>
where T: Copy + Clone +
Add<T, Output=T> +
Mul<T, Output=T> +
Div<T, Output=T> +
Sub<T, Output=T> +
Trig +
PartialOrd +
One + Zero {
/// Returns the multiplication of the two matrices such that mat's transformation
/// applies after self's transformation.
#[must_use]
pub fn post_mul<NewDst>(&self, mat: &TypedTransform2D<T, Dst, NewDst>) -> TypedTransform2D<T, Src, NewDst> {
TypedTransform2D::row_major(
self.m11 * mat.m11 + self.m12 * mat.m21,
self.m11 * mat.m12 + self.m12 * mat.m22,
self.m21 * mat.m11 + self.m22 * mat.m21,
self.m21 * mat.m12 + self.m22 * mat.m22,
self.m31 * mat.m11 + self.m32 * mat.m21 + mat.m31,
self.m31 * mat.m12 + self.m32 * mat.m22 + mat.m32,
)
}
/// Returns the multiplication of the two matrices such that mat's transformation
/// applies before self's transformation.
#[must_use]
pub fn pre_mul<NewSrc>(&self, mat: &TypedTransform2D<T, NewSrc, Src>) -> TypedTransform2D<T, NewSrc, Dst> {
mat.post_mul(self)
}
/// Returns a translation transform.
pub fn create_translation(x: T, y: T) -> Self {
let (_0, _1): (T, T) = (Zero::zero(), One::one());
TypedTransform2D::row_major(
_1, _0,
_0, _1,
x, y
)
}
/// Applies a translation after self's transformation and returns the resulting transform.
#[must_use]
pub fn post_translate(&self, v: TypedVector2D<T, Dst>) -> Self {
self.post_mul(&TypedTransform2D::create_translation(v.x, v.y))
}
/// Applies a translation before self's transformation and returns the resulting transform.
#[must_use]
pub fn pre_translate(&self, v: TypedVector2D<T, Src>) -> Self {
self.pre_mul(&TypedTransform2D::create_translation(v.x, v.y))
}
/// Returns a scale transform.
pub fn create_scale(x: T, y: T) -> Self {
let _0 = Zero::zero();
TypedTransform2D::row_major(
x, _0,
_0, y,
_0, _0
)
}
/// Applies a scale after self's transformation and returns the resulting transform.
#[must_use]
pub fn post_scale(&self, x: T, y: T) -> Self {
self.post_mul(&TypedTransform2D::create_scale(x, y))
}
/// Applies a scale before self's transformation and returns the resulting transform.
#[must_use]
pub fn pre_scale(&self, x: T, y: T) -> Self {
TypedTransform2D::row_major(
self.m11 * x, self.m12,
self.m21, self.m22 * y,
self.m31, self.m32
)
}
/// Returns a rotation transform.
pub fn create_rotation(theta: Radians<T>) -> Self {
let _0 = Zero::zero();
let cos = theta.get().cos();
let sin = theta.get().sin();
TypedTransform2D::row_major(
cos, _0 - sin,
sin, cos,
_0, _0
)
}
/// Applies a rotation after self's transformation and returns the resulting transform.
#[must_use]
pub fn post_rotate(&self, theta: Radians<T>) -> Self {
self.post_mul(&TypedTransform2D::create_rotation(theta))
}
/// Applies a rotation after self's transformation and returns the resulting transform.
#[must_use]
pub fn pre_rotate(&self, theta: Radians<T>) -> Self {
self.pre_mul(&TypedTransform2D::create_rotation(theta))
}
/// Returns the given point transformed by this transform.
#[inline]
#[must_use]
pub fn transform_point(&self, point: &TypedPoint2D<T, Src>) -> TypedPoint2D<T, Dst> {
TypedPoint2D::new(point.x * self.m11 + point.y * self.m21 + self.m31,
point.x * self.m12 + point.y * self.m22 + self.m32)
}
/// Returns the given vector transformed by this matrix.
#[inline]
#[must_use]
pub fn transform_vector(&self, vec: &TypedVector2D<T, Src>) -> TypedVector2D<T, Dst> {
vec2(vec.x * self.m11 + vec.y * self.m21,
vec.x * self.m12 + vec.y * self.m22)
}
/// Returns a rectangle that encompasses the result of transforming the given rectangle by this
/// transform.
#[inline]
#[must_use]
pub fn transform_rect(&self, rect: &TypedRect<T, Src>) -> TypedRect<T, Dst> {
TypedRect::from_points(&[
self.transform_point(&rect.origin),
self.transform_point(&rect.top_right()),
self.transform_point(&rect.bottom_left()),
self.transform_point(&rect.bottom_right()),
])
}
/// Computes and returns the determinant of this transform.
pub fn determinant(&self) -> T {
self.m11 * self.m22 - self.m12 * self.m21
}
/// Returns the inverse transform if possible.
#[must_use]
pub fn inverse(&self) -> Option<TypedTransform2D<T, Dst, Src>> {
let det = self.determinant();
let _0: T = Zero::zero();
let _1: T = One::one();
if det == _0 {
return None;
}
let inv_det = _1 / det;
Some(TypedTransform2D::row_major(
inv_det * self.m22,
inv_det * (_0 - self.m12),
inv_det * (_0 - self.m21),
inv_det * self.m11,
inv_det * (self.m21 * self.m32 - self.m22 * self.m31),
inv_det * (self.m31 * self.m12 - self.m11 * self.m32),
))
}
/// Returns the same transform with a different destination unit.
#[inline]
pub fn with_destination<NewDst>(&self) -> TypedTransform2D<T, Src, NewDst> {
TypedTransform2D::row_major(
self.m11, self.m12,
self.m21, self.m22,
self.m31, self.m32,
)
}
/// Returns the same transform with a different source unit.
#[inline]
pub fn with_source<NewSrc>(&self) -> TypedTransform2D<T, NewSrc, Dst> {
TypedTransform2D::row_major(
self.m11, self.m12,
self.m21, self.m22,
self.m31, self.m32,
)
}
}
impl<T: ApproxEq<T>, Src, Dst> TypedTransform2D<T, Src, Dst> {
pub fn approx_eq(&self, other: &Self) -> bool {
self.m11.approx_eq(&other.m11) && self.m12.approx_eq(&other.m12) &&
self.m21.approx_eq(&other.m21) && self.m22.approx_eq(&other.m22) &&
self.m31.approx_eq(&other.m31) && self.m32.approx_eq(&other.m32)
}
}
impl<T: Copy + fmt::Debug, Src, Dst> fmt::Debug for TypedTransform2D<T, Src, Dst>
where T: Copy + fmt::Debug +
PartialEq +
One + Zero {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.is_identity() {
write!(f, "[I]")
} else {
self.to_row_major_array().fmt(f)
}
}
}
#[cfg(test)]
mod test {
use super::*;
use approxeq::ApproxEq;
use point::Point2D;
use Radians;
use std::f32::consts::FRAC_PI_2;
type Mat = Transform2D<f32>;
fn rad(v: f32) -> Radians<f32> { Radians::new(v) }
#[test]
pub fn test_translation() {
let t1 = Mat::create_translation(1.0, 2.0);
let t2 = Mat::identity().pre_translate(vec2(1.0, 2.0));
let t3 = Mat::identity().post_translate(vec2(1.0, 2.0));
assert_eq!(t1, t2);
assert_eq!(t1, t3);
assert_eq!(t1.transform_point(&Point2D::new(1.0, 1.0)), Point2D::new(2.0, 3.0));
assert_eq!(t1.post_mul(&t1), Mat::create_translation(2.0, 4.0));
}
#[test]
pub fn test_rotation() {
let r1 = Mat::create_rotation(rad(FRAC_PI_2));
let r2 = Mat::identity().pre_rotate(rad(FRAC_PI_2));
let r3 = Mat::identity().post_rotate(rad(FRAC_PI_2));
assert_eq!(r1, r2);
assert_eq!(r1, r3);
assert!(r1.transform_point(&Point2D::new(1.0, 2.0)).approx_eq(&Point2D::new(2.0, -1.0)));
assert!(r1.post_mul(&r1).approx_eq(&Mat::create_rotation(rad(FRAC_PI_2*2.0))));
}
#[test]
pub fn test_scale() {
let s1 = Mat::create_scale(2.0, 3.0);
let s2 = Mat::identity().pre_scale(2.0, 3.0);
let s3 = Mat::identity().post_scale(2.0, 3.0);
assert_eq!(s1, s2);
assert_eq!(s1, s3);
assert!(s1.transform_point(&Point2D::new(2.0, 2.0)).approx_eq(&Point2D::new(4.0, 6.0)));
}
#[test]
fn test_column_major() {
assert_eq!(
Mat::row_major(
1.0, 2.0,
3.0, 4.0,
5.0, 6.0
),
Mat::column_major(
1.0, 3.0, 5.0,
2.0, 4.0, 6.0,
)
);
}
#[test]
pub fn test_inverse_simple() {
let m1 = Mat::identity();
let m2 = m1.inverse().unwrap();
assert!(m1.approx_eq(&m2));
}
#[test]
pub fn test_inverse_scale() {
let m1 = Mat::create_scale(1.5, 0.3);
let m2 = m1.inverse().unwrap();
assert!(m1.pre_mul(&m2).approx_eq(&Mat::identity()));
}
#[test]
pub fn test_inverse_translate() {
let m1 = Mat::create_translation(-132.0, 0.3);
let m2 = m1.inverse().unwrap();
assert!(m1.pre_mul(&m2).approx_eq(&Mat::identity()));
}
#[test]
fn test_inverse_none() {
assert!(Mat::create_scale(2.0, 0.0).inverse().is_none());
assert!(Mat::create_scale(2.0, 2.0).inverse().is_some());
}
#[test]
pub fn test_pre_post() {
let m1 = Transform2D::identity().post_scale(1.0, 2.0).post_translate(vec2(1.0, 2.0));
let m2 = Transform2D::identity().pre_translate(vec2(1.0, 2.0)).pre_scale(1.0, 2.0);
assert!(m1.approx_eq(&m2));
let r = Mat::create_rotation(rad(FRAC_PI_2));
let t = Mat::create_translation(2.0, 3.0);
let a = Point2D::new(1.0, 1.0);
assert!(r.post_mul(&t).transform_point(&a).approx_eq(&Point2D::new(3.0, 2.0)));
assert!(t.post_mul(&r).transform_point(&a).approx_eq(&Point2D::new(4.0, -3.0)));
assert!(t.post_mul(&r).transform_point(&a).approx_eq(&r.transform_point(&t.transform_point(&a))));
assert!(r.pre_mul(&t).transform_point(&a).approx_eq(&Point2D::new(4.0, -3.0)));
assert!(t.pre_mul(&r).transform_point(&a).approx_eq(&Point2D::new(3.0, 2.0)));
assert!(t.pre_mul(&r).transform_point(&a).approx_eq(&t.transform_point(&r.transform_point(&a))));
}
#[test]
fn test_size_of() {
use std::mem::size_of;
assert_eq!(size_of::<Transform2D<f32>>(), 6*size_of::<f32>());
assert_eq!(size_of::<Transform2D<f64>>(), 6*size_of::<f64>());
}
#[test]
pub fn test_is_identity() {
let m1 = Transform2D::identity();
assert!(m1.is_identity());
let m2 = m1.post_translate(vec2(0.1, 0.0));
assert!(!m2.is_identity());
}
#[test]
pub fn test_transform_vector() {
// Translation does not apply to vectors.
let m1 = Mat::create_translation(1.0, 1.0);
let v1 = vec2(10.0, -10.0);
assert_eq!(v1, m1.transform_vector(&v1));
}
}

888
third_party/rust/euclid/src/transform3d.rs поставляемый
Просмотреть файл

@ -1,888 +0,0 @@
// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use super::{UnknownUnit, Radians};
use approxeq::ApproxEq;
use trig::Trig;
use point::{TypedPoint2D, TypedPoint3D, point2, point3};
use vector::{TypedVector2D, TypedVector3D, vec2, vec3};
use rect::TypedRect;
use transform2d::TypedTransform2D;
use scale_factor::ScaleFactor;
use num::{One, Zero};
use std::ops::{Add, Mul, Sub, Div, Neg};
use std::marker::PhantomData;
use std::fmt;
define_matrix! {
/// A 3d transform stored as a 4 by 4 matrix in row-major order in memory.
///
/// Transforms can be parametrized over the source and destination units, to describe a
/// transformation from a space to another.
/// For example, `TypedTransform3D<f32, WordSpace, ScreenSpace>::transform_point3d`
/// takes a `TypedPoint3D<f32, WordSpace>` and returns a `TypedPoint3D<f32, ScreenSpace>`.
///
/// Transforms expose a set of convenience methods for pre- and post-transformations.
/// A pre-transformation corresponds to adding an operation that is applied before
/// the rest of the transformation, while a post-transformation adds an operation
/// that is applied after.
pub struct TypedTransform3D<T, Src, Dst> {
pub m11: T, pub m12: T, pub m13: T, pub m14: T,
pub m21: T, pub m22: T, pub m23: T, pub m24: T,
pub m31: T, pub m32: T, pub m33: T, pub m34: T,
pub m41: T, pub m42: T, pub m43: T, pub m44: T,
}
}
/// The default 4d transform type with no units.
pub type Transform3D<T> = TypedTransform3D<T, UnknownUnit, UnknownUnit>;
impl<T, Src, Dst> TypedTransform3D<T, Src, Dst> {
/// Create a transform specifying its components in row-major order.
///
/// For example, the translation terms m41, m42, m43 on the last row with the
/// row-major convention) are the 13rd, 14th and 15th parameters.
#[inline]
pub fn row_major(
m11: T, m12: T, m13: T, m14: T,
m21: T, m22: T, m23: T, m24: T,
m31: T, m32: T, m33: T, m34: T,
m41: T, m42: T, m43: T, m44: T)
-> Self {
TypedTransform3D {
m11: m11, m12: m12, m13: m13, m14: m14,
m21: m21, m22: m22, m23: m23, m24: m24,
m31: m31, m32: m32, m33: m33, m34: m34,
m41: m41, m42: m42, m43: m43, m44: m44,
_unit: PhantomData,
}
}
/// Create a transform specifying its components in column-major order.
///
/// For example, the translation terms m41, m42, m43 on the last column with the
/// column-major convention) are the 4th, 8th and 12nd parameters.
#[inline]
pub fn column_major(
m11: T, m21: T, m31: T, m41: T,
m12: T, m22: T, m32: T, m42: T,
m13: T, m23: T, m33: T, m43: T,
m14: T, m24: T, m34: T, m44: T)
-> Self {
TypedTransform3D {
m11: m11, m12: m12, m13: m13, m14: m14,
m21: m21, m22: m22, m23: m23, m24: m24,
m31: m31, m32: m32, m33: m33, m34: m34,
m41: m41, m42: m42, m43: m43, m44: m44,
_unit: PhantomData,
}
}
}
impl <T, Src, Dst> TypedTransform3D<T, Src, Dst>
where T: Copy + Clone +
PartialEq +
One + Zero {
#[inline]
pub fn identity() -> Self {
let (_0, _1): (T, T) = (Zero::zero(), One::one());
TypedTransform3D::row_major(
_1, _0, _0, _0,
_0, _1, _0, _0,
_0, _0, _1, _0,
_0, _0, _0, _1
)
}
// Intentional not public, because it checks for exact equivalence
// while most consumers will probably want some sort of approximate
// equivalence to deal with floating-point errors.
#[inline]
fn is_identity(&self) -> bool {
*self == TypedTransform3D::identity()
}
}
impl <T, Src, Dst> TypedTransform3D<T, Src, Dst>
where T: Copy + Clone +
Add<T, Output=T> +
Sub<T, Output=T> +
Mul<T, Output=T> +
Div<T, Output=T> +
Neg<Output=T> +
ApproxEq<T> +
PartialOrd +
Trig +
One + Zero {
/// Create a 4 by 4 transform representing a 2d transformation, specifying its components
/// in row-major order.
#[inline]
pub fn row_major_2d(m11: T, m12: T, m21: T, m22: T, m41: T, m42: T) -> Self {
let (_0, _1): (T, T) = (Zero::zero(), One::one());
TypedTransform3D::row_major(
m11, m12, _0, _0,
m21, m22, _0, _0,
_0, _0, _1, _0,
m41, m42, _0, _1
)
}
/// Create an orthogonal projection transform.
pub fn ortho(left: T, right: T,
bottom: T, top: T,
near: T, far: T) -> Self {
let tx = -((right + left) / (right - left));
let ty = -((top + bottom) / (top - bottom));
let tz = -((far + near) / (far - near));
let (_0, _1): (T, T) = (Zero::zero(), One::one());
let _2 = _1 + _1;
TypedTransform3D::row_major(
_2 / (right - left), _0 , _0 , _0,
_0 , _2 / (top - bottom), _0 , _0,
_0 , _0 , -_2 / (far - near), _0,
tx , ty , tz , _1
)
}
/// Returns true if this transform can be represented with a TypedTransform2D.
///
/// See https://drafts.csswg.org/css-transforms/#2d-transform
#[inline]
pub fn is_2d(&self) -> bool {
let (_0, _1): (T, T) = (Zero::zero(), One::one());
self.m31 == _0 && self.m32 == _0 &&
self.m13 == _0 && self.m23 == _0 &&
self.m43 == _0 && self.m14 == _0 &&
self.m24 == _0 && self.m34 == _0 &&
self.m33 == _1 && self.m44 == _1
}
/// Create a 2D transform picking the relevent terms from this transform.
///
/// This method assumes that self represents a 2d transformation, callers
/// should check that self.is_2d() returns true beforehand.
pub fn to_2d(&self) -> TypedTransform2D<T, Src, Dst> {
TypedTransform2D::row_major(
self.m11, self.m12,
self.m21, self.m22,
self.m41, self.m42
)
}
pub fn approx_eq(&self, other: &Self) -> bool {
self.m11.approx_eq(&other.m11) && self.m12.approx_eq(&other.m12) &&
self.m13.approx_eq(&other.m13) && self.m14.approx_eq(&other.m14) &&
self.m21.approx_eq(&other.m21) && self.m22.approx_eq(&other.m22) &&
self.m23.approx_eq(&other.m23) && self.m24.approx_eq(&other.m24) &&
self.m31.approx_eq(&other.m31) && self.m32.approx_eq(&other.m32) &&
self.m33.approx_eq(&other.m33) && self.m34.approx_eq(&other.m34) &&
self.m41.approx_eq(&other.m41) && self.m42.approx_eq(&other.m42) &&
self.m43.approx_eq(&other.m43) && self.m44.approx_eq(&other.m44)
}
/// Returns the same transform with a different destination unit.
#[inline]
pub fn with_destination<NewDst>(&self) -> TypedTransform3D<T, Src, NewDst> {
TypedTransform3D::row_major(
self.m11, self.m12, self.m13, self.m14,
self.m21, self.m22, self.m23, self.m24,
self.m31, self.m32, self.m33, self.m34,
self.m41, self.m42, self.m43, self.m44,
)
}
/// Returns the same transform with a different source unit.
#[inline]
pub fn with_source<NewSrc>(&self) -> TypedTransform3D<T, NewSrc, Dst> {
TypedTransform3D::row_major(
self.m11, self.m12, self.m13, self.m14,
self.m21, self.m22, self.m23, self.m24,
self.m31, self.m32, self.m33, self.m34,
self.m41, self.m42, self.m43, self.m44,
)
}
/// Drop the units, preserving only the numeric value.
#[inline]
pub fn to_untyped(&self) -> Transform3D<T> {
Transform3D::row_major(
self.m11, self.m12, self.m13, self.m14,
self.m21, self.m22, self.m23, self.m24,
self.m31, self.m32, self.m33, self.m34,
self.m41, self.m42, self.m43, self.m44,
)
}
/// Tag a unitless value with units.
#[inline]
pub fn from_untyped(m: &Transform3D<T>) -> Self {
TypedTransform3D::row_major(
m.m11, m.m12, m.m13, m.m14,
m.m21, m.m22, m.m23, m.m24,
m.m31, m.m32, m.m33, m.m34,
m.m41, m.m42, m.m43, m.m44,
)
}
/// Returns the multiplication of the two matrices such that mat's transformation
/// applies after self's transformation.
pub fn post_mul<NewDst>(&self, mat: &TypedTransform3D<T, Dst, NewDst>) -> TypedTransform3D<T, Src, NewDst> {
TypedTransform3D::row_major(
self.m11 * mat.m11 + self.m12 * mat.m21 + self.m13 * mat.m31 + self.m14 * mat.m41,
self.m11 * mat.m12 + self.m12 * mat.m22 + self.m13 * mat.m32 + self.m14 * mat.m42,
self.m11 * mat.m13 + self.m12 * mat.m23 + self.m13 * mat.m33 + self.m14 * mat.m43,
self.m11 * mat.m14 + self.m12 * mat.m24 + self.m13 * mat.m34 + self.m14 * mat.m44,
self.m21 * mat.m11 + self.m22 * mat.m21 + self.m23 * mat.m31 + self.m24 * mat.m41,
self.m21 * mat.m12 + self.m22 * mat.m22 + self.m23 * mat.m32 + self.m24 * mat.m42,
self.m21 * mat.m13 + self.m22 * mat.m23 + self.m23 * mat.m33 + self.m24 * mat.m43,
self.m21 * mat.m14 + self.m22 * mat.m24 + self.m23 * mat.m34 + self.m24 * mat.m44,
self.m31 * mat.m11 + self.m32 * mat.m21 + self.m33 * mat.m31 + self.m34 * mat.m41,
self.m31 * mat.m12 + self.m32 * mat.m22 + self.m33 * mat.m32 + self.m34 * mat.m42,
self.m31 * mat.m13 + self.m32 * mat.m23 + self.m33 * mat.m33 + self.m34 * mat.m43,
self.m31 * mat.m14 + self.m32 * mat.m24 + self.m33 * mat.m34 + self.m34 * mat.m44,
self.m41 * mat.m11 + self.m42 * mat.m21 + self.m43 * mat.m31 + self.m44 * mat.m41,
self.m41 * mat.m12 + self.m42 * mat.m22 + self.m43 * mat.m32 + self.m44 * mat.m42,
self.m41 * mat.m13 + self.m42 * mat.m23 + self.m43 * mat.m33 + self.m44 * mat.m43,
self.m41 * mat.m14 + self.m42 * mat.m24 + self.m43 * mat.m34 + self.m44 * mat.m44,
)
}
/// Returns the multiplication of the two matrices such that mat's transformation
/// applies before self's transformation.
pub fn pre_mul<NewSrc>(&self, mat: &TypedTransform3D<T, NewSrc, Src>) -> TypedTransform3D<T, NewSrc, Dst> {
mat.post_mul(self)
}
/// Returns the inverse transform if possible.
pub fn inverse(&self) -> Option<TypedTransform3D<T, Dst, Src>> {
let det = self.determinant();
if det == Zero::zero() {
return None;
}
// todo(gw): this could be made faster by special casing
// for simpler transform types.
let m = TypedTransform3D::row_major(
self.m23*self.m34*self.m42 - self.m24*self.m33*self.m42 +
self.m24*self.m32*self.m43 - self.m22*self.m34*self.m43 -
self.m23*self.m32*self.m44 + self.m22*self.m33*self.m44,
self.m14*self.m33*self.m42 - self.m13*self.m34*self.m42 -
self.m14*self.m32*self.m43 + self.m12*self.m34*self.m43 +
self.m13*self.m32*self.m44 - self.m12*self.m33*self.m44,
self.m13*self.m24*self.m42 - self.m14*self.m23*self.m42 +
self.m14*self.m22*self.m43 - self.m12*self.m24*self.m43 -
self.m13*self.m22*self.m44 + self.m12*self.m23*self.m44,
self.m14*self.m23*self.m32 - self.m13*self.m24*self.m32 -
self.m14*self.m22*self.m33 + self.m12*self.m24*self.m33 +
self.m13*self.m22*self.m34 - self.m12*self.m23*self.m34,
self.m24*self.m33*self.m41 - self.m23*self.m34*self.m41 -
self.m24*self.m31*self.m43 + self.m21*self.m34*self.m43 +
self.m23*self.m31*self.m44 - self.m21*self.m33*self.m44,
self.m13*self.m34*self.m41 - self.m14*self.m33*self.m41 +
self.m14*self.m31*self.m43 - self.m11*self.m34*self.m43 -
self.m13*self.m31*self.m44 + self.m11*self.m33*self.m44,
self.m14*self.m23*self.m41 - self.m13*self.m24*self.m41 -
self.m14*self.m21*self.m43 + self.m11*self.m24*self.m43 +
self.m13*self.m21*self.m44 - self.m11*self.m23*self.m44,
self.m13*self.m24*self.m31 - self.m14*self.m23*self.m31 +
self.m14*self.m21*self.m33 - self.m11*self.m24*self.m33 -
self.m13*self.m21*self.m34 + self.m11*self.m23*self.m34,
self.m22*self.m34*self.m41 - self.m24*self.m32*self.m41 +
self.m24*self.m31*self.m42 - self.m21*self.m34*self.m42 -
self.m22*self.m31*self.m44 + self.m21*self.m32*self.m44,
self.m14*self.m32*self.m41 - self.m12*self.m34*self.m41 -
self.m14*self.m31*self.m42 + self.m11*self.m34*self.m42 +
self.m12*self.m31*self.m44 - self.m11*self.m32*self.m44,
self.m12*self.m24*self.m41 - self.m14*self.m22*self.m41 +
self.m14*self.m21*self.m42 - self.m11*self.m24*self.m42 -
self.m12*self.m21*self.m44 + self.m11*self.m22*self.m44,
self.m14*self.m22*self.m31 - self.m12*self.m24*self.m31 -
self.m14*self.m21*self.m32 + self.m11*self.m24*self.m32 +
self.m12*self.m21*self.m34 - self.m11*self.m22*self.m34,
self.m23*self.m32*self.m41 - self.m22*self.m33*self.m41 -
self.m23*self.m31*self.m42 + self.m21*self.m33*self.m42 +
self.m22*self.m31*self.m43 - self.m21*self.m32*self.m43,
self.m12*self.m33*self.m41 - self.m13*self.m32*self.m41 +
self.m13*self.m31*self.m42 - self.m11*self.m33*self.m42 -
self.m12*self.m31*self.m43 + self.m11*self.m32*self.m43,
self.m13*self.m22*self.m41 - self.m12*self.m23*self.m41 -
self.m13*self.m21*self.m42 + self.m11*self.m23*self.m42 +
self.m12*self.m21*self.m43 - self.m11*self.m22*self.m43,
self.m12*self.m23*self.m31 - self.m13*self.m22*self.m31 +
self.m13*self.m21*self.m32 - self.m11*self.m23*self.m32 -
self.m12*self.m21*self.m33 + self.m11*self.m22*self.m33
);
let _1: T = One::one();
Some(m.mul_s(_1 / det))
}
/// Compute the determinant of the transform.
pub fn determinant(&self) -> T {
self.m14 * self.m23 * self.m32 * self.m41 -
self.m13 * self.m24 * self.m32 * self.m41 -
self.m14 * self.m22 * self.m33 * self.m41 +
self.m12 * self.m24 * self.m33 * self.m41 +
self.m13 * self.m22 * self.m34 * self.m41 -
self.m12 * self.m23 * self.m34 * self.m41 -
self.m14 * self.m23 * self.m31 * self.m42 +
self.m13 * self.m24 * self.m31 * self.m42 +
self.m14 * self.m21 * self.m33 * self.m42 -
self.m11 * self.m24 * self.m33 * self.m42 -
self.m13 * self.m21 * self.m34 * self.m42 +
self.m11 * self.m23 * self.m34 * self.m42 +
self.m14 * self.m22 * self.m31 * self.m43 -
self.m12 * self.m24 * self.m31 * self.m43 -
self.m14 * self.m21 * self.m32 * self.m43 +
self.m11 * self.m24 * self.m32 * self.m43 +
self.m12 * self.m21 * self.m34 * self.m43 -
self.m11 * self.m22 * self.m34 * self.m43 -
self.m13 * self.m22 * self.m31 * self.m44 +
self.m12 * self.m23 * self.m31 * self.m44 +
self.m13 * self.m21 * self.m32 * self.m44 -
self.m11 * self.m23 * self.m32 * self.m44 -
self.m12 * self.m21 * self.m33 * self.m44 +
self.m11 * self.m22 * self.m33 * self.m44
}
/// Multiplies all of the transform's component by a scalar and returns the result.
#[must_use]
pub fn mul_s(&self, x: T) -> Self {
TypedTransform3D::row_major(
self.m11 * x, self.m12 * x, self.m13 * x, self.m14 * x,
self.m21 * x, self.m22 * x, self.m23 * x, self.m24 * x,
self.m31 * x, self.m32 * x, self.m33 * x, self.m34 * x,
self.m41 * x, self.m42 * x, self.m43 * x, self.m44 * x
)
}
/// Convenience function to create a scale transform from a ScaleFactor.
pub fn from_scale_factor(scale: ScaleFactor<T, Src, Dst>) -> Self {
TypedTransform3D::create_scale(scale.get(), scale.get(), scale.get())
}
/// Returns the given 2d point transformed by this transform.
///
/// The input point must be use the unit Src, and the returned point has the unit Dst.
#[inline]
pub fn transform_point2d(&self, p: &TypedPoint2D<T, Src>) -> TypedPoint2D<T, Dst> {
let x = p.x * self.m11 + p.y * self.m21 + self.m41;
let y = p.x * self.m12 + p.y * self.m22 + self.m42;
let w = p.x * self.m14 + p.y * self.m24 + self.m44;
point2(x/w, y/w)
}
/// Returns the given 2d vector transformed by this matrix.
///
/// The input point must be use the unit Src, and the returned point has the unit Dst.
#[inline]
pub fn transform_vector2d(&self, v: &TypedVector2D<T, Src>) -> TypedVector2D<T, Dst> {
vec2(
v.x * self.m11 + v.y * self.m21,
v.x * self.m12 + v.y * self.m22,
)
}
/// Returns the given 3d point transformed by this transform.
///
/// The input point must be use the unit Src, and the returned point has the unit Dst.
#[inline]
pub fn transform_point3d(&self, p: &TypedPoint3D<T, Src>) -> TypedPoint3D<T, Dst> {
let x = p.x * self.m11 + p.y * self.m21 + p.z * self.m31 + self.m41;
let y = p.x * self.m12 + p.y * self.m22 + p.z * self.m32 + self.m42;
let z = p.x * self.m13 + p.y * self.m23 + p.z * self.m33 + self.m43;
let w = p.x * self.m14 + p.y * self.m24 + p.z * self.m34 + self.m44;
point3(x/w, y/w, z/w)
}
/// Returns the given 3d vector transformed by this matrix.
///
/// The input point must be use the unit Src, and the returned point has the unit Dst.
#[inline]
pub fn transform_vector3d(&self, v: &TypedVector3D<T, Src>) -> TypedVector3D<T, Dst> {
vec3(
v.x * self.m11 + v.y * self.m21 + v.z * self.m31,
v.x * self.m12 + v.y * self.m22 + v.z * self.m32,
v.x * self.m13 + v.y * self.m23 + v.z * self.m33,
)
}
/// Returns a rectangle that encompasses the result of transforming the given rectangle by this
/// transform.
pub fn transform_rect(&self, rect: &TypedRect<T, Src>) -> TypedRect<T, Dst> {
TypedRect::from_points(&[
self.transform_point2d(&rect.origin),
self.transform_point2d(&rect.top_right()),
self.transform_point2d(&rect.bottom_left()),
self.transform_point2d(&rect.bottom_right()),
])
}
/// Create a 3d translation transform
pub fn create_translation(x: T, y: T, z: T) -> Self {
let (_0, _1): (T, T) = (Zero::zero(), One::one());
TypedTransform3D::row_major(
_1, _0, _0, _0,
_0, _1, _0, _0,
_0, _0, _1, _0,
x, y, z, _1
)
}
/// Returns a transform with a translation applied before self's transformation.
#[must_use]
pub fn pre_translate(&self, v: TypedVector3D<T, Src>) -> Self {
self.pre_mul(&TypedTransform3D::create_translation(v.x, v.y, v.z))
}
/// Returns a transform with a translation applied after self's transformation.
#[must_use]
pub fn post_translate(&self, v: TypedVector3D<T, Dst>) -> Self {
self.post_mul(&TypedTransform3D::create_translation(v.x, v.y, v.z))
}
/// Create a 3d scale transform
pub fn create_scale(x: T, y: T, z: T) -> Self {
let (_0, _1): (T, T) = (Zero::zero(), One::one());
TypedTransform3D::row_major(
x, _0, _0, _0,
_0, y, _0, _0,
_0, _0, z, _0,
_0, _0, _0, _1
)
}
/// Returns a transform with a scale applied before self's transformation.
#[must_use]
pub fn pre_scale(&self, x: T, y: T, z: T) -> Self {
TypedTransform3D::row_major(
self.m11 * x, self.m12, self.m13, self.m14,
self.m21 , self.m22 * y, self.m23, self.m24,
self.m31 , self.m32, self.m33 * z, self.m34,
self.m41 , self.m42, self.m43, self.m44
)
}
/// Returns a transform with a scale applied after self's transformation.
#[must_use]
pub fn post_scale(&self, x: T, y: T, z: T) -> Self {
self.post_mul(&TypedTransform3D::create_scale(x, y, z))
}
/// Create a 3d rotation transform from an angle / axis.
/// The supplied axis must be normalized.
pub fn create_rotation(x: T, y: T, z: T, theta: Radians<T>) -> Self {
let (_0, _1): (T, T) = (Zero::zero(), One::one());
let _2 = _1 + _1;
let xx = x * x;
let yy = y * y;
let zz = z * z;
let half_theta = theta.get() / _2;
let sc = half_theta.sin() * half_theta.cos();
let sq = half_theta.sin() * half_theta.sin();
TypedTransform3D::row_major(
_1 - _2 * (yy + zz) * sq,
_2 * (x * y * sq - z * sc),
_2 * (x * z * sq + y * sc),
_0,
_2 * (x * y * sq + z * sc),
_1 - _2 * (xx + zz) * sq,
_2 * (y * z * sq - x * sc),
_0,
_2 * (x * z * sq - y * sc),
_2 * (y * z * sq + x * sc),
_1 - _2 * (xx + yy) * sq,
_0,
_0,
_0,
_0,
_1
)
}
/// Returns a transform with a rotation applied after self's transformation.
#[must_use]
pub fn post_rotate(&self, x: T, y: T, z: T, theta: Radians<T>) -> Self {
self.post_mul(&TypedTransform3D::create_rotation(x, y, z, theta))
}
/// Returns a transform with a rotation applied before self's transformation.
#[must_use]
pub fn pre_rotate(&self, x: T, y: T, z: T, theta: Radians<T>) -> Self {
self.pre_mul(&TypedTransform3D::create_rotation(x, y, z, theta))
}
/// Create a 2d skew transform.
///
/// See https://drafts.csswg.org/css-transforms/#funcdef-skew
pub fn create_skew(alpha: Radians<T>, beta: Radians<T>) -> Self {
let (_0, _1): (T, T) = (Zero::zero(), One::one());
let (sx, sy) = (beta.get().tan(), alpha.get().tan());
TypedTransform3D::row_major(
_1, sx, _0, _0,
sy, _1, _0, _0,
_0, _0, _1, _0,
_0, _0, _0, _1
)
}
/// Create a simple perspective projection transform
pub fn create_perspective(d: T) -> Self {
let (_0, _1): (T, T) = (Zero::zero(), One::one());
TypedTransform3D::row_major(
_1, _0, _0, _0,
_0, _1, _0, _0,
_0, _0, _1, -_1 / d,
_0, _0, _0, _1
)
}
}
impl<T: Copy, Src, Dst> TypedTransform3D<T, Src, Dst> {
/// Returns an array containing this transform's terms in row-major order (the order
/// in which the transform is actually laid out in memory).
pub fn to_row_major_array(&self) -> [T; 16] {
[
self.m11, self.m12, self.m13, self.m14,
self.m21, self.m22, self.m23, self.m24,
self.m31, self.m32, self.m33, self.m34,
self.m41, self.m42, self.m43, self.m44
]
}
/// Returns an array containing this transform's terms in column-major order.
pub fn to_column_major_array(&self) -> [T; 16] {
[
self.m11, self.m21, self.m31, self.m41,
self.m12, self.m22, self.m32, self.m42,
self.m13, self.m23, self.m33, self.m43,
self.m14, self.m24, self.m34, self.m44
]
}
/// Returns an array containing this transform's 4 rows in (in row-major order)
/// as arrays.
///
/// This is a convenience method to interface with other libraries like glium.
pub fn to_row_arrays(&self) -> [[T; 4]; 4] {
[
[self.m11, self.m12, self.m13, self.m14],
[self.m21, self.m22, self.m23, self.m24],
[self.m31, self.m32, self.m33, self.m34],
[self.m41, self.m42, self.m43, self.m44]
]
}
/// Returns an array containing this transform's 4 columns in (in row-major order,
/// or 4 rows in column-major order) as arrays.
///
/// This is a convenience method to interface with other libraries like glium.
pub fn to_column_arrays(&self) -> [[T; 4]; 4] {
[
[self.m11, self.m21, self.m31, self.m41],
[self.m12, self.m22, self.m32, self.m42],
[self.m13, self.m23, self.m33, self.m43],
[self.m14, self.m24, self.m34, self.m44]
]
}
/// Creates a transform from an array of 16 elements in row-major order.
pub fn from_array(array: [T; 16]) -> Self {
Self::row_major(
array[0], array[1], array[2], array[3],
array[4], array[5], array[6], array[7],
array[8], array[9], array[10], array[11],
array[12], array[13], array[14], array[15],
)
}
/// Creates a transform from 4 rows of 4 elements (row-major order).
pub fn from_row_arrays(array: [[T; 4]; 4]) -> Self {
Self::row_major(
array[0][0], array[0][1], array[0][2], array[0][3],
array[1][0], array[1][1], array[1][2], array[1][3],
array[2][0], array[2][1], array[2][2], array[2][3],
array[3][0], array[3][1], array[3][2], array[3][3],
)
}
}
impl<T, Src, Dst> fmt::Debug for TypedTransform3D<T, Src, Dst>
where T: Copy + fmt::Debug +
PartialEq +
One + Zero {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.is_identity() {
write!(f, "[I]")
} else {
self.to_row_major_array().fmt(f)
}
}
}
#[cfg(test)]
mod tests {
use approxeq::ApproxEq;
use transform2d::Transform2D;
use point::{Point2D, Point3D};
use Radians;
use super::*;
use std::f32::consts::FRAC_PI_2;
type Mf32 = Transform3D<f32>;
// For convenience.
fn rad(v: f32) -> Radians<f32> { Radians::new(v) }
#[test]
pub fn test_translation() {
let t1 = Mf32::create_translation(1.0, 2.0, 3.0);
let t2 = Mf32::identity().pre_translate(vec3(1.0, 2.0, 3.0));
let t3 = Mf32::identity().post_translate(vec3(1.0, 2.0, 3.0));
assert_eq!(t1, t2);
assert_eq!(t1, t3);
assert_eq!(t1.transform_point3d(&Point3D::new(1.0, 1.0, 1.0)), Point3D::new(2.0, 3.0, 4.0));
assert_eq!(t1.transform_point2d(&Point2D::new(1.0, 1.0)), Point2D::new(2.0, 3.0));
assert_eq!(t1.post_mul(&t1), Mf32::create_translation(2.0, 4.0, 6.0));
assert!(!t1.is_2d());
assert_eq!(Mf32::create_translation(1.0, 2.0, 3.0).to_2d(), Transform2D::create_translation(1.0, 2.0));
}
#[test]
pub fn test_rotation() {
let r1 = Mf32::create_rotation(0.0, 0.0, 1.0, rad(FRAC_PI_2));
let r2 = Mf32::identity().pre_rotate(0.0, 0.0, 1.0, rad(FRAC_PI_2));
let r3 = Mf32::identity().post_rotate(0.0, 0.0, 1.0, rad(FRAC_PI_2));
assert_eq!(r1, r2);
assert_eq!(r1, r3);
assert!(r1.transform_point3d(&Point3D::new(1.0, 2.0, 3.0)).approx_eq(&Point3D::new(2.0, -1.0, 3.0)));
assert!(r1.transform_point2d(&Point2D::new(1.0, 2.0)).approx_eq(&Point2D::new(2.0, -1.0)));
assert!(r1.post_mul(&r1).approx_eq(&Mf32::create_rotation(0.0, 0.0, 1.0, rad(FRAC_PI_2*2.0))));
assert!(r1.is_2d());
assert!(r1.to_2d().approx_eq(&Transform2D::create_rotation(rad(FRAC_PI_2))));
}
#[test]
pub fn test_scale() {
let s1 = Mf32::create_scale(2.0, 3.0, 4.0);
let s2 = Mf32::identity().pre_scale(2.0, 3.0, 4.0);
let s3 = Mf32::identity().post_scale(2.0, 3.0, 4.0);
assert_eq!(s1, s2);
assert_eq!(s1, s3);
assert!(s1.transform_point3d(&Point3D::new(2.0, 2.0, 2.0)).approx_eq(&Point3D::new(4.0, 6.0, 8.0)));
assert!(s1.transform_point2d(&Point2D::new(2.0, 2.0)).approx_eq(&Point2D::new(4.0, 6.0)));
assert_eq!(s1.post_mul(&s1), Mf32::create_scale(4.0, 9.0, 16.0));
assert!(!s1.is_2d());
assert_eq!(Mf32::create_scale(2.0, 3.0, 0.0).to_2d(), Transform2D::create_scale(2.0, 3.0));
}
#[test]
pub fn test_ortho() {
let (left, right, bottom, top) = (0.0f32, 1.0f32, 0.1f32, 1.0f32);
let (near, far) = (-1.0f32, 1.0f32);
let result = Mf32::ortho(left, right, bottom, top, near, far);
let expected = Mf32::row_major(
2.0, 0.0, 0.0, 0.0,
0.0, 2.22222222, 0.0, 0.0,
0.0, 0.0, -1.0, 0.0,
-1.0, -1.22222222, -0.0, 1.0
);
debug!("result={:?} expected={:?}", result, expected);
assert!(result.approx_eq(&expected));
}
#[test]
pub fn test_is_2d() {
assert!(Mf32::identity().is_2d());
assert!(Mf32::create_rotation(0.0, 0.0, 1.0, rad(0.7854)).is_2d());
assert!(!Mf32::create_rotation(0.0, 1.0, 0.0, rad(0.7854)).is_2d());
}
#[test]
pub fn test_row_major_2d() {
let m1 = Mf32::row_major_2d(1.0, 2.0, 3.0, 4.0, 5.0, 6.0);
let m2 = Mf32::row_major(
1.0, 2.0, 0.0, 0.0,
3.0, 4.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
5.0, 6.0, 0.0, 1.0
);
assert_eq!(m1, m2);
}
#[test]
fn test_column_major() {
assert_eq!(
Mf32::row_major(
1.0, 2.0, 3.0, 4.0,
5.0, 6.0, 7.0, 8.0,
9.0, 10.0, 11.0, 12.0,
13.0, 14.0, 15.0, 16.0,
),
Mf32::column_major(
1.0, 5.0, 9.0, 13.0,
2.0, 6.0, 10.0, 14.0,
3.0, 7.0, 11.0, 15.0,
4.0, 8.0, 12.0, 16.0,
)
);
}
#[test]
pub fn test_inverse_simple() {
let m1 = Mf32::identity();
let m2 = m1.inverse().unwrap();
assert!(m1.approx_eq(&m2));
}
#[test]
pub fn test_inverse_scale() {
let m1 = Mf32::create_scale(1.5, 0.3, 2.1);
let m2 = m1.inverse().unwrap();
assert!(m1.pre_mul(&m2).approx_eq(&Mf32::identity()));
}
#[test]
pub fn test_inverse_translate() {
let m1 = Mf32::create_translation(-132.0, 0.3, 493.0);
let m2 = m1.inverse().unwrap();
assert!(m1.pre_mul(&m2).approx_eq(&Mf32::identity()));
}
#[test]
pub fn test_inverse_rotate() {
let m1 = Mf32::create_rotation(0.0, 1.0, 0.0, rad(1.57));
let m2 = m1.inverse().unwrap();
assert!(m1.pre_mul(&m2).approx_eq(&Mf32::identity()));
}
#[test]
pub fn test_inverse_transform_point_2d() {
let m1 = Mf32::create_translation(100.0, 200.0, 0.0);
let m2 = m1.inverse().unwrap();
assert!(m1.pre_mul(&m2).approx_eq(&Mf32::identity()));
let p1 = Point2D::new(1000.0, 2000.0);
let p2 = m1.transform_point2d(&p1);
assert!(p2.eq(&Point2D::new(1100.0, 2200.0)));
let p3 = m2.transform_point2d(&p2);
assert!(p3.eq(&p1));
}
#[test]
fn test_inverse_none() {
assert!(Mf32::create_scale(2.0, 0.0, 2.0).inverse().is_none());
assert!(Mf32::create_scale(2.0, 2.0, 2.0).inverse().is_some());
}
#[test]
pub fn test_pre_post() {
let m1 = Transform3D::identity().post_scale(1.0, 2.0, 3.0).post_translate(vec3(1.0, 2.0, 3.0));
let m2 = Transform3D::identity().pre_translate(vec3(1.0, 2.0, 3.0)).pre_scale(1.0, 2.0, 3.0);
assert!(m1.approx_eq(&m2));
let r = Mf32::create_rotation(0.0, 0.0, 1.0, rad(FRAC_PI_2));
let t = Mf32::create_translation(2.0, 3.0, 0.0);
let a = Point3D::new(1.0, 1.0, 1.0);
assert!(r.post_mul(&t).transform_point3d(&a).approx_eq(&Point3D::new(3.0, 2.0, 1.0)));
assert!(t.post_mul(&r).transform_point3d(&a).approx_eq(&Point3D::new(4.0, -3.0, 1.0)));
assert!(t.post_mul(&r).transform_point3d(&a).approx_eq(&r.transform_point3d(&t.transform_point3d(&a))));
assert!(r.pre_mul(&t).transform_point3d(&a).approx_eq(&Point3D::new(4.0, -3.0, 1.0)));
assert!(t.pre_mul(&r).transform_point3d(&a).approx_eq(&Point3D::new(3.0, 2.0, 1.0)));
assert!(t.pre_mul(&r).transform_point3d(&a).approx_eq(&t.transform_point3d(&r.transform_point3d(&a))));
}
#[test]
fn test_size_of() {
use std::mem::size_of;
assert_eq!(size_of::<Transform3D<f32>>(), 16*size_of::<f32>());
assert_eq!(size_of::<Transform3D<f64>>(), 16*size_of::<f64>());
}
#[test]
pub fn test_transform_associativity() {
let m1 = Mf32::row_major(3.0, 2.0, 1.5, 1.0,
0.0, 4.5, -1.0, -4.0,
0.0, 3.5, 2.5, 40.0,
0.0, 3.0, 0.0, 1.0);
let m2 = Mf32::row_major(1.0, -1.0, 3.0, 0.0,
-1.0, 0.5, 0.0, 2.0,
1.5, -2.0, 6.0, 0.0,
-2.5, 6.0, 1.0, 1.0);
let p = Point3D::new(1.0, 3.0, 5.0);
let p1 = m2.pre_mul(&m1).transform_point3d(&p);
let p2 = m2.transform_point3d(&m1.transform_point3d(&p));
assert!(p1.approx_eq(&p2));
}
#[test]
pub fn test_is_identity() {
let m1 = Transform3D::identity();
assert!(m1.is_identity());
let m2 = m1.post_translate(vec3(0.1, 0.0, 0.0));
assert!(!m2.is_identity());
}
#[test]
pub fn test_transform_vector() {
// Translation does not apply to vectors.
let m = Mf32::create_translation(1.0, 2.0, 3.0);
let v1 = vec3(10.0, -10.0, 3.0);
assert_eq!(v1, m.transform_vector3d(&v1));
// While it does apply to points.
assert!(v1.to_point() != m.transform_point3d(&v1.to_point()));
// same thing with 2d vectors/points
let v2 = vec2(10.0, -5.0);
assert_eq!(v2, m.transform_vector2d(&v2));
assert!(v2.to_point() != m.transform_point2d(&v2.to_point()));
}
}

894
third_party/rust/euclid/src/vector.rs поставляемый
Просмотреть файл

@ -1,894 +0,0 @@
// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use super::UnknownUnit;
use approxeq::ApproxEq;
use length::Length;
use point::{TypedPoint2D, TypedPoint3D, point2, point3};
use size::{TypedSize2D, size2};
use scale_factor::ScaleFactor;
use num::*;
use num_traits::{Float, NumCast};
use std::fmt;
use std::ops::{Add, Neg, Mul, Sub, Div, AddAssign, SubAssign, MulAssign, DivAssign};
use std::marker::PhantomData;
define_matrix! {
/// A 2d Vector tagged with a unit.
pub struct TypedVector2D<T, U> {
pub x: T,
pub y: T,
}
}
/// Default 2d vector type with no unit.
///
/// `Vector2D` provides the same methods as `TypedVector2D`.
pub type Vector2D<T> = TypedVector2D<T, UnknownUnit>;
impl<T: Copy + Zero, U> TypedVector2D<T, U> {
/// Constructor, setting all components to zero.
#[inline]
pub fn zero() -> Self {
TypedVector2D::new(Zero::zero(), Zero::zero())
}
/// Convert into a 3d vector.
#[inline]
pub fn to_3d(&self) -> TypedVector3D<T, U> {
vec3(self.x, self.y, Zero::zero())
}
}
impl<T: fmt::Debug, U> fmt::Debug for TypedVector2D<T, U> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({:?},{:?})", self.x, self.y)
}
}
impl<T: fmt::Display, U> fmt::Display for TypedVector2D<T, U> {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "({},{})", self.x, self.y)
}
}
impl<T: Copy, U> TypedVector2D<T, U> {
/// Constructor taking scalar values directly.
#[inline]
pub fn new(x: T, y: T) -> Self {
TypedVector2D { x: x, y: y, _unit: PhantomData }
}
/// Constructor taking properly typed Lengths instead of scalar values.
#[inline]
pub fn from_lengths(x: Length<T, U>, y: Length<T, U>) -> Self {
vec2(x.0, y.0)
}
/// Create a 3d vector from this one, using the specified z value.
#[inline]
pub fn extend(&self, z: T) -> TypedVector3D<T, U> {
vec3(self.x, self.y, z)
}
/// Cast this vector into a point.
///
/// Equivalent to adding this vector to the origin.
#[inline]
pub fn to_point(&self) -> TypedPoint2D<T, U> {
point2(self.x, self.y)
}
/// Cast this vector into a size.
#[inline]
pub fn to_size(&self) -> TypedSize2D<T, U> {
size2(self.x, self.y)
}
/// Returns self.x as a Length carrying the unit.
#[inline]
pub fn x_typed(&self) -> Length<T, U> { Length::new(self.x) }
/// Returns self.y as a Length carrying the unit.
#[inline]
pub fn y_typed(&self) -> Length<T, U> { Length::new(self.y) }
/// Drop the units, preserving only the numeric value.
#[inline]
pub fn to_untyped(&self) -> Vector2D<T> {
vec2(self.x, self.y)
}
/// Tag a unitless value with units.
#[inline]
pub fn from_untyped(p: &Vector2D<T>) -> Self {
vec2(p.x, p.y)
}
#[inline]
pub fn to_array(&self) -> [T; 2] {
[self.x, self.y]
}
}
impl<T, U> TypedVector2D<T, U>
where T: Copy + Mul<T, Output=T> + Add<T, Output=T> + Sub<T, Output=T> {
/// Dot product.
#[inline]
pub fn dot(self, other: Self) -> T {
self.x * other.x + self.y * other.y
}
/// Returns the norm of the cross product [self.x, self.y, 0] x [other.x, other.y, 0]..
#[inline]
pub fn cross(self, other: Self) -> T {
self.x * other.y - self.y * other.x
}
#[inline]
pub fn normalize(self) -> Self where T: Float + ApproxEq<T> {
let dot = self.dot(self);
if dot.approx_eq(&T::zero()) {
self
} else {
self / dot.sqrt()
}
}
#[inline]
pub fn square_length(&self) -> T {
self.x * self.x + self.y * self.y
}
#[inline]
pub fn length(&self) -> T where T: Float + ApproxEq<T> {
self.square_length().sqrt()
}
}
impl<T, U> TypedVector2D<T, U>
where T: Copy + One + Add<Output=T> + Sub<Output=T> + Mul<Output=T> {
/// Linearly interpolate between this vector and another vector.
///
/// `t` is expected to be between zero and one.
#[inline]
pub fn lerp(&self, other: Self, t: T) -> Self {
let one_t = T::one() - t;
(*self) * one_t + other * t
}
}
impl<T: Copy + Add<T, Output=T>, U> Add for TypedVector2D<T, U> {
type Output = Self;
fn add(self, other: Self) -> Self {
TypedVector2D::new(self.x + other.x, self.y + other.y)
}
}
impl<T: Copy + Add<T, Output=T>, U> AddAssign for TypedVector2D<T, U> {
#[inline]
fn add_assign(&mut self, other: Self) {
*self = *self + other
}
}
impl<T: Copy + Sub<T, Output=T>, U> SubAssign<TypedVector2D<T, U>> for TypedVector2D<T, U> {
#[inline]
fn sub_assign(&mut self, other: Self) {
*self = *self - other
}
}
impl<T: Copy + Sub<T, Output=T>, U> Sub for TypedVector2D<T, U> {
type Output = Self;
#[inline]
fn sub(self, other: Self) -> Self {
vec2(self.x - other.x, self.y - other.y)
}
}
impl <T: Copy + Neg<Output=T>, U> Neg for TypedVector2D<T, U> {
type Output = Self;
#[inline]
fn neg(self) -> Self {
vec2(-self.x, -self.y)
}
}
impl<T: Float, U> TypedVector2D<T, U> {
#[inline]
pub fn min(self, other: Self) -> Self {
vec2(self.x.min(other.x), self.y.min(other.y))
}
#[inline]
pub fn max(self, other: Self) -> Self {
vec2(self.x.max(other.x), self.y.max(other.y))
}
}
impl<T: Copy + Mul<T, Output=T>, U> Mul<T> for TypedVector2D<T, U> {
type Output = Self;
#[inline]
fn mul(self, scale: T) -> Self {
vec2(self.x * scale, self.y * scale)
}
}
impl<T: Copy + Div<T, Output=T>, U> Div<T> for TypedVector2D<T, U> {
type Output = Self;
#[inline]
fn div(self, scale: T) -> Self {
vec2(self.x / scale, self.y / scale)
}
}
impl<T: Copy + Mul<T, Output=T>, U> MulAssign<T> for TypedVector2D<T, U> {
#[inline]
fn mul_assign(&mut self, scale: T) {
*self = *self * scale
}
}
impl<T: Copy + Div<T, Output=T>, U> DivAssign<T> for TypedVector2D<T, U> {
#[inline]
fn div_assign(&mut self, scale: T) {
*self = *self / scale
}
}
impl<T: Copy + Mul<T, Output=T>, U1, U2> Mul<ScaleFactor<T, U1, U2>> for TypedVector2D<T, U1> {
type Output = TypedVector2D<T, U2>;
#[inline]
fn mul(self, scale: ScaleFactor<T, U1, U2>) -> TypedVector2D<T, U2> {
vec2(self.x * scale.get(), self.y * scale.get())
}
}
impl<T: Copy + Div<T, Output=T>, U1, U2> Div<ScaleFactor<T, U1, U2>> for TypedVector2D<T, U2> {
type Output = TypedVector2D<T, U1>;
#[inline]
fn div(self, scale: ScaleFactor<T, U1, U2>) -> TypedVector2D<T, U1> {
vec2(self.x / scale.get(), self.y / scale.get())
}
}
impl<T: Round, U> TypedVector2D<T, U> {
/// Rounds each component to the nearest integer value.
///
/// This behavior is preserved for negative values (unlike the basic cast).
/// For example `{ -0.1, -0.8 }.round() == { 0.0, -1.0 }`.
#[inline]
#[must_use]
pub fn round(&self) -> Self {
vec2(self.x.round(), self.y.round())
}
}
impl<T: Ceil, U> TypedVector2D<T, U> {
/// Rounds each component to the smallest integer equal or greater than the original value.
///
/// This behavior is preserved for negative values (unlike the basic cast).
/// For example `{ -0.1, -0.8 }.ceil() == { 0.0, 0.0 }`.
#[inline]
#[must_use]
pub fn ceil(&self) -> Self {
vec2(self.x.ceil(), self.y.ceil())
}
}
impl<T: Floor, U> TypedVector2D<T, U> {
/// Rounds each component to the biggest integer equal or lower than the original value.
///
/// This behavior is preserved for negative values (unlike the basic cast).
/// For example `{ -0.1, -0.8 }.floor() == { -1.0, -1.0 }`.
#[inline]
#[must_use]
pub fn floor(&self) -> Self {
vec2(self.x.floor(), self.y.floor())
}
}
impl<T: NumCast + Copy, U> TypedVector2D<T, U> {
/// Cast from one numeric representation to another, preserving the units.
///
/// When casting from floating vector to integer coordinates, the decimals are truncated
/// as one would expect from a simple cast, but this behavior does not always make sense
/// geometrically. Consider using `round()`, `ceil()` or `floor()` before casting.
#[inline]
pub fn cast<NewT: NumCast + Copy>(&self) -> Option<TypedVector2D<NewT, U>> {
match (NumCast::from(self.x), NumCast::from(self.y)) {
(Some(x), Some(y)) => Some(TypedVector2D::new(x, y)),
_ => None
}
}
// Convenience functions for common casts
/// Cast into an `f32` vector.
#[inline]
pub fn to_f32(&self) -> TypedVector2D<f32, U> {
self.cast().unwrap()
}
/// Cast into an `usize` vector, truncating decimals if any.
///
/// When casting from floating vector vectors, it is worth considering whether
/// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
/// the desired conversion behavior.
#[inline]
pub fn to_usize(&self) -> TypedVector2D<usize, U> {
self.cast().unwrap()
}
/// Cast into an i32 vector, truncating decimals if any.
///
/// When casting from floating vector vectors, it is worth considering whether
/// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
/// the desired conversion behavior.
#[inline]
pub fn to_i32(&self) -> TypedVector2D<i32, U> {
self.cast().unwrap()
}
/// Cast into an i64 vector, truncating decimals if any.
///
/// When casting from floating vector vectors, it is worth considering whether
/// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
/// the desired conversion behavior.
#[inline]
pub fn to_i64(&self) -> TypedVector2D<i64, U> {
self.cast().unwrap()
}
}
impl<T: Copy+ApproxEq<T>, U> ApproxEq<TypedVector2D<T, U>> for TypedVector2D<T, U> {
#[inline]
fn approx_epsilon() -> Self {
vec2(T::approx_epsilon(), T::approx_epsilon())
}
#[inline]
fn approx_eq(&self, other: &Self) -> bool {
self.x.approx_eq(&other.x) && self.y.approx_eq(&other.y)
}
#[inline]
fn approx_eq_eps(&self, other: &Self, eps: &Self) -> bool {
self.x.approx_eq_eps(&other.x, &eps.x) && self.y.approx_eq_eps(&other.y, &eps.y)
}
}
impl<T: Copy, U> Into<[T; 2]> for TypedVector2D<T, U> {
fn into(self) -> [T; 2] {
self.to_array()
}
}
impl<T: Copy, U> From<[T; 2]> for TypedVector2D<T, U> {
fn from(array: [T; 2]) -> Self {
vec2(array[0], array[1])
}
}
define_matrix! {
/// A 3d Vector tagged with a unit.
pub struct TypedVector3D<T, U> {
pub x: T,
pub y: T,
pub z: T,
}
}
/// Default 3d vector type with no unit.
///
/// `Vector3D` provides the same methods as `TypedVector3D`.
pub type Vector3D<T> = TypedVector3D<T, UnknownUnit>;
impl<T: Copy + Zero, U> TypedVector3D<T, U> {
/// Constructor, setting all copmonents to zero.
#[inline]
pub fn zero() -> Self {
vec3(Zero::zero(), Zero::zero(), Zero::zero())
}
#[inline]
pub fn to_array_4d(&self) -> [T; 4] {
[self.x, self.y, self.z, Zero::zero()]
}
}
impl<T: fmt::Debug, U> fmt::Debug for TypedVector3D<T, U> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({:?},{:?},{:?})", self.x, self.y, self.z)
}
}
impl<T: fmt::Display, U> fmt::Display for TypedVector3D<T, U> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({},{},{})", self.x, self.y, self.z)
}
}
impl<T: Copy, U> TypedVector3D<T, U> {
/// Constructor taking scalar values directly.
#[inline]
pub fn new(x: T, y: T, z: T) -> Self {
TypedVector3D { x: x, y: y, z: z, _unit: PhantomData }
}
/// Constructor taking properly typed Lengths instead of scalar values.
#[inline]
pub fn from_lengths(x: Length<T, U>, y: Length<T, U>, z: Length<T, U>) -> TypedVector3D<T, U> {
vec3(x.0, y.0, z.0)
}
/// Cast this vector into a point.
///
/// Equivalent to adding this vector to the origin.
#[inline]
pub fn to_point(&self) -> TypedPoint3D<T, U> {
point3(self.x, self.y, self.z)
}
/// Returns self.x as a Length carrying the unit.
#[inline]
pub fn x_typed(&self) -> Length<T, U> { Length::new(self.x) }
/// Returns self.y as a Length carrying the unit.
#[inline]
pub fn y_typed(&self) -> Length<T, U> { Length::new(self.y) }
/// Returns self.z as a Length carrying the unit.
#[inline]
pub fn z_typed(&self) -> Length<T, U> { Length::new(self.z) }
#[inline]
pub fn to_array(&self) -> [T; 3] { [self.x, self.y, self.z] }
/// Drop the units, preserving only the numeric value.
#[inline]
pub fn to_untyped(&self) -> Vector3D<T> {
vec3(self.x, self.y, self.z)
}
/// Tag a unitless value with units.
#[inline]
pub fn from_untyped(p: &Vector3D<T>) -> Self {
vec3(p.x, p.y, p.z)
}
/// Convert into a 2d vector.
#[inline]
pub fn to_2d(&self) -> TypedVector2D<T, U> {
vec2(self.x, self.y)
}
}
impl<T: Mul<T, Output=T> +
Add<T, Output=T> +
Sub<T, Output=T> +
Copy, U> TypedVector3D<T, U> {
// Dot product.
#[inline]
pub fn dot(self, other: Self) -> T {
self.x * other.x +
self.y * other.y +
self.z * other.z
}
// Cross product.
#[inline]
pub fn cross(self, other: Self) -> Self {
vec3(
self.y * other.z - self.z * other.y,
self.z * other.x - self.x * other.z,
self.x * other.y - self.y * other.x
)
}
#[inline]
pub fn normalize(self) -> Self where T: Float + ApproxEq<T> {
let dot = self.dot(self);
if dot.approx_eq(&T::zero()) {
self
} else {
self / dot.sqrt()
}
}
#[inline]
pub fn square_length(&self) -> T {
self.x * self.x + self.y * self.y + self.z * self.z
}
#[inline]
pub fn length(&self) -> T where T: Float + ApproxEq<T> {
self.square_length().sqrt()
}
}
impl<T, U> TypedVector3D<T, U>
where T: Copy + One + Add<Output=T> + Sub<Output=T> + Mul<Output=T> {
/// Linearly interpolate between this vector and another vector.
///
/// `t` is expected to be between zero and one.
#[inline]
pub fn lerp(&self, other: Self, t: T) -> Self {
let one_t = T::one() - t;
(*self) * one_t + other * t
}
}
impl<T: Copy + Add<T, Output=T>, U> Add for TypedVector3D<T, U> {
type Output = Self;
#[inline]
fn add(self, other: Self) -> Self {
vec3(self.x + other.x, self.y + other.y, self.z + other.z)
}
}
impl<T: Copy + Sub<T, Output=T>, U> Sub for TypedVector3D<T, U> {
type Output = Self;
#[inline]
fn sub(self, other: Self) -> Self {
vec3(self.x - other.x, self.y - other.y, self.z - other.z)
}
}
impl<T: Copy + Add<T, Output=T>, U> AddAssign for TypedVector3D<T, U> {
#[inline]
fn add_assign(&mut self, other: Self) {
*self = *self + other
}
}
impl<T: Copy + Sub<T, Output=T>, U> SubAssign<TypedVector3D<T, U>> for TypedVector3D<T, U> {
#[inline]
fn sub_assign(&mut self, other: Self) {
*self = *self - other
}
}
impl <T: Copy + Neg<Output=T>, U> Neg for TypedVector3D<T, U> {
type Output = Self;
#[inline]
fn neg(self) -> Self {
vec3(-self.x, -self.y, -self.z)
}
}
impl<T: Copy + Mul<T, Output=T>, U> Mul<T> for TypedVector3D<T, U> {
type Output = Self;
#[inline]
fn mul(self, scale: T) -> Self {
Self::new(self.x * scale, self.y * scale, self.z * scale)
}
}
impl<T: Copy + Div<T, Output=T>, U> Div<T> for TypedVector3D<T, U> {
type Output = Self;
#[inline]
fn div(self, scale: T) -> Self {
Self::new(self.x / scale, self.y / scale, self.z / scale)
}
}
impl<T: Copy + Mul<T, Output=T>, U> MulAssign<T> for TypedVector3D<T, U> {
#[inline]
fn mul_assign(&mut self, scale: T) {
*self = *self * scale
}
}
impl<T: Copy + Div<T, Output=T>, U> DivAssign<T> for TypedVector3D<T, U> {
#[inline]
fn div_assign(&mut self, scale: T) {
*self = *self / scale
}
}
impl<T: Float, U> TypedVector3D<T, U> {
#[inline]
pub fn min(self, other: Self) -> Self {
vec3(self.x.min(other.x), self.y.min(other.y), self.z.min(other.z))
}
#[inline]
pub fn max(self, other: Self) -> Self {
vec3(self.x.max(other.x), self.y.max(other.y), self.z.max(other.z))
}
}
impl<T: Round, U> TypedVector3D<T, U> {
/// Rounds each component to the nearest integer value.
///
/// This behavior is preserved for negative values (unlike the basic cast).
#[inline]
#[must_use]
pub fn round(&self) -> Self {
vec3(self.x.round(), self.y.round(), self.z.round())
}
}
impl<T: Ceil, U> TypedVector3D<T, U> {
/// Rounds each component to the smallest integer equal or greater than the original value.
///
/// This behavior is preserved for negative values (unlike the basic cast).
#[inline]
#[must_use]
pub fn ceil(&self) -> Self {
vec3(self.x.ceil(), self.y.ceil(), self.z.ceil())
}
}
impl<T: Floor, U> TypedVector3D<T, U> {
/// Rounds each component to the biggest integer equal or lower than the original value.
///
/// This behavior is preserved for negative values (unlike the basic cast).
#[inline]
#[must_use]
pub fn floor(&self) -> Self {
vec3(self.x.floor(), self.y.floor(), self.z.floor())
}
}
impl<T: NumCast + Copy, U> TypedVector3D<T, U> {
/// Cast from one numeric representation to another, preserving the units.
///
/// When casting from floating vector to integer coordinates, the decimals are truncated
/// as one would expect from a simple cast, but this behavior does not always make sense
/// geometrically. Consider using round(), ceil or floor() before casting.
#[inline]
pub fn cast<NewT: NumCast + Copy>(&self) -> Option<TypedVector3D<NewT, U>> {
match (NumCast::from(self.x),
NumCast::from(self.y),
NumCast::from(self.z)) {
(Some(x), Some(y), Some(z)) => Some(vec3(x, y, z)),
_ => None
}
}
// Convenience functions for common casts
/// Cast into an `f32` vector.
#[inline]
pub fn to_f32(&self) -> TypedVector3D<f32, U> {
self.cast().unwrap()
}
/// Cast into an `usize` vector, truncating decimals if any.
///
/// When casting from floating vector vectors, it is worth considering whether
/// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
/// the desired conversion behavior.
#[inline]
pub fn to_usize(&self) -> TypedVector3D<usize, U> {
self.cast().unwrap()
}
/// Cast into an `i32` vector, truncating decimals if any.
///
/// When casting from floating vector vectors, it is worth considering whether
/// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
/// the desired conversion behavior.
#[inline]
pub fn to_i32(&self) -> TypedVector3D<i32, U> {
self.cast().unwrap()
}
/// Cast into an `i64` vector, truncating decimals if any.
///
/// When casting from floating vector vectors, it is worth considering whether
/// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
/// the desired conversion behavior.
#[inline]
pub fn to_i64(&self) -> TypedVector3D<i64, U> {
self.cast().unwrap()
}
}
impl<T: Copy+ApproxEq<T>, U> ApproxEq<TypedVector3D<T, U>> for TypedVector3D<T, U> {
#[inline]
fn approx_epsilon() -> Self {
vec3(T::approx_epsilon(), T::approx_epsilon(), T::approx_epsilon())
}
#[inline]
fn approx_eq(&self, other: &Self) -> bool {
self.x.approx_eq(&other.x)
&& self.y.approx_eq(&other.y)
&& self.z.approx_eq(&other.z)
}
#[inline]
fn approx_eq_eps(&self, other: &Self, eps: &Self) -> bool {
self.x.approx_eq_eps(&other.x, &eps.x)
&& self.y.approx_eq_eps(&other.y, &eps.y)
&& self.z.approx_eq_eps(&other.z, &eps.z)
}
}
impl<T: Copy, U> Into<[T; 3]> for TypedVector3D<T, U> {
fn into(self) -> [T; 3] {
self.to_array()
}
}
impl<T: Copy, U> From<[T; 3]> for TypedVector3D<T, U> {
fn from(array: [T; 3]) -> Self {
vec3(array[0], array[1], array[2])
}
}
/// Convenience constructor.
#[inline]
pub fn vec2<T: Copy, U>(x: T, y: T) -> TypedVector2D<T, U> {
TypedVector2D::new(x, y)
}
/// Convenience constructor.
#[inline]
pub fn vec3<T: Copy, U>(x: T, y: T, z: T) -> TypedVector3D<T, U> {
TypedVector3D::new(x, y, z)
}
#[cfg(test)]
mod vector2d {
use super::{Vector2D, vec2};
type Vec2 = Vector2D<f32>;
#[test]
pub fn test_scalar_mul() {
let p1: Vec2 = vec2(3.0, 5.0);
let result = p1 * 5.0;
assert_eq!(result, Vector2D::new(15.0, 25.0));
}
#[test]
pub fn test_dot() {
let p1: Vec2 = vec2(2.0, 7.0);
let p2: Vec2 = vec2(13.0, 11.0);
assert_eq!(p1.dot(p2), 103.0);
}
#[test]
pub fn test_cross() {
let p1: Vec2 = vec2(4.0, 7.0);
let p2: Vec2 = vec2(13.0, 8.0);
let r = p1.cross(p2);
assert_eq!(r, -59.0);
}
#[test]
pub fn test_normalize() {
let p0: Vec2 = Vec2::zero();
let p1: Vec2 = vec2(4.0, 0.0);
let p2: Vec2 = vec2(3.0, -4.0);
assert_eq!(p0.normalize(), p0);
assert_eq!(p1.normalize(), vec2(1.0, 0.0));
assert_eq!(p2.normalize(), vec2(0.6, -0.8));
}
#[test]
pub fn test_min() {
let p1: Vec2 = vec2(1.0, 3.0);
let p2: Vec2 = vec2(2.0, 2.0);
let result = p1.min(p2);
assert_eq!(result, vec2(1.0, 2.0));
}
#[test]
pub fn test_max() {
let p1: Vec2 = vec2(1.0, 3.0);
let p2: Vec2 = vec2(2.0, 2.0);
let result = p1.max(p2);
assert_eq!(result, vec2(2.0, 3.0));
}
}
#[cfg(test)]
mod typedvector2d {
use super::{TypedVector2D, vec2};
use scale_factor::ScaleFactor;
pub enum Mm {}
pub enum Cm {}
pub type Vector2DMm<T> = TypedVector2D<T, Mm>;
pub type Vector2DCm<T> = TypedVector2D<T, Cm>;
#[test]
pub fn test_add() {
let p1 = Vector2DMm::new(1.0, 2.0);
let p2 = Vector2DMm::new(3.0, 4.0);
let result = p1 + p2;
assert_eq!(result, vec2(4.0, 6.0));
}
#[test]
pub fn test_add_assign() {
let mut p1 = Vector2DMm::new(1.0, 2.0);
p1 += vec2(3.0, 4.0);
assert_eq!(p1, vec2(4.0, 6.0));
}
#[test]
pub fn test_scalar_mul() {
let p1 = Vector2DMm::new(1.0, 2.0);
let cm_per_mm: ScaleFactor<f32, Mm, Cm> = ScaleFactor::new(0.1);
let result: Vector2DCm<f32> = p1 * cm_per_mm;
assert_eq!(result, vec2(0.1, 0.2));
}
}
#[cfg(test)]
mod vector3d {
use super::{Vector3D, vec3};
type Vec3 = Vector3D<f32>;
#[test]
pub fn test_dot() {
let p1: Vec3 = vec3(7.0, 21.0, 32.0);
let p2: Vec3 = vec3(43.0, 5.0, 16.0);
assert_eq!(p1.dot(p2), 918.0);
}
#[test]
pub fn test_cross() {
let p1: Vec3 = vec3(4.0, 7.0, 9.0);
let p2: Vec3 = vec3(13.0, 8.0, 3.0);
let p3 = p1.cross(p2);
assert_eq!(p3, vec3(-51.0, 105.0, -59.0));
}
#[test]
pub fn test_normalize() {
let p0: Vec3 = Vec3::zero();
let p1: Vec3 = vec3(0.0, -6.0, 0.0);
let p2: Vec3 = vec3(1.0, 2.0, -2.0);
assert_eq!(p0.normalize(), p0);
assert_eq!(p1.normalize(), vec3(0.0, -1.0, 0.0));
assert_eq!(p2.normalize(), vec3(1.0/3.0, 2.0/3.0, -2.0/3.0));
}
#[test]
pub fn test_min() {
let p1: Vec3 = vec3(1.0, 3.0, 5.0);
let p2: Vec3 = vec3(2.0, 2.0, -1.0);
let result = p1.min(p2);
assert_eq!(result, vec3(1.0, 2.0, -1.0));
}
#[test]
pub fn test_max() {
let p1: Vec3 = vec3(1.0, 3.0, 5.0);
let p2: Vec3 = vec3(2.0, 2.0, -1.0);
let result = p1.max(p2);
assert_eq!(result, vec3(2.0, 3.0, 5.0));
}
}

Просмотреть файл

@ -1 +1 @@
{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".gitignore":"f9b1ca6ae27d1c18215265024629a8960c31379f206d9ed20f64e0b2dcf79805",".travis.yml":"b76d49f66f842c652d40825c67791352364a6b6bbb7d8d1009f2ac79eb413e66","Cargo.toml":"42a432c2bd866b37698e064e7f72b6cf96d7aa57dcc5ae32c9474bd6eef745a2","LICENSE":"b946744aeda89b467929585fe8eeb5461847695220c1b168fb375d8abd4ea3d0","README.md":"62f99334c17b451342fcea70eb1cc27b26612616b7c1a58fab50dd493f766f32","benches/split.rs":"dfe01759652e2098f20547e0ddcc1b2937e88c6d6ddb025353c037a46b7ef85d","src/bsp.rs":"66e1690aa8540f744ee013ac0e550ecdee84633727cb3a2d8239db3597ad25d6","src/lib.rs":"21d6135c10dd820c2b9ac484cc018e1149f2bf44c315d27134edd3ecb8a7f3d2","src/naive.rs":"444d3298224009209ae329458fe8df953193b15a04da29cdd6f498572a6471bf","tests/main.rs":"d65d7fe01ff3091a9b470a2f26b28108968ca5d32a5a14defba4336df31c7d7f","tests/split.rs":"19d5bfaaf93115ddecdac0f720893c61b2ed73a0bcb4711534ac7e4500cc06ae"},"package":"da4c13e9ba1388fd628ec2bcd69f3346dec64357e9b552601b244f92189d4610"}
{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".gitignore":"f9b1ca6ae27d1c18215265024629a8960c31379f206d9ed20f64e0b2dcf79805",".travis.yml":"b76d49f66f842c652d40825c67791352364a6b6bbb7d8d1009f2ac79eb413e66","Cargo.toml":"6a8c18281f4854b2f184e335d2efb7702ed920f3e66adbe84ce2013215215068","LICENSE":"b946744aeda89b467929585fe8eeb5461847695220c1b168fb375d8abd4ea3d0","README.md":"62f99334c17b451342fcea70eb1cc27b26612616b7c1a58fab50dd493f766f32","benches/split.rs":"49befe22321f34280106fdea53d93644b7757873407376247f86f9d55d09b4ab","src/bsp.rs":"1bc961e97b47f6d918384858310c60a20f9490e11404a89f379a2ad6c5705071","src/lib.rs":"c7f52a46d9ebdb9c1346b39312110aaba75821297e5f446c81a8a25706d850f5","src/naive.rs":"c7e50de094d24b609f03e3dc9599bb040a6baef84bce93ffab7af7f049fb805b","tests/main.rs":"915d915c5ca82befef82f1604cc974b072238a8d69043341589d8dd569d412d3","tests/split.rs":"a4681a788f9a9a515d4084d97ba33406a54bc0725711ade9fc955348d1703368"},"package":"f00d5b0bef85e7e218329cde2f9b75784967c62c0cc9b7faa491d81c2d35eb2a"}

4
third_party/rust/plane-split/Cargo.toml поставляемый
Просмотреть файл

@ -1,6 +1,6 @@
[package]
name = "plane-split"
version = "0.5.0"
version = "0.4.1"
description = "Plane splitting"
authors = ["Dzmitry Malyshau <kvark@mozilla.com>"]
license = "MPL-2.0"
@ -10,6 +10,6 @@ documentation = "https://docs.rs/plane-split"
[dependencies]
binary-space-partition = "0.1.2"
euclid = "0.14.2"
euclid = "0.13"
log = "0.3"
num-traits = {version = "0.1.37", default-features = false}

Просмотреть файл

@ -5,14 +5,14 @@ extern crate plane_split;
extern crate test;
use std::sync::Arc;
use euclid::vec3;
use euclid::TypedPoint3D;
use plane_split::{BspSplitter, NaiveSplitter, Splitter, _make_grid};
#[bench]
fn bench_naive(b: &mut test::Bencher) {
let polys = Arc::new(_make_grid(5));
let mut splitter = NaiveSplitter::new();
let view = vec3(0.0, 0.0, 1.0);
let view = TypedPoint3D::new(0.0, 0.0, 1.0);
b.iter(|| {
let p = polys.clone();
splitter.solve(&p, view);
@ -23,7 +23,7 @@ fn bench_naive(b: &mut test::Bencher) {
fn bench_bsp(b: &mut test::Bencher) {
let polys = Arc::new(_make_grid(5));
let mut splitter = BspSplitter::new();
let view = vec3(0.0, 0.0, 1.0);
let view = TypedPoint3D::new(0.0, 0.0, 1.0);
b.iter(|| {
let p = polys.clone();
splitter.solve(&p, view);

6
third_party/rust/plane-split/src/bsp.rs поставляемый
Просмотреть файл

@ -1,5 +1,5 @@
use binary_space_partition::{BspNode, Plane, PlaneCut};
use euclid::{TypedPoint3D, TypedVector3D};
use euclid::TypedPoint3D;
use euclid::approxeq::ApproxEq;
use num_traits::{Float, One, Zero};
use std::{fmt, ops};
@ -96,10 +96,10 @@ impl<T, U> Splitter<T, U> for BspSplitter<T, U> where
self.tree.insert(poly);
}
fn sort(&mut self, view: TypedVector3D<T, U>) -> &[Polygon<T, U>] {
fn sort(&mut self, view: TypedPoint3D<T, U>) -> &[Polygon<T, U>] {
//debug!("\t\ttree before sorting {:?}", self.tree);
let poly = Polygon {
points: [TypedPoint3D::origin(); 4],
points: [TypedPoint3D::zero(); 4],
normal: -view, //Note: BSP `order()` is back to front
offset: T::zero(),
anchor: 0,

39
third_party/rust/plane-split/src/lib.rs поставляемый
Просмотреть файл

@ -20,9 +20,9 @@ mod bsp;
mod naive;
use std::{fmt, mem, ops};
use euclid::{Point2D, TypedTransform3D, TypedPoint3D, TypedVector3D, TypedRect};
use euclid::{Point2D, TypedMatrix4D, TypedPoint3D, TypedRect};
use euclid::approxeq::ApproxEq;
use euclid::Trig;
use euclid::trig::Trig;
use num_traits::{Float, One, Zero};
pub use self::bsp::BspSplitter;
@ -35,7 +35,7 @@ fn is_zero<T>(value: T) -> bool where
(value * value).approx_eq(&T::zero())
}
fn is_zero_vec<T, U>(vec: TypedVector3D<T, U>) -> bool where
fn is_zero_vec<T, U>(vec: TypedPoint3D<T, U>) -> bool where
T: Copy + Zero + ApproxEq<T> +
ops::Add<T, Output=T> + ops::Sub<T, Output=T> + ops::Mul<T, Output=T> {
vec.dot(vec).approx_eq(&T::zero())
@ -47,7 +47,7 @@ pub struct Line<T, U> {
/// Arbitrary point on the line.
pub origin: TypedPoint3D<T, U>,
/// Normalized direction of the line.
pub dir: TypedVector3D<T, U>,
pub dir: TypedPoint3D<T, U>,
}
impl<T, U> Line<T, U> where
@ -73,7 +73,7 @@ pub struct Polygon<T, U> {
/// Points making the polygon.
pub points: [TypedPoint3D<T, U>; 4],
/// Normalized vector perpendicular to the polygon plane.
pub normal: TypedVector3D<T, U>,
pub normal: TypedPoint3D<T, U>,
/// Constant offset from the normal plane, specified in the
/// direction opposite to the normal.
pub offset: T,
@ -179,7 +179,7 @@ impl<T, U> Polygon<T, U> where
{
/// Construct a polygon from a transformed rectangle.
pub fn from_transformed_rect<V>(rect: TypedRect<T, V>,
transform: TypedTransform3D<T, V, U>,
transform: TypedMatrix4D<T, V, U>,
anchor: usize)
-> Polygon<T, U>
where T: Trig + ops::Neg<Output=T> {
@ -196,7 +196,7 @@ impl<T, U> Polygon<T, U> where
let normal = (points[1] - points[0]).cross(points[2] - points[0])
.normalize();
let offset = -TypedVector3D::new(transform.m41, transform.m42, transform.m43).dot(normal);
let offset = -TypedPoint3D::new(transform.m41, transform.m42, transform.m43).dot(normal);
Polygon {
points: points,
@ -231,7 +231,7 @@ impl<T, U> Polygon<T, U> where
/// The distance is negative if the point is on the other side of the polygon
/// from the direction of the normal.
pub fn signed_distance_to(&self, point: &TypedPoint3D<T, U>) -> T {
point.to_vector().dot(self.normal) + self.offset
point.dot(self.normal) + self.offset
}
/// Compute the distance across the line to the polygon plane,
@ -283,13 +283,13 @@ impl<T, U> Polygon<T, U> where
/// Project this polygon onto a 3D vector, returning a line projection.
/// Note: we can think of it as a projection to a ray placed at the origin.
pub fn project_on(&self, vector: &TypedVector3D<T, U>) -> LineProjection<T> {
pub fn project_on(&self, vector: &TypedPoint3D<T, U>) -> LineProjection<T> {
LineProjection {
markers: [
vector.dot(self.points[0].to_vector()),
vector.dot(self.points[1].to_vector()),
vector.dot(self.points[2].to_vector()),
vector.dot(self.points[3].to_vector()),
vector.dot(self.points[0]),
vector.dot(self.points[1]),
vector.dot(self.points[2]),
vector.dot(self.points[3]),
],
}
}
@ -321,8 +321,7 @@ impl<T, U> Polygon<T, U> where
// v = (d2*w - d1) / (1 - w*w) * n1 - (d2 - d1*w) / (1 - w*w) * n2
let w = self.normal.dot(other.normal);
let factor = T::one() / (T::one() - w * w);
let center = TypedPoint3D::origin() +
self.normal * ((other.offset * w - self.offset) * factor) -
let center = self.normal * ((other.offset * w - self.offset) * factor) -
other.normal* ((other.offset - self.offset * w) * factor);
Intersection::Inside(Line {
origin: center,
@ -444,10 +443,10 @@ pub trait Splitter<T, U> {
/// Sort the produced polygon set by the ascending distance across
/// the specified view vector. Return the sorted slice.
fn sort(&mut self, TypedVector3D<T, U>) -> &[Polygon<T, U>];
fn sort(&mut self, TypedPoint3D<T, U>) -> &[Polygon<T, U>];
/// Process a set of polygons at once.
fn solve(&mut self, input: &[Polygon<T, U>], view: TypedVector3D<T, U>)
fn solve(&mut self, input: &[Polygon<T, U>], view: TypedPoint3D<T, U>)
-> &[Polygon<T, U>]
where T: Clone, U: Clone {
self.reset();
@ -471,7 +470,7 @@ pub fn _make_grid(count: usize) -> Vec<Polygon<f32, ()>> {
TypedPoint3D::new(len, i as f32, len),
TypedPoint3D::new(0.0, i as f32, len),
],
normal: TypedVector3D::new(0.0, 1.0, 0.0),
normal: TypedPoint3D::new(0.0, 1.0, 0.0),
offset: -(i as f32),
anchor: 0,
}));
@ -482,7 +481,7 @@ pub fn _make_grid(count: usize) -> Vec<Polygon<f32, ()>> {
TypedPoint3D::new(i as f32, len, len),
TypedPoint3D::new(i as f32, 0.0, len),
],
normal: TypedVector3D::new(1.0, 0.0, 0.0),
normal: TypedPoint3D::new(1.0, 0.0, 0.0),
offset: -(i as f32),
anchor: 0,
}));
@ -493,7 +492,7 @@ pub fn _make_grid(count: usize) -> Vec<Polygon<f32, ()>> {
TypedPoint3D::new(len, len, i as f32),
TypedPoint3D::new(0.0, len, i as f32),
],
normal: TypedVector3D::new(0.0, 0.0, 1.0),
normal: TypedPoint3D::new(0.0, 0.0, 1.0),
offset: -(i as f32),
anchor: 0,
}));

14
third_party/rust/plane-split/src/naive.rs поставляемый
Просмотреть файл

@ -1,7 +1,7 @@
use std::{fmt, ops};
use std::cmp::Ordering;
use {Intersection, Line, Polygon, Splitter};
use euclid::TypedVector3D;
use euclid::TypedPoint3D;
use euclid::approxeq::ApproxEq;
use num_traits::{Float, One, Zero};
@ -27,8 +27,8 @@ impl<T, U> NaiveSplitter<T, U> {
/// Find a closest intersection point between two polygons,
/// across the specified direction.
fn intersect_across<T, U>(a: &Polygon<T, U>, b: &Polygon<T, U>,
dir: TypedVector3D<T, U>)
-> TypedVector3D<T, U>
dir: TypedPoint3D<T, U>)
-> TypedPoint3D<T, U>
where
T: Copy + fmt::Debug + PartialOrd + ApproxEq<T> +
ops::Sub<T, Output=T> + ops::Add<T, Output=T> +
@ -136,11 +136,11 @@ impl<
}
//TODO: verify/prove that the sorting approach is consistent
fn sort(&mut self, view: TypedVector3D<T, U>) -> &[Polygon<T, U>] {
fn sort(&mut self, view: TypedPoint3D<T, U>) -> &[Polygon<T, U>] {
// choose the most perpendicular axis among these two
let axis_pre = {
let axis_pre0 = TypedVector3D::new(T::one(), T::zero(), T::zero());
let axis_pre1 = TypedVector3D::new(T::zero(), T::one(), T::zero());
let axis_pre0 = TypedPoint3D::new(T::one(), T::zero(), T::zero());
let axis_pre1 = TypedPoint3D::new(T::zero(), T::one(), T::zero());
if view.dot(axis_pre0).abs() < view.dot(axis_pre1).abs() {
axis_pre0
} else {
@ -160,7 +160,7 @@ impl<
let comp_y = intersect_across(a, b, axis_y);
// line that tries to intersect both
let line = Line {
origin: (comp_x + comp_y).to_point(),
origin: comp_x + comp_y,
dir: view,
};
debug!("\t\tGot {:?}", line);

148
third_party/rust/plane-split/tests/main.rs поставляемый
Просмотреть файл

@ -1,7 +1,7 @@
extern crate euclid;
extern crate plane_split;
use euclid::{Radians, TypedRect, TypedSize2D, TypedTransform3D, point2, point3, vec3};
use euclid::{Point2D, Radians, TypedPoint2D, TypedPoint3D, TypedRect, TypedSize2D, TypedMatrix4D};
use euclid::approxeq::ApproxEq;
use plane_split::{Intersection, Line, LineProjection, Polygon};
@ -16,36 +16,36 @@ fn line_proj_bounds() {
fn valid() {
let poly_a: Polygon<f32, ()> = Polygon {
points: [
point3(0.0, 0.0, 0.0),
point3(1.0, 1.0, 1.0),
point3(1.0, 1.0, 0.0),
point3(0.0, 1.0, 1.0),
TypedPoint3D::new(0.0, 0.0, 0.0),
TypedPoint3D::new(1.0, 1.0, 1.0),
TypedPoint3D::new(1.0, 1.0, 0.0),
TypedPoint3D::new(0.0, 1.0, 1.0),
],
normal: vec3(0.0, 1.0, 0.0),
normal: TypedPoint3D::new(0.0, 1.0, 0.0),
offset: -1.0,
anchor: 0,
};
assert!(!poly_a.is_valid()); // points[0] is outside
let poly_b: Polygon<f32, ()> = Polygon {
points: [
point3(0.0, 1.0, 0.0),
point3(1.0, 1.0, 1.0),
point3(1.0, 1.0, 0.0),
point3(0.0, 1.0, 1.0),
TypedPoint3D::new(0.0, 1.0, 0.0),
TypedPoint3D::new(1.0, 1.0, 1.0),
TypedPoint3D::new(1.0, 1.0, 0.0),
TypedPoint3D::new(0.0, 1.0, 1.0),
],
normal: vec3(0.0, 1.0, 0.0),
normal: TypedPoint3D::new(0.0, 1.0, 0.0),
offset: -1.0,
anchor: 0,
};
assert!(!poly_b.is_valid()); // winding is incorrect
let poly_c: Polygon<f32, ()> = Polygon {
points: [
point3(0.0, 0.0, 1.0),
point3(1.0, 0.0, 1.0),
point3(1.0, 1.0, 1.0),
point3(0.0, 1.0, 1.0),
TypedPoint3D::new(0.0, 0.0, 1.0),
TypedPoint3D::new(1.0, 0.0, 1.0),
TypedPoint3D::new(1.0, 1.0, 1.0),
TypedPoint3D::new(0.0, 1.0, 1.0),
],
normal: vec3(0.0, 0.0, 1.0),
normal: TypedPoint3D::new(0.0, 0.0, 1.0),
offset: -1.0,
anchor: 0,
};
@ -54,10 +54,10 @@ fn valid() {
#[test]
fn from_transformed_rect() {
let rect: TypedRect<f32, ()> = TypedRect::new(point2(10.0, 10.0), TypedSize2D::new(20.0, 30.0));
let transform: TypedTransform3D<f32, (), ()> =
TypedTransform3D::create_rotation(0.5f32.sqrt(), 0.0, 0.5f32.sqrt(), Radians::new(5.0))
.pre_translate(vec3(0.0, 0.0, 10.0));
let rect: TypedRect<f32, ()> = TypedRect::new(TypedPoint2D::new(10.0, 10.0), TypedSize2D::new(20.0, 30.0));
let transform: TypedMatrix4D<f32, (), ()> =
TypedMatrix4D::create_rotation(0.5f32.sqrt(), 0.0, 0.5f32.sqrt(), Radians::new(5.0))
.pre_translated(0.0, 0.0, 10.0);
let poly = Polygon::from_transformed_rect(rect, transform, 0);
assert!(poly.is_valid());
}
@ -66,45 +66,45 @@ fn from_transformed_rect() {
fn untransform_point() {
let poly: Polygon<f32, ()> = Polygon {
points: [
point3(0.0, 0.0, 0.0),
point3(0.5, 1.0, 0.0),
point3(1.5, 1.0, 0.0),
point3(1.0, 0.0, 0.0),
TypedPoint3D::new(0.0, 0.0, 0.0),
TypedPoint3D::new(0.5, 1.0, 0.0),
TypedPoint3D::new(1.5, 1.0, 0.0),
TypedPoint3D::new(1.0, 0.0, 0.0),
],
normal: vec3(0.0, 1.0, 0.0),
normal: TypedPoint3D::new(0.0, 1.0, 0.0),
offset: 0.0,
anchor: 0,
};
assert_eq!(poly.untransform_point(poly.points[0]), point2(0.0, 0.0));
assert_eq!(poly.untransform_point(poly.points[1]), point2(1.0, 0.0));
assert_eq!(poly.untransform_point(poly.points[2]), point2(1.0, 1.0));
assert_eq!(poly.untransform_point(poly.points[3]), point2(0.0, 1.0));
assert_eq!(poly.untransform_point(poly.points[0]), Point2D::new(0.0, 0.0));
assert_eq!(poly.untransform_point(poly.points[1]), Point2D::new(1.0, 0.0));
assert_eq!(poly.untransform_point(poly.points[2]), Point2D::new(1.0, 1.0));
assert_eq!(poly.untransform_point(poly.points[3]), Point2D::new(0.0, 1.0));
}
#[test]
fn are_outside() {
let poly: Polygon<f32, ()> = Polygon {
points: [
point3(0.0, 0.0, 1.0),
point3(1.0, 0.0, 1.0),
point3(1.0, 1.0, 1.0),
point3(0.0, 1.0, 1.0),
TypedPoint3D::new(0.0, 0.0, 1.0),
TypedPoint3D::new(1.0, 0.0, 1.0),
TypedPoint3D::new(1.0, 1.0, 1.0),
TypedPoint3D::new(0.0, 1.0, 1.0),
],
normal: vec3(0.0, 0.0, 1.0),
normal: TypedPoint3D::new(0.0, 0.0, 1.0),
offset: -1.0,
anchor: 0,
};
assert!(poly.is_valid());
assert!(poly.are_outside(&[
point3(0.0, 0.0, 1.1),
point3(1.0, 1.0, 2.0),
TypedPoint3D::new(0.0, 0.0, 1.1),
TypedPoint3D::new(1.0, 1.0, 2.0),
]));
assert!(poly.are_outside(&[
point3(0.5, 0.5, 1.0),
TypedPoint3D::new(0.5, 0.5, 1.0),
]));
assert!(!poly.are_outside(&[
point3(0.0, 0.0, 1.0),
point3(0.0, 0.0, -1.0),
TypedPoint3D::new(0.0, 0.0, 1.0),
TypedPoint3D::new(0.0, 0.0, -1.0),
]));
}
@ -112,24 +112,24 @@ fn are_outside() {
fn intersect() {
let poly_a: Polygon<f32, ()> = Polygon {
points: [
point3(0.0, 0.0, 1.0),
point3(1.0, 0.0, 1.0),
point3(1.0, 1.0, 1.0),
point3(0.0, 1.0, 1.0),
TypedPoint3D::new(0.0, 0.0, 1.0),
TypedPoint3D::new(1.0, 0.0, 1.0),
TypedPoint3D::new(1.0, 1.0, 1.0),
TypedPoint3D::new(0.0, 1.0, 1.0),
],
normal: vec3(0.0, 0.0, 1.0),
normal: TypedPoint3D::new(0.0, 0.0, 1.0),
offset: -1.0,
anchor: 0,
};
assert!(poly_a.is_valid());
let poly_b: Polygon<f32, ()> = Polygon {
points: [
point3(0.5, 0.0, 2.0),
point3(0.5, 1.0, 2.0),
point3(0.5, 1.0, 0.0),
point3(0.5, 0.0, 0.0),
TypedPoint3D::new(0.5, 0.0, 2.0),
TypedPoint3D::new(0.5, 1.0, 2.0),
TypedPoint3D::new(0.5, 1.0, 0.0),
TypedPoint3D::new(0.5, 0.0, 0.0),
],
normal: vec3(1.0, 0.0, 0.0),
normal: TypedPoint3D::new(1.0, 0.0, 0.0),
offset: -0.5,
anchor: 0,
};
@ -149,24 +149,24 @@ fn intersect() {
let poly_c: Polygon<f32, ()> = Polygon {
points: [
point3(0.0, -1.0, 2.0),
point3(0.0, -1.0, 0.0),
point3(0.0, 0.0, 0.0),
point3(0.0, 0.0, 2.0),
TypedPoint3D::new(0.0, -1.0, 2.0),
TypedPoint3D::new(0.0, -1.0, 0.0),
TypedPoint3D::new(0.0, 0.0, 0.0),
TypedPoint3D::new(0.0, 0.0, 2.0),
],
normal: vec3(1.0, 0.0, 0.0),
normal: TypedPoint3D::new(1.0, 0.0, 0.0),
offset: 0.0,
anchor: 0,
};
assert!(poly_c.is_valid());
let poly_d: Polygon<f32, ()> = Polygon {
points: [
point3(0.0, 0.0, 0.5),
point3(1.0, 0.0, 0.5),
point3(1.0, 1.0, 0.5),
point3(0.0, 1.0, 0.5),
TypedPoint3D::new(0.0, 0.0, 0.5),
TypedPoint3D::new(1.0, 0.0, 0.5),
TypedPoint3D::new(1.0, 1.0, 0.5),
TypedPoint3D::new(0.0, 1.0, 0.5),
],
normal: vec3(0.0, 0.0, 1.0),
normal: TypedPoint3D::new(0.0, 0.0, 1.0),
offset: -0.5,
anchor: 0,
};
@ -195,43 +195,43 @@ fn test_cut(poly_base: &Polygon<f32, ()>, extra_count: u8, line: Line<f32, ()>)
fn split() {
let poly: Polygon<f32, ()> = Polygon {
points: [
point3(0.0, 1.0, 0.0),
point3(1.0, 1.0, 0.0),
point3(1.0, 1.0, 1.0),
point3(0.0, 1.0, 1.0),
TypedPoint3D::new(0.0, 1.0, 0.0),
TypedPoint3D::new(1.0, 1.0, 0.0),
TypedPoint3D::new(1.0, 1.0, 1.0),
TypedPoint3D::new(0.0, 1.0, 1.0),
],
normal: vec3(0.0, 1.0, 0.0),
normal: TypedPoint3D::new(0.0, 1.0, 0.0),
offset: -1.0,
anchor: 0,
};
// non-intersecting line
test_cut(&poly, 0, Line {
origin: point3(0.0, 1.0, 0.5),
dir: vec3(0.0, 1.0, 0.0),
origin: TypedPoint3D::new(0.0, 1.0, 0.5),
dir: TypedPoint3D::new(0.0, 1.0, 0.0),
});
// simple cut (diff=2)
test_cut(&poly, 1, Line {
origin: point3(0.0, 1.0, 0.5),
dir: vec3(1.0, 0.0, 0.0),
origin: TypedPoint3D::new(0.0, 1.0, 0.5),
dir: TypedPoint3D::new(1.0, 0.0, 0.0),
});
// complex cut (diff=1, wrapped)
test_cut(&poly, 2, Line {
origin: point3(0.0, 1.0, 0.5),
dir: vec3(0.5f32.sqrt(), 0.0, -0.5f32.sqrt()),
origin: TypedPoint3D::new(0.0, 1.0, 0.5),
dir: TypedPoint3D::new(0.5f32.sqrt(), 0.0, -0.5f32.sqrt()),
});
// complex cut (diff=1, non-wrapped)
test_cut(&poly, 2, Line {
origin: point3(0.5, 1.0, 0.0),
dir: vec3(0.5f32.sqrt(), 0.0, 0.5f32.sqrt()),
origin: TypedPoint3D::new(0.5, 1.0, 0.0),
dir: TypedPoint3D::new(0.5f32.sqrt(), 0.0, 0.5f32.sqrt()),
});
// complex cut (diff=3)
test_cut(&poly, 2, Line {
origin: point3(0.5, 1.0, 0.0),
dir: vec3(-0.5f32.sqrt(), 0.0, 0.5f32.sqrt()),
origin: TypedPoint3D::new(0.5, 1.0, 0.0),
dir: TypedPoint3D::new(-0.5f32.sqrt(), 0.0, 0.5f32.sqrt()),
});
}

26
third_party/rust/plane-split/tests/split.rs поставляемый
Просмотреть файл

@ -2,13 +2,13 @@ extern crate euclid;
extern crate plane_split;
use std::f32::consts::FRAC_PI_4;
use euclid::{Radians, TypedTransform3D, TypedRect, vec3};
use euclid::{Radians, TypedMatrix4D, TypedPoint2D, TypedPoint3D, TypedSize2D, TypedRect};
use plane_split::{BspSplitter, NaiveSplitter, Polygon, Splitter, _make_grid};
fn grid_impl(count: usize, splitter: &mut Splitter<f32, ()>) {
let polys = _make_grid(count);
let result = splitter.solve(&polys, vec3(0.0, 0.0, 1.0));
let result = splitter.solve(&polys, TypedPoint3D::new(0.0, 0.0, 1.0));
assert_eq!(result.len(), count + count*count + count*count*count);
}
@ -24,21 +24,21 @@ fn grid_bsp() {
fn sort_rotation(splitter: &mut Splitter<f32, ()>) {
let transform0: TypedTransform3D<f32, (), ()> =
TypedTransform3D::create_rotation(0.0, 1.0, 0.0, Radians::new(-FRAC_PI_4));
let transform1: TypedTransform3D<f32, (), ()> =
TypedTransform3D::create_rotation(0.0, 1.0, 0.0, Radians::new(0.0));
let transform2: TypedTransform3D<f32, (), ()> =
TypedTransform3D::create_rotation(0.0, 1.0, 0.0, Radians::new(FRAC_PI_4));
let transform0: TypedMatrix4D<f32, (), ()> =
TypedMatrix4D::create_rotation(0.0, 1.0, 0.0, Radians::new(-FRAC_PI_4));
let transform1: TypedMatrix4D<f32, (), ()> =
TypedMatrix4D::create_rotation(0.0, 1.0, 0.0, Radians::new(0.0));
let transform2: TypedMatrix4D<f32, (), ()> =
TypedMatrix4D::create_rotation(0.0, 1.0, 0.0, Radians::new(FRAC_PI_4));
let rect: TypedRect<f32, ()> = euclid::rect(-10.0, -10.0, 20.0, 20.0);
let rect: TypedRect<f32, ()> = TypedRect::new(TypedPoint2D::new(-10.0, -10.0), TypedSize2D::new(20.0, 20.0));
let polys = [
Polygon::from_transformed_rect(rect, transform0, 0),
Polygon::from_transformed_rect(rect, transform1, 1),
Polygon::from_transformed_rect(rect, transform2, 2),
];
let result = splitter.solve(&polys, vec3(0.0, 0.0, -1.0));
let result = splitter.solve(&polys, TypedPoint3D::new(0.0, 0.0, -1.0));
let ids: Vec<_> = result.iter().map(|poly| poly.anchor).collect();
assert_eq!(&ids, &[2, 1, 0, 1, 2]);
}
@ -56,13 +56,13 @@ fn rotation_bsp() {
fn sort_trivial(splitter: &mut Splitter<f32, ()>) {
let anchors: Vec<_> = (0usize .. 10).collect();
let rect: TypedRect<f32, ()> = euclid::rect(-10.0, -10.0, 20.0, 20.0);
let rect: TypedRect<f32, ()> = TypedRect::new(TypedPoint2D::new(-10.0, -10.0), TypedSize2D::new(20.0, 20.0));
let polys: Vec<_> = anchors.iter().map(|&anchor| {
let transform: TypedTransform3D<f32, (), ()> = TypedTransform3D::create_translation(0.0, 0.0, anchor as f32);
let transform: TypedMatrix4D<f32, (), ()> = TypedMatrix4D::create_translation(0.0, 0.0, anchor as f32);
Polygon::from_transformed_rect(rect, transform, anchor)
}).collect();
let result = splitter.solve(&polys, vec3(0.0, 0.0, -1.0));
let result = splitter.solve(&polys, TypedPoint3D::new(0.0, 0.0, -1.0));
let anchors1: Vec<_> = result.iter().map(|p| p.anchor).collect();
let mut anchors2 = anchors1.clone();
anchors2.sort_by_key(|&a| -(a as i32));

26
toolkit/library/gtest/rust/Cargo.lock сгенерированный
Просмотреть файл

@ -325,17 +325,6 @@ dependencies = [
"serde 0.9.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "euclid"
version = "0.14.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"heapsize 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 0.9.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "fnv"
version = "1.0.5"
@ -679,11 +668,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "plane-split"
version = "0.5.0"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"binary-space-partition 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -1160,7 +1149,7 @@ dependencies = [
"core-graphics 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"core-text 4.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"dwrote 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
"fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"freetype 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gamma-lut 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1168,7 +1157,7 @@ dependencies = [
"lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
"plane-split 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"plane-split 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_profiler 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1180,7 +1169,7 @@ name = "webrender_bindings"
version = "0.1.0"
dependencies = [
"app_units 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gleam 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_profiler 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1198,7 +1187,7 @@ dependencies = [
"core-foundation 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"core-graphics 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"dwrote 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gleam 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"heapsize 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 0.9.9 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1258,7 +1247,6 @@ dependencies = [
"checksum encoding_rs 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "e00a1b1e95eb46988805ceee6f34cd95c46a6753e290cb3ff0486931989d4a4c"
"checksum env_logger 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ed39959122ea027670b704fb70539f4286ddf4a49eefede23bf0b4b2a069ec03"
"checksum euclid 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6083f113c422ff9cd855a1cf6cc8ec0903606c0eb43a0c6a0ced3bdc9731e4c1"
"checksum euclid 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)" = "995b21c36b37e0f18ed9ba1714378a337e3ff19a6e5e952ea94b0f3dd4e12fbc"
"checksum fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc484842f1e2884faf56f529f960cc12ad8c71ce96cc7abba0a067c98fee344"
"checksum freetype 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fde23272c687e4570aefec06cb71174ec0f5284b725deac4e77ba2665d635faf"
"checksum futures 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "55f0008e13fc853f79ea8fc86e931486860d4c4c156cdffb59fa5f7fa833660a"
@ -1296,7 +1284,7 @@ dependencies = [
"checksum phf_generator 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "6b07ffcc532ccc85e3afc45865469bf5d9e4ef5bfcf9622e3cfe80c2d275ec03"
"checksum phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "07e24b0ca9643bdecd0632f2b3da6b1b89bbb0030e0b992afc1113b23a7bc2f2"
"checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903"
"checksum plane-split 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "da4c13e9ba1388fd628ec2bcd69f3346dec64357e9b552601b244f92189d4610"
"checksum plane-split 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f00d5b0bef85e7e218329cde2f9b75784967c62c0cc9b7faa491d81c2d35eb2a"
"checksum precomputed-hash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf1fc3616b3ef726a847f2cd2388c646ef6a1f1ba4835c2629004da48184150"
"checksum procedural-masquerade 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9f566249236c6ca4340f7ca78968271f0ed2b0f234007a61b66f9ecd0af09260"
"checksum quasi 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18c45c4854d6d1cf5d531db97c75880feb91c958b0720f4ec1057135fec358b3"

26
toolkit/library/rust/Cargo.lock сгенерированный
Просмотреть файл

@ -323,17 +323,6 @@ dependencies = [
"serde 0.9.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "euclid"
version = "0.14.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"heapsize 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 0.9.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "fnv"
version = "1.0.5"
@ -666,11 +655,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "plane-split"
version = "0.5.0"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"binary-space-partition 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -1147,7 +1136,7 @@ dependencies = [
"core-graphics 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"core-text 4.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"dwrote 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
"fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"freetype 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gamma-lut 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1155,7 +1144,7 @@ dependencies = [
"lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
"plane-split 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"plane-split 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_profiler 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1167,7 +1156,7 @@ name = "webrender_bindings"
version = "0.1.0"
dependencies = [
"app_units 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gleam 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_profiler 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1185,7 +1174,7 @@ dependencies = [
"core-foundation 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"core-graphics 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"dwrote 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gleam 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"heapsize 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 0.9.9 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1245,7 +1234,6 @@ dependencies = [
"checksum encoding_rs 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "e00a1b1e95eb46988805ceee6f34cd95c46a6753e290cb3ff0486931989d4a4c"
"checksum env_logger 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ed39959122ea027670b704fb70539f4286ddf4a49eefede23bf0b4b2a069ec03"
"checksum euclid 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6083f113c422ff9cd855a1cf6cc8ec0903606c0eb43a0c6a0ced3bdc9731e4c1"
"checksum euclid 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)" = "995b21c36b37e0f18ed9ba1714378a337e3ff19a6e5e952ea94b0f3dd4e12fbc"
"checksum fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc484842f1e2884faf56f529f960cc12ad8c71ce96cc7abba0a067c98fee344"
"checksum freetype 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fde23272c687e4570aefec06cb71174ec0f5284b725deac4e77ba2665d635faf"
"checksum futures 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "55f0008e13fc853f79ea8fc86e931486860d4c4c156cdffb59fa5f7fa833660a"
@ -1283,7 +1271,7 @@ dependencies = [
"checksum phf_generator 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "6b07ffcc532ccc85e3afc45865469bf5d9e4ef5bfcf9622e3cfe80c2d275ec03"
"checksum phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "07e24b0ca9643bdecd0632f2b3da6b1b89bbb0030e0b992afc1113b23a7bc2f2"
"checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903"
"checksum plane-split 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "da4c13e9ba1388fd628ec2bcd69f3346dec64357e9b552601b244f92189d4610"
"checksum plane-split 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f00d5b0bef85e7e218329cde2f9b75784967c62c0cc9b7faa491d81c2d35eb2a"
"checksum precomputed-hash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf1fc3616b3ef726a847f2cd2388c646ef6a1f1ba4835c2629004da48184150"
"checksum procedural-masquerade 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9f566249236c6ca4340f7ca78968271f0ed2b0f234007a61b66f9ecd0af09260"
"checksum quasi 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18c45c4854d6d1cf5d531db97c75880feb91c958b0720f4ec1057135fec358b3"