<commit_before>/*
 * Implemenation of a bitfield as a vec. Only
 * supports bytes (Vec<u8>) as the underlying
 * storage.
 *
 * A future implementation should be more efficient,
 * this is just to get the job done for now.
 */
extern crate ssz;

use std::cmp::max;

#[derive(Eq, Clone, Default, Debug)]
pub struct BooleanBitfield{
    len: usize,
    vec: Vec<u8>
}

impl BooleanBitfield {
    /// Create a new bitfield with a length of zero.
    pub fn new() -> Self {
        Self {
            len: 0,
            vec: vec![0]
        }
    }

    /// Create a new bitfield of a certain capacity
    pub fn with_capacity(capacity: usize) -> Self {
        let mut vec = Vec::with_capacity(capacity / 8 + 1);
        vec.push(0);
        Self {
            len: 0,
            vec
        }
    }

    /// Read the value of a bit.
    ///
    /// Will return `true` if the bit has been set to `true`
    /// without then being set to `False`.
    pub fn get_bit(&self, i: usize) -> bool {
        let bit = |i: usize| i % 8;
        let byte = |i: usize| i / 8;

        if byte(i) >= self.vec.len() {
            false
        } else {
             self.vec[byte(i)] & (1 << (bit(i) as u8)) != 0
        }
    }

    /// Set the value of a bit.
    ///
    /// If this bit is larger than the length of the underlying byte
    /// array it will be extended.
    pub fn set_bit(&mut self, i: usize, to: bool) {
        let bit = |i: usize| i % 8;
        let byte = |i: usize| i / 8;

        self.len = max(self.len, i + 1);

        if byte(i) >= self.vec.len() {
            self.vec.resize(byte(i) + 1, 0);
        }
        if to {
            self.vec[byte(i)] =
                self.vec[byte(i)] |  (1 << (bit(i) as u8))
        } else {
            self.vec[byte(i)] =
                self.vec[byte(i)] & !(1 << (bit(i) as u8))
        }
    }

    /// Return the "length" of this bitfield. Length is defined as
    /// the highest bit that has been set.
    ///
    /// Note: this is distinct from the length of the underlying
    /// vector.
    pub fn len(&self) -> usize { self.len }

    /// True if no bits have ever been set. A bit that is set and then
    /// unset will still count to the length of the bitfield.
    ///
    /// Note: this is distinct from the length of the underlying
    /// vector.
    pub fn is_empty(&self) -> bool { self.len == 0 }

    /// The number of bytes required to represent the bitfield.
    pub fn num_bytes(&self) -> usize { self.vec.len() }

    /// Iterate through the underlying vector and count the number of
    /// true bits.
    pub fn num_true_bits(&self) -> u64 {
        let mut count: u64 = 0;
        for byte in &self.vec {
            for bit in 0..8 {
                if byte & (1 << (bit as u8)) != 0 {
                    count += 1;
                }
            }
        }
        count
    }

    /// Iterate through the underlying vector and find the highest
    /// set bit. Useful for instantiating a new instance from
    /// some set of bytes.
    pub fn compute_length(bytes: &[u8]) -> usize {
        for byte in (0..bytes.len()).rev() {
            for bit in (0..8).rev() {
                if byte & (1 << (bit as u8)) != 0 {
                    return (byte * 8) + bit
                }
            }
        }
        0
    }

    /// Get the byte at a position, assuming big-endian encoding.
    pub fn get_byte(&self, n: usize) -> Option<&u8> {
        self.vec.get(n)
    }

    /// Clone and return the underlying byte array (`Vec<u8>`).
    pub fn to_vec(&self) -> Vec<u8> {
        self.vec.clone()
    }

    /// Clone and return the underlying byte array (`Vec<u8>`) in big-endinan format.
    pub fn to_be_vec(&self) -> Vec<u8> {
        let mut o = self.vec.clone();
        o.reverse();
        o
    }
}

impl<'a> From<&'a [u8]> for BooleanBitfield {
    fn from(input: &[u8]) -> Self {
        let mut vec = input.to_vec();
        vec.reverse();
        BooleanBitfield {
            vec,
            len: BooleanBitfield::compute_length(input)
        }
    }
}

impl PartialEq for BooleanBitfield {
    fn eq(&self, other: &BooleanBitfield) -> bool {
        (self.vec == other.vec) &
            (self.len == other.len)
    }
}

impl ssz::Encodable for BooleanBitfield {
    fn ssz_append(&self, s: &mut ssz::SszStream) {
        s.append_vec(&self.to_vec());
    }
}

impl ssz::Decodable for BooleanBitfield {
    fn ssz_decode(bytes: &[u8], index: usize)
        -> Result<(Self, usize), ssz::DecodeError>
    {
        let len = ssz::decode::decode_length(
            bytes,
            index,
            ssz::LENGTH_BYTES)?;
        if (ssz::LENGTH_BYTES + len) > bytes.len() {
            return Err(ssz::DecodeError::TooShort);
        }
        if len == 0 {
            Ok((BooleanBitfield::new(),
                index + ssz::LENGTH_BYTES))
        } else {
            let b = BooleanBitfield::
                from(&bytes[(index + 4)..(index + len + 4)]);
            let index = index + ssz::LENGTH_BYTES + len;
            Ok((b, index))
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use ssz::Decodable;

    #[test]
    fn test_ssz_encoding() {
        let mut b = BooleanBitfield::new();
        b.set_bit(8, true);

        let mut stream = ssz::SszStream::new();
        stream.append(&b);

        assert_eq!(stream.drain(), vec![0, 0, 0, 2, 0, 1]);
    }

    #[test]
    fn test_ssz_decoding() {
        /*
         * Correct input
         */
        let input = vec![0, 0, 0, 2, 0, 1];
        let (b, i) = BooleanBitfield::ssz_decode(&input, 0).unwrap();
        assert_eq!(i, 6);
        assert_eq!(b.num_true_bits(), 1);
        assert_eq!(b.get_bit(8), true);

        /*
         * Input too long
         */
        let mut input = vec![0, 0, 0, 2, 0, 1];
        input.push(42);
        let (b, i) = BooleanBitfield::ssz_decode(&input, 0).unwrap();
        assert_eq!(i, 6);
        assert_eq!(b.num_true_bits(), 1);
        assert_eq!(b.get_bit(8), true);

        /*
         * Input too short
         */
        let input = vec![0, 0, 0, 2, 1];
        let res = BooleanBitfield::ssz_decode(&input, 0);
        assert_eq!(res, Err(ssz::DecodeError::TooShort));
    }

    #[test]
    fn test_new_bitfield_len() {
        let b = BooleanBitfield::new();
        assert_eq!(b.len(), 0);
        assert_eq!(b.to_be_vec(), vec![0]);

        let b = BooleanBitfield::with_capacity(100);
        assert_eq!(b.len(), 0);
        assert_eq!(b.to_be_vec(), vec![0]);
    }

    #[test]
    fn test_bitfield_set() {
        let mut b = BooleanBitfield::new();
        b.set_bit(0, false);
        assert_eq!(b.to_be_vec(), [0]);

        b = BooleanBitfield::new();
        b.set_bit(7, true);
        assert_eq!(b.to_be_vec(), [128]);
        b.set_bit(7, false);
        assert_eq!(b.to_be_vec(), [0]);
        assert_eq!(b.len(), 8);

        b = BooleanBitfield::new();
        b.set_bit(7, true);
        b.set_bit(0, true);
        assert_eq!(b.to_be_vec(), [129]);
        b.set_bit(7, false);
        assert_eq!(b.to_be_vec(), [1]);
        assert_eq!(b.len(), 8);

        b = BooleanBitfield::new();
        b.set_bit(8, true);
        assert_eq!(b.to_be_vec(), [1, 0]);
        assert_eq!(b.len(), 9);
        b.set_bit(8, false);
        assert_eq!(b.to_be_vec(), [0, 0]);
        assert_eq!(b.len(), 9);

        b = BooleanBitfield::new();
        b.set_bit(15, true);
        assert_eq!(b.to_be_vec(), [128, 0]);
        b.set_bit(15, false);
        assert_eq!(b.to_be_vec(), [0, 0]);
        assert_eq!(b.len(), 16);

        b = BooleanBitfield::new();
        b.set_bit(8, true);
        b.set_bit(15, true);
        assert_eq!(b.to_be_vec(), [129, 0]);
        b.set_bit(15, false);
        assert_eq!(b.to_be_vec(), [1, 0]);
        assert_eq!(b.len(), 16);
    }

    #[test]
    fn test_bitfield_get() {
        let test_nums = vec![0, 8, 15, 42, 1337];
        for i in test_nums {
            let mut b = BooleanBitfield::new();
            assert_eq!(b.get_bit(i), false);
            b.set_bit(i, true);
            assert_eq!(b.get_bit(i), true);
            b.set_bit(i, true);
        }
    }

    #[test]
    fn test_bitfield_num_true_bits() {
        let mut b = BooleanBitfield::new();
        assert_eq!(b.num_true_bits(), 0);
        b.set_bit(15, true);
        assert_eq!(b.num_true_bits(), 1);
        b.set_bit(15, false);
        assert_eq!(b.num_true_bits(), 0);
        b.set_bit(0, true);
        b.set_bit(7, true);
        b.set_bit(8, true);
        b.set_bit(1337, true);
        assert_eq!(b.num_true_bits(), 4);
    }
}
<commit_msg>Fix bug in boolean bitfield<commit_after>/*
 * Implemenation of a bitfield as a vec. Only
 * supports bytes (Vec<u8>) as the underlying
 * storage.
 *
 * A future implementation should be more efficient,
 * this is just to get the job done for now.
 */
extern crate ssz;

use std::cmp::max;

#[derive(Eq, Clone, Default, Debug)]
pub struct BooleanBitfield{
    len: usize,
    vec: Vec<u8>
}

impl BooleanBitfield {
    /// Create a new bitfield with a length of zero.
    pub fn new() -> Self {
        Self {
            len: 0,
            vec: vec![0]
        }
    }

    /// Create a new bitfield of a certain capacity
    pub fn with_capacity(capacity: usize) -> Self {
        let mut vec = Vec::with_capacity(capacity / 8 + 1);
        vec.push(0);
        Self {
            len: 0,
            vec
        }
    }

    /// Read the value of a bit.
    ///
    /// Will return `true` if the bit has been set to `true`
    /// without then being set to `False`.
    pub fn get_bit(&self, i: usize) -> bool {
        let bit = |i: usize| i % 8;
        let byte = |i: usize| i / 8;

        if byte(i) >= self.vec.len() {
            false
        } else {
             self.vec[byte(i)] & (1 << (bit(i) as u8)) != 0
        }
    }

    /// Set the value of a bit.
    ///
    /// If this bit is larger than the length of the underlying byte
    /// array it will be extended.
    pub fn set_bit(&mut self, i: usize, to: bool) {
        let bit = |i: usize| i % 8;
        let byte = |i: usize| i / 8;

        self.len = max(self.len, i + 1);

        if byte(i) >= self.vec.len() {
            self.vec.resize(byte(i) + 1, 0);
        }
        if to {
            self.vec[byte(i)] =
                self.vec[byte(i)] |  (1 << (bit(i) as u8))
        } else {
            self.vec[byte(i)] =
                self.vec[byte(i)] & !(1 << (bit(i) as u8))
        }
    }

    /// Return the "length" of this bitfield. Length is defined as
    /// the highest bit that has been set.
    ///
    /// Note: this is distinct from the length of the underlying
    /// vector.
    pub fn len(&self) -> usize { self.len }

    /// True if no bits have ever been set. A bit that is set and then
    /// unset will still count to the length of the bitfield.
    ///
    /// Note: this is distinct from the length of the underlying
    /// vector.
    pub fn is_empty(&self) -> bool { self.len == 0 }

    /// The number of bytes required to represent the bitfield.
    pub fn num_bytes(&self) -> usize { self.vec.len() }

    /// Iterate through the underlying vector and count the number of
    /// true bits.
    pub fn num_true_bits(&self) -> u64 {
        let mut count: u64 = 0;
        for byte in &self.vec {
            for bit in 0..8 {
                if byte & (1 << (bit as u8)) != 0 {
                    count += 1;
                }
            }
        }
        count
    }

    /// Iterate through the underlying vector and find the highest
    /// set bit. Useful for instantiating a new instance from
    /// some set of bytes.
    pub fn compute_length(bytes: &[u8]) -> usize {
        for byte in (0..bytes.len()).rev() {
            for bit in (0..8).rev() {
                if bytes[byte] & (1 << (bit as u8)) != 0 {
                    return (byte * 8) + bit + 1
                }
            }
        }
        0
    }

    /// Get the byte at a position, assuming big-endian encoding.
    pub fn get_byte(&self, n: usize) -> Option<&u8> {
        self.vec.get(n)
    }

    /// Clone and return the underlying byte array (`Vec<u8>`).
    pub fn to_vec(&self) -> Vec<u8> {
        self.vec.clone()
    }

    /// Clone and return the underlying byte array (`Vec<u8>`) in big-endinan format.
    pub fn to_be_vec(&self) -> Vec<u8> {
        let mut o = self.vec.clone();
        o.reverse();
        o
    }
}

impl<'a> From<&'a [u8]> for BooleanBitfield {
    fn from(input: &[u8]) -> Self {
        let mut vec = input.to_vec();
        vec.reverse();
        BooleanBitfield {
            vec,
            len: BooleanBitfield::compute_length(input)
        }
    }
}

impl PartialEq for BooleanBitfield {
    fn eq(&self, other: &BooleanBitfield) -> bool {
        (self.vec == other.vec) &
            (self.len == other.len)
    }
}

impl ssz::Encodable for BooleanBitfield {
    fn ssz_append(&self, s: &mut ssz::SszStream) {
        s.append_vec(&self.to_vec());
    }
}

impl ssz::Decodable for BooleanBitfield {
    fn ssz_decode(bytes: &[u8], index: usize)
        -> Result<(Self, usize), ssz::DecodeError>
    {
        let len = ssz::decode::decode_length(
            bytes,
            index,
            ssz::LENGTH_BYTES)?;
        if (ssz::LENGTH_BYTES + len) > bytes.len() {
            return Err(ssz::DecodeError::TooShort);
        }
        if len == 0 {
            Ok((BooleanBitfield::new(),
                index + ssz::LENGTH_BYTES))
        } else {
            let b = BooleanBitfield::
                from(&bytes[(index + 4)..(index + len + 4)]);
            let index = index + ssz::LENGTH_BYTES + len;
            Ok((b, index))
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use ssz::Decodable;

    #[test]
    fn test_new_from_slice() {
        let s = [0];
        let b = BooleanBitfield::from(&s[..]);
        assert_eq!(b.len, 0);

        let s = [255];
        let b = BooleanBitfield::from(&s[..]);
        assert_eq!(b.len, 8);

        let s = [0, 1];
        let b = BooleanBitfield::from(&s[..]);
        assert_eq!(b.len, 9);

        let s = [31];
        let b = BooleanBitfield::from(&s[..]);
        assert_eq!(b.len, 5);
    }

    #[test]
    fn test_ssz_encoding() {
        let mut b = BooleanBitfield::new();
        b.set_bit(8, true);

        let mut stream = ssz::SszStream::new();
        stream.append(&b);

        assert_eq!(stream.drain(), vec![0, 0, 0, 2, 0, 1]);
    }

    #[test]
    fn test_ssz_decoding() {
        /*
         * Correct input
         */
        let input = vec![0, 0, 0, 2, 0, 1];
        let (b, i) = BooleanBitfield::ssz_decode(&input, 0).unwrap();
        assert_eq!(i, 6);
        assert_eq!(b.num_true_bits(), 1);
        assert_eq!(b.get_bit(8), true);

        /*
         * Input too long
         */
        let mut input = vec![0, 0, 0, 2, 0, 1];
        input.push(42);
        let (b, i) = BooleanBitfield::ssz_decode(&input, 0).unwrap();
        assert_eq!(i, 6);
        assert_eq!(b.num_true_bits(), 1);
        assert_eq!(b.get_bit(8), true);

        /*
         * Input too short
         */
        let input = vec![0, 0, 0, 2, 1];
        let res = BooleanBitfield::ssz_decode(&input, 0);
        assert_eq!(res, Err(ssz::DecodeError::TooShort));
    }

    #[test]
    fn test_new_bitfield_len() {
        let b = BooleanBitfield::new();
        assert_eq!(b.len(), 0);
        assert_eq!(b.to_be_vec(), vec![0]);

        let b = BooleanBitfield::with_capacity(100);
        assert_eq!(b.len(), 0);
        assert_eq!(b.to_be_vec(), vec![0]);
    }

    #[test]
    fn test_bitfield_set() {
        let mut b = BooleanBitfield::new();
        b.set_bit(0, false);
        assert_eq!(b.to_be_vec(), [0]);

        b = BooleanBitfield::new();
        b.set_bit(7, true);
        assert_eq!(b.to_be_vec(), [128]);
        b.set_bit(7, false);
        assert_eq!(b.to_be_vec(), [0]);
        assert_eq!(b.len(), 8);

        b = BooleanBitfield::new();
        b.set_bit(7, true);
        b.set_bit(0, true);
        assert_eq!(b.to_be_vec(), [129]);
        b.set_bit(7, false);
        assert_eq!(b.to_be_vec(), [1]);
        assert_eq!(b.len(), 8);

        b = BooleanBitfield::new();
        b.set_bit(8, true);
        assert_eq!(b.to_be_vec(), [1, 0]);
        assert_eq!(b.len(), 9);
        b.set_bit(8, false);
        assert_eq!(b.to_be_vec(), [0, 0]);
        assert_eq!(b.len(), 9);

        b = BooleanBitfield::new();
        b.set_bit(15, true);
        assert_eq!(b.to_be_vec(), [128, 0]);
        b.set_bit(15, false);
        assert_eq!(b.to_be_vec(), [0, 0]);
        assert_eq!(b.len(), 16);

        b = BooleanBitfield::new();
        b.set_bit(8, true);
        b.set_bit(15, true);
        assert_eq!(b.to_be_vec(), [129, 0]);
        b.set_bit(15, false);
        assert_eq!(b.to_be_vec(), [1, 0]);
        assert_eq!(b.len(), 16);
    }

    #[test]
    fn test_bitfield_get() {
        let test_nums = vec![0, 8, 15, 42, 1337];
        for i in test_nums {
            let mut b = BooleanBitfield::new();
            assert_eq!(b.get_bit(i), false);
            b.set_bit(i, true);
            assert_eq!(b.get_bit(i), true);
            b.set_bit(i, true);
        }
    }

    #[test]
    fn test_bitfield_num_true_bits() {
        let mut b = BooleanBitfield::new();
        assert_eq!(b.num_true_bits(), 0);
        b.set_bit(15, true);
        assert_eq!(b.num_true_bits(), 1);
        b.set_bit(15, false);
        assert_eq!(b.num_true_bits(), 0);
        b.set_bit(0, true);
        b.set_bit(7, true);
        b.set_bit(8, true);
        b.set_bit(1337, true);
        assert_eq!(b.num_true_bits(), 4);
    }
}
<|endoftext|>


<commit_before>/* 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;

use gleam::gl;
use std::env;
use std::path::PathBuf;
use webrender_traits::{ClipId, ClipRegion, ColorF, Epoch};
use webrender_traits::{DeviceUintSize, LayoutPoint, LayoutRect, LayoutSize};
use webrender_traits::{PipelineId, RenderApi, TransformStyle};

struct ScrollState {
    root_clip_id: ClipId,
    root_scroller_pos: LayoutPoint,
    nested_clip_id: ClipId,
    nested_scroller_pos: LayoutPoint,
}

impl ScrollState {
    pub fn new(root: ClipId, nested: ClipId) -> ScrollState {
        ScrollState {
            root_clip_id: root,
            root_scroller_pos: LayoutPoint::zero(),
            nested_clip_id: nested,
            nested_scroller_pos: LayoutPoint::zero(),
        }
    }

    pub fn scroll(&mut self, root: bool, delta: (i32, i32), api: &RenderApi) {
        if root {
            self.root_scroller_pos.x += delta.0 as f32;
            self.root_scroller_pos.y += delta.1 as f32;
            api.scroll_node_with_id(self.root_scroller_pos, self.root_clip_id);
        } else {
            self.nested_scroller_pos.x += delta.0 as f32;
            self.nested_scroller_pos.y += delta.1 as f32;
            api.scroll_node_with_id(self.nested_scroller_pos, self.nested_clip_id);
        }
    }
}

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();
    }
}

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 mut builder = webrender_traits::DisplayListBuilder::new(pipeline_id);

    let bounds = LayoutRect::new(LayoutPoint::zero(), LayoutSize::new(width as f32, height as f32));
    builder.push_stacking_context(webrender_traits::ScrollPolicy::Scrollable,
                                  bounds,
                                  0,
                                  None,
                                  TransformStyle::Flat,
                                  None,
                                  webrender_traits::MixBlendMode::Normal,
                                  Vec::new());

    if true {   // scrolling and clips stuff
        // let's make a scrollbox
        let scrollbox = (0, 0).to(300, 400);
        builder.push_stacking_context(webrender_traits::ScrollPolicy::Scrollable,
                                      LayoutRect::new(LayoutPoint::new(10.0, 10.0),
                                                      LayoutSize::zero()),
                                      0,
                                      None,
                                      TransformStyle::Flat,
                                      None,
                                      webrender_traits::MixBlendMode::Normal,
                                      Vec::new());
        // set the scrolling clip
        let clip_id = builder.define_clip((0, 0).to(1000, 1000),
                                          ClipRegion::simple(&scrollbox),
                                          Some(ClipId::new(42, pipeline_id)));
        builder.push_clip_id(clip_id);
        // now put some content into it.
        // start with a white background
        builder.push_rect((0, 0).to(500, 500),
                          ClipRegion::simple(&(0, 0).to(1000, 1000)),
                          ColorF::new(1.0, 1.0, 1.0, 1.0));
        // let's make a 50x50 blue square as a visual reference
        builder.push_rect((0, 0).to(50, 50),
                          ClipRegion::simple(&(0, 0).to(50, 50)),
                          ColorF::new(0.0, 0.0, 1.0, 1.0));
        // and a 50x50 green square next to it with an offset clip
        // to see what that looks like
        builder.push_rect((50, 0).to(100, 50),
                          ClipRegion::simple(&(60, 10).to(110, 60)),
                          ColorF::new(0.0, 1.0, 0.0, 1.0));

        // Below the above rectangles, set up a nested scrollbox. It's still in
        // the same stacking context, so note that the rects passed in need to
        // be relative to the stacking context.
        let nested_clip_id = builder.define_clip((0, 100).to(300, 400),
                                                 ClipRegion::simple(&(0, 100).to(200, 300)),
                                                 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
        builder.push_rect((-1000, -1000).to(5000, 5000),
                          ClipRegion::simple(&(-1000, -1000).to(5000, 5000)),
                          ColorF::new(0.5, 0.5, 0.5, 1.0));
        // add a teal square to visualize the scrolling/clipping behaviour
        // as you scroll the nested scrollbox with WASD keys
        builder.push_rect((0, 100).to(50, 150),
                          ClipRegion::simple(&(0, 100).to(50, 150)),
                          ColorF::new(0.0, 1.0, 1.0, 1.0));
        // just for good measure add another teal square in the bottom-right
        // corner of the nested scrollframe content, which can be scrolled into
        // view by the user
        builder.push_rect((250, 350).to(300, 400),
                          ClipRegion::simple(&(250, 350).to(300, 400)),
                          ColorF::new(0.0, 1.0, 1.0, 1.0));
        builder.pop_clip_id(); // nested_clip_id

        builder.pop_clip_id(); // clip_id
        builder.pop_stacking_context();
    }

    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);

    let mut scroll_state = ScrollState::new(ClipId::new(42, pipeline_id),
                                            ClipId::new(43, pipeline_id));

    '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,
                // Use up/down/left/right for scrolling the outer scrollbox
                glutin::Event::KeyboardInput(glutin::ElementState::Pressed,
                                             _, Some(glutin::VirtualKeyCode::Down)) => {
                    scroll_state.scroll(true, (0, 10), &api);
                }
                glutin::Event::KeyboardInput(glutin::ElementState::Pressed,
                                             _, Some(glutin::VirtualKeyCode::Up)) => {
                    scroll_state.scroll(true, (0, -10), &api);
                }
                glutin::Event::KeyboardInput(glutin::ElementState::Pressed,
                                             _, Some(glutin::VirtualKeyCode::Left)) => {
                    scroll_state.scroll(true, (-10, 0), &api);
                }
                glutin::Event::KeyboardInput(glutin::ElementState::Pressed,
                                             _, Some(glutin::VirtualKeyCode::Right)) => {
                    scroll_state.scroll(true, (10, 0), &api);
                }
                // Use WASD for scrolling the nested scrollbox
                glutin::Event::KeyboardInput(glutin::ElementState::Pressed,
                                             _, Some(glutin::VirtualKeyCode::S)) => {
                    scroll_state.scroll(false, (0, 10), &api);
                }
                glutin::Event::KeyboardInput(glutin::ElementState::Pressed,
                                             _, Some(glutin::VirtualKeyCode::W)) => {
                    scroll_state.scroll(false, (0, -10), &api);
                }
                glutin::Event::KeyboardInput(glutin::ElementState::Pressed,
                                             _, Some(glutin::VirtualKeyCode::A)) => {
                    scroll_state.scroll(false, (-10, 0), &api);
                }
                glutin::Event::KeyboardInput(glutin::ElementState::Pressed,
                                             _, Some(glutin::VirtualKeyCode::D)) => {
                    scroll_state.scroll(false, (10, 0), &api);
                }
                _ => ()
            }
        }

        renderer.update();
        renderer.render(DeviceUintSize::new(width, height));
        window.swap_buffers().ok();
    }
}
<commit_msg>Add mousewheel support to the scrolling example<commit_after>/* 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;

use gleam::gl;
use std::env;
use std::path::PathBuf;
use webrender_traits::{ClipId, ClipRegion, ColorF, DeviceUintSize, Epoch, LayoutPoint, LayoutRect};
use webrender_traits::{LayoutSize, PipelineId, ScrollEventPhase, ScrollLocation, TransformStyle};
use webrender_traits::WorldPoint;

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();
    }
}

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 mut builder = webrender_traits::DisplayListBuilder::new(pipeline_id);

    let bounds = LayoutRect::new(LayoutPoint::zero(), LayoutSize::new(width as f32, height as f32));
    builder.push_stacking_context(webrender_traits::ScrollPolicy::Scrollable,
                                  bounds,
                                  0,
                                  None,
                                  TransformStyle::Flat,
                                  None,
                                  webrender_traits::MixBlendMode::Normal,
                                  Vec::new());

    if true {   // scrolling and clips stuff
        // let's make a scrollbox
        let scrollbox = (0, 0).to(300, 400);
        builder.push_stacking_context(webrender_traits::ScrollPolicy::Scrollable,
                                      LayoutRect::new(LayoutPoint::new(10.0, 10.0),
                                                      LayoutSize::zero()),
                                      0,
                                      None,
                                      TransformStyle::Flat,
                                      None,
                                      webrender_traits::MixBlendMode::Normal,
                                      Vec::new());
        // set the scrolling clip
        let clip_id = builder.define_clip((0, 0).to(1000, 1000),
                                          ClipRegion::simple(&scrollbox),
                                          Some(ClipId::new(42, pipeline_id)));
        builder.push_clip_id(clip_id);
        // now put some content into it.
        // start with a white background
        builder.push_rect((0, 0).to(500, 500),
                          ClipRegion::simple(&(0, 0).to(1000, 1000)),
                          ColorF::new(1.0, 1.0, 1.0, 1.0));
        // let's make a 50x50 blue square as a visual reference
        builder.push_rect((0, 0).to(50, 50),
                          ClipRegion::simple(&(0, 0).to(50, 50)),
                          ColorF::new(0.0, 0.0, 1.0, 1.0));
        // and a 50x50 green square next to it with an offset clip
        // to see what that looks like
        builder.push_rect((50, 0).to(100, 50),
                          ClipRegion::simple(&(60, 10).to(110, 60)),
                          ColorF::new(0.0, 1.0, 0.0, 1.0));

        // Below the above rectangles, set up a nested scrollbox. It's still in
        // the same stacking context, so note that the rects passed in need to
        // be relative to the stacking context.
        let nested_clip_id = builder.define_clip((0, 100).to(300, 400),
                                                 ClipRegion::simple(&(0, 100).to(200, 300)),
                                                 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
        builder.push_rect((-1000, -1000).to(5000, 5000),
                          ClipRegion::simple(&(-1000, -1000).to(5000, 5000)),
                          ColorF::new(0.5, 0.5, 0.5, 1.0));
        // add a teal square to visualize the scrolling/clipping behaviour
        // as you scroll the nested scrollbox with WASD keys
        builder.push_rect((0, 100).to(50, 150),
                          ClipRegion::simple(&(0, 100).to(50, 150)),
                          ColorF::new(0.0, 1.0, 1.0, 1.0));
        // just for good measure add another teal square in the bottom-right
        // corner of the nested scrollframe content, which can be scrolled into
        // view by the user
        builder.push_rect((250, 350).to(300, 400),
                          ClipRegion::simple(&(250, 350).to(300, 400)),
                          ColorF::new(0.0, 1.0, 1.0, 1.0));
        builder.pop_clip_id(); // nested_clip_id

        builder.pop_clip_id(); // clip_id
        builder.pop_stacking_context();
    }

    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);

    let mut cursor_position = WorldPoint::zero();

    '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(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);
                }
                _ => ()
            }
        }

        renderer.update();
        renderer.render(DeviceUintSize::new(width, height));
        window.swap_buffers().ok();
    }
}
<|endoftext|>


<commit_before>//
// zhtta.rs
//
// Running on Rust 0.8
//
// Code for PS3
//
// Note: it would be very unwise to run this server on a machine that is
// on the Internet and contains any sensitive files!
//
// University of Virginia - cs4414 Fall 2013
// Daniel Nizri, Renee Seaman, and Alex Fabian
// Version 0.4

extern mod extra;

use std::rt::io::*;
use std::rt::io::net::ip::SocketAddr;
use std::io::println;
use std::cell::Cell;
use std::{os, str, io, run, libc, hashmap};
use extra::arc;
use std::comm::*;

static PORT:    int = 4414;
static IP: &'static str = "127.0.0.1";

struct sched_msg {
    stream: Option<std::rt::io::net::tcp::TcpStream>,
    filepath: ~std::path::PosixPath,
    file_size: uint
}

fn main() {
    let req_vec: ~[sched_msg] = ~[];
    let shared_req_vec = arc::RWArc::new(req_vec);
    let add_vec = shared_req_vec.clone();
    let take_vec = shared_req_vec.clone();
    let visitor_count : uint = 0;
    let shared_visitor_count = arc::RWArc::new(visitor_count);

    let (port, chan) = stream();
    let chan = SharedChan::new(chan);

    // FIFO - dequeue file requests, and send responses.
    do spawn {
        let (sm_port, sm_chan) = stream();

        // a task for sending responses.
        do spawn {
            let mut cache_map: hashmap::HashMap<~str, ~str> = hashmap::HashMap::new();

            loop {
                let mut tf: sched_msg = sm_port.recv(); // wait for the dequeued request to handle

                let file_contents = cache_map.find_or_insert_with(tf.filepath.to_str(), |path| {
                    println(fmt!("reading file: %s", tf.filepath.to_str()));
                    match io::read_whole_file_str(&PosixPath(*path)) {
                        Ok(file_contents) => {
                            if path.slice(path.len() - 4, path.len()) != "html" {
                                file_contents.replace("\n", "
")
                            }
                            else {
                                file_contents
                            }
                        }
                        Err(err)          => err
                    }
                }).to_str();

                println(fmt!("begin serving file [%?]", tf.filepath));
                // A web server should always reply a HTTP header for any legal HTTP request.
                tf.stream.write("HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n".as_bytes());

                let mut file_data_vec = ~[file_contents.clone()];

                while(file_data_vec[0].contains("");
                            match end_pos_ssi {
                                Some(end_ssi) => {
                                    let start_pos_cmd = start_ssi + 15;
                                    let end_pos_cmd = end_ssi;
                                    let cmd = file_data_clone.slice(start_pos_cmd, end_pos_cmd);
                                    let output = get_gash_output(cmd.to_owned());
                                    file_data_vec[0] = file_data_clone.slice(0, start_ssi).clone().to_owned().append(output).append(file_data_clone.slice(end_ssi + 5, file_data_clone.len()));
                                }
                                None      => { println("Not found") }
                            }
                        }
                        None      => { }
                    }
                }

                tf.stream.write(file_data_vec[0].as_bytes());
                println(fmt!("finish file [%?]", tf.filepath));
            }
        }

        loop {
            port.recv(); // wait for arrving notification
            do take_vec.write |vec| {
                if ((*vec).len() > 0) {
                    // LIFO didn't make sense in service scheduling, so we modify it as FIFO by using shift_opt() rather than pop().
                    let tf_opt: Option<sched_msg> = (*vec).shift_opt();
                    let tf = tf_opt.unwrap();
                    println(fmt!("shift from queue, size: %ud", (*vec).len()));
                    sm_chan.send(tf); // send the request to send-response-task to serve.
                }
            }
        }
    }

    let ip = match FromStr::from_str(IP) { Some(ip) => ip,
                                           None => { println(fmt!("Error: Invalid IP address <%s>", IP));
                                                     return;},
                                         };

    let socket = net::tcp::TcpListener::bind(SocketAddr {ip: ip, port: PORT as u16});

    println(fmt!("Listening on %s:%d ...", ip.to_str(), PORT));
    let mut acceptor = socket.listen().unwrap();

    for stream in acceptor.incoming() {
        let stream = Cell::new(stream);

        // Start a new task to handle the each connection
        let child_chan = chan.clone();
        let child_add_vec = add_vec.clone();
        let (port2, chan2) = std::comm::stream();
        chan2.send(shared_visitor_count.clone());
        do spawn {
            let visitor_count = port2.recv();
            visitor_count.write(|count| {
                *count += 1;
            });

            let mut stream = stream.take();
            let mut buf = [0, ..500];
            stream.read(buf);
            let request_str = str::from_utf8(buf);

            let req_group : ~[&str]= request_str.splitn_iter(' ', 3).collect();
            if req_group.len() > 2 {
                let path = req_group[1];
                println(fmt!("Request for path: \n%?", path));

                let file_path = ~os::getcwd().push(path.replace("/../", ""));
                if !os::path_exists(file_path) || os::path_is_dir(file_path) {
                    visitor_count.read(|val| {
                        println(fmt!("Request received:\n%s", request_str));
                        let response: ~str = fmt!(
                            "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n
                             <doctype !html><title>Hello, Rust!</title>

Greetings, Krusty!

Visitor count: %u

                             \r\n", *val);

                        stream.write(response.as_bytes());
                    });
                }
                else {
                    // Requests scheduling
                    let mut file_size = 0;
                    let reader : Result<@io::Reader, ~str> = io::file_reader(file_path);
                    match reader {
                        Ok(reader) => {
                            reader.seek(0, io::SeekEnd);
                            file_size = reader.tell();
                        },
                        Err(msg) => {
                            println(msg);
                        },
                    }

                    let msg: sched_msg = sched_msg{stream: stream, filepath: file_path.clone(), file_size: file_size};
                    let (sm_port, sm_chan) = std::comm::stream();
                    sm_chan.send(msg);

                    let ip_str = ip.to_str().clone();
                    let mut is_ip_preferred = false;

                    if ip_str.slice(0, 8) == "128.143." || ip_str.slice(0, 7) == "137.54." || ip_str.slice(0, 8) == "192.168." {
                        is_ip_preferred = true;
                    }

                    do child_add_vec.write |vec| {
                        let msg = sm_port.recv();
                        if is_ip_preferred {
                            (*vec).insert(0, msg); // enqueue new preferred request.
                        }
                        else {
                            let mut insert_pos = 0;
                            for queued_msg in vec.iter() {
                                if msg.file_size >= queued_msg.file_size {
                                    insert_pos += 1;
                                }
                                else {
                                    break;
                                }
                            }
                            (*vec).insert(insert_pos, msg); // enqueue new request.
                        }
                        println("add to queue");
                    }
                    child_chan.send(""); //notify the new arriving request.
                    println(fmt!("get file request: %?", file_path));
                }
            }
            println!("connection terminates")
        }
    }
}

/********************** MODIFIED GASH CODE **********************/
fn get_gash_output(mut cmd_line : ~str) -> ~str {
    cmd_line = cmd_line.trim().to_owned();
    return handle_cmdline(cmd_line);
}

fn get_fd(fpath: &str, mode: &str) -> libc::c_int {
    #[fixed_stack_segment]; #[inline(never)];

    unsafe {
        let fpathbuf = fpath.to_c_str().unwrap();
        let modebuf = mode.to_c_str().unwrap();
        return libc::fileno(libc::fopen(fpathbuf, modebuf));
    }
}

fn handle_cmd(cmd_line: &str, pipe_in: libc::c_int, pipe_out: libc::c_int, pipe_err: libc::c_int) -> ~str {
    let mut out_fd = pipe_out;
    let mut in_fd = pipe_in;
    let err_fd = pipe_err;

    let mut argv: ~[~str] =
        cmd_line.split_iter(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();
    let mut i = 0;
    while (i < argv.len()) {
        if (argv[i] == ~">") {
            argv.remove(i);
            out_fd = get_fd(argv.remove(i), "w");
        } else if (argv[i] == ~"<") {
            argv.remove(i);
            in_fd = get_fd(argv.remove(i), "r");
        }
        i += 1;
    }

    let mut output = ~"";

    let mut out = Some(out_fd);
    let mut err = Some(err_fd);

    if pipe_out == -1 {
        out = None;
        err = None;
    }

    if argv.len() > 0 {
        let program = argv.remove(0);
        match program {
            ~"help"     => {output = ~"This is a new shell implemented in Rust!"}
            _           => {let mut prog = run::Process::new(program, argv, run::ProcessOptions {
                                                                                env: None,
                                                                                dir: None,
                                                                                in_fd: Some(in_fd),
                                                                                out_fd: out,
                                                                                err_fd: err
                                                                                });
                             if pipe_out == -1 {
                                 let prog_output = prog.finish_with_output();
                                 output = str::from_utf8(prog_output.output).replace("\n", "
");
                             }
                             else {
                                 prog.finish();
                             }

                             if in_fd != 0 {os::close(in_fd);}
                             if out_fd != 1 {os::close(out_fd);}
                             if err_fd != 2 {os::close(err_fd);}
                            }
        }
    }

    return output;
}

fn handle_cmdline(cmd_line:&str) -> ~str
{
    // handle pipes
    let progs: ~[~str] = cmd_line.split_iter('|').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

    let mut pipes: ~[os::Pipe] = ~[];

    // create pipes
    if (progs.len() > 1) {
        for _ in range(0, progs.len()-1) {
            pipes.push(os::pipe());
        }
    }

    let mut output = ~"";

    if progs.len() == 1 {
        output = handle_cmd(progs[0], 0, -1, 2);
    } else {
        for i in range(0, progs.len()) {
            let prog = progs[i].to_owned();
            if i == 0 {
                let pipe_i = pipes[i];
                handle_cmd(prog, 0, pipe_i.out, 2);
            } else if i < progs.len() - 1 {
                let pipe_i = pipes[i];
                let pipe_i_1 = pipes[i-1];
                handle_cmd(prog, pipe_i_1.input, pipe_i.out, 2);
            } else {
                let pipe_i_1 = pipes[i-1];
                output = handle_cmd(prog, pipe_i_1.input, -1, 2);
            }
        }
    }
    return output;
}
<commit_msg>Cache now works when files are modified<commit_after>//
// zhtta.rs
//
// Running on Rust 0.8
//
// Code for PS3
//
// Note: it would be very unwise to run this server on a machine that is
// on the Internet and contains any sensitive files!
//
// University of Virginia - cs4414 Fall 2013
// Daniel Nizri, Renee Seaman, and Alex Fabian
// Version 0.4

extern mod extra;

use std::rt::io::*;
use std::rt::io::net::ip::SocketAddr;
use std::io::println;
use std::cell::Cell;
use std::{os, str, io, run, libc, hashmap};
use extra::arc;
use std::comm::*;

static PORT:    int = 4414;
static IP: &'static str = "127.0.0.1";

struct sched_msg {
    stream: Option<std::rt::io::net::tcp::TcpStream>,
    filepath: ~std::path::PosixPath,
    file_size: uint
}

struct cached_file {
    content: ~str,
    modified: ~str
}

fn get_file_contents(map: &mut hashmap::HashMap<~str, cached_file>, filepath: ~std::path::PosixPath) -> ~str {
    if map.contains_key(&filepath.to_str()) {
        match map.find(&filepath.to_str()) {
            Some(cached_file) => {
                let last_modified = get_gash_output(fmt!("stat -c %s %s", "%y", filepath.to_str()));
                if last_modified != cached_file.modified {
                    println(fmt!("file in cache was modified, re-reading %s", filepath.to_str()));
                    match io::read_whole_file_str(filepath) {
                        Ok(file_contents) => {
                            let path = filepath.to_str();
                            if path.slice(path.len() - 4, path.len()) != "html" {
                                return file_contents.replace("\n", "
");
                            }
                            else {
                                return file_contents;
                            }
                        }
                        Err(err)          => { return err; }
                    }
                } else {
                    println(fmt!("retrieving cached file: %s", filepath.to_str()));
                    return cached_file.content.clone();
                }
            },
            None    => { return ~""; }
        }
    }
    else {
        println(fmt!("reading file: %s", filepath.to_str()));
        match io::read_whole_file_str(filepath) {
            Ok(file_contents) => {
                let path = filepath.to_str();
                if path.slice(path.len() - 4, path.len()) != "html" {
                    return file_contents.replace("\n", "
");
                }
                else {
                    return file_contents;
                }
            }
            Err(err)          => { return err; }
        }
    }
}

fn main() {
    let req_vec: ~[sched_msg] = ~[];
    let shared_req_vec = arc::RWArc::new(req_vec);
    let add_vec = shared_req_vec.clone();
    let take_vec = shared_req_vec.clone();
    let visitor_count : uint = 0;
    let shared_visitor_count = arc::RWArc::new(visitor_count);

    let (port, chan) = stream();
    let chan = SharedChan::new(chan);

    // FIFO - dequeue file requests, and send responses.
    do spawn {
        let (sm_port, sm_chan) = stream();

        // a task for sending responses.
        do spawn {
            let mut cache_map: hashmap::HashMap<~str, cached_file> = hashmap::HashMap::new();

            loop {
                let mut tf: sched_msg = sm_port.recv(); // wait for the dequeued request to handle
                let file_contents = get_file_contents(&mut cache_map, tf.filepath.clone());
                let last_modified = get_gash_output(fmt!("stat -c %s %s", "%y", tf.filepath.to_str()));
                let cached_file: cached_file = cached_file{content: file_contents.clone(), modified: last_modified};
                cache_map.insert(tf.filepath.to_str(), cached_file);

                println(fmt!("begin serving file [%?]", tf.filepath));
                // A web server should always reply a HTTP header for any legal HTTP request.
                tf.stream.write("HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n".as_bytes());

                let mut file_data_vec = ~[file_contents.clone()];

                while(file_data_vec[0].contains("");
                            match end_pos_ssi {
                                Some(end_ssi) => {
                                    let start_pos_cmd = start_ssi + 15;
                                    let end_pos_cmd = end_ssi;
                                    let cmd = file_data_clone.slice(start_pos_cmd, end_pos_cmd);
                                    let output = get_gash_output(cmd.to_owned());
                                    file_data_vec[0] = file_data_clone.slice(0, start_ssi).clone().to_owned().append(output).append(file_data_clone.slice(end_ssi + 5, file_data_clone.len()));
                                }
                                None      => { println("Error --- Found ''") }
                            }
                        }
                        None      => { println("Error --- Expected to find '


<commit_before>use std::cell::{Cell, RefCell};

use cairo::{self, ImageSurface};
use rulinalg::matrix::{BaseMatrix, Matrix};

use attributes::Attribute;
use drawing_ctx::DrawingCtx;
use error::NodeError;
use handle::RsvgHandle;
use node::{NodeResult, NodeTrait, RsvgCNodeImpl, RsvgNode};
use parsers::{self, ListLength, NumberListError, ParseError};
use property_bag::PropertyBag;
use surface_utils::{
    iterators::{PixelRectangle, Pixels},
    shared_surface::SharedImageSurface,
    EdgeMode,
    ImageSurfaceDataExt,
    Pixel,
};
use util::clamp;

use super::context::{FilterContext, FilterOutput, FilterResult, IRect};
use super::{Filter, FilterError, PrimitiveWithInput};

/// The `feConvolveMatrix` filter primitive.
pub struct ConvolveMatrix {
    base: PrimitiveWithInput,
    order: Cell<(u32, u32)>,
    kernel_matrix: RefCell<Option<Matrix<f64>>>,
    divisor: Cell<Option<f64>>,
    bias: Cell<f64>,
    target_x: Cell<Option<u32>>,
    target_y: Cell<Option<u32>>,
    edge_mode: Cell<EdgeMode>,
    kernel_unit_length: Cell<Option<(f64, f64)>>,
    preserve_alpha: Cell<bool>,
}

impl ConvolveMatrix {
    /// Constructs a new `ConvolveMatrix` with empty properties.
    #[inline]
    pub fn new() -> ConvolveMatrix {
        ConvolveMatrix {
            base: PrimitiveWithInput::new::<Self>(),
            order: Cell::new((3, 3)),
            kernel_matrix: RefCell::new(None),
            divisor: Cell::new(None),
            bias: Cell::new(0.0),
            target_x: Cell::new(None),
            target_y: Cell::new(None),
            edge_mode: Cell::new(EdgeMode::Duplicate),
            kernel_unit_length: Cell::new(None),
            preserve_alpha: Cell::new(false),
        }
    }
}

impl NodeTrait for ConvolveMatrix {
    fn set_atts(
        &self,
        node: &RsvgNode,
        handle: *const RsvgHandle,
        pbag: &PropertyBag,
    ) -> NodeResult {
        self.base.set_atts(node, handle, pbag)?;

        for (_key, attr, value) in pbag.iter() {
            match attr {
                Attribute::Order => self.order.set(
                    parsers::integer_optional_integer(value)
                        .map_err(|err| NodeError::parse_error(attr, err))
                        .and_then(|(x, y)| {
                            if x > 0 && y > 0 {
                                Ok((x as u32, y as u32))
                            } else {
                                Err(NodeError::value_error(
                                    attr,
                                    "values must be greater than 0",
                                ))
                            }
                        })?,
                ),
                Attribute::Divisor => self.divisor.set(Some(
                    parsers::number(value)
                        .map_err(|err| NodeError::parse_error(attr, err))
                        .and_then(|x| {
                            if x != 0.0 {
                                Ok(x)
                            } else {
                                Err(NodeError::value_error(attr, "divisor cannot be equal to 0"))
                            }
                        })?,
                )),
                Attribute::Bias => self
                    .bias
                    .set(parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?),
                Attribute::EdgeMode => self.edge_mode.set(EdgeMode::parse(attr, value)?),
                Attribute::KernelUnitLength => self.kernel_unit_length.set(Some(
                    parsers::number_optional_number(value)
                        .map_err(|err| NodeError::parse_error(attr, err))
                        .and_then(|(x, y)| {
                            if x > 0.0 && y > 0.0 {
                                Ok((x, y))
                            } else {
                                Err(NodeError::value_error(
                                    attr,
                                    "kernelUnitLength can't be less or equal to zero",
                                ))
                            }
                        })?,
                )),
                Attribute::PreserveAlpha => self.preserve_alpha.set(match value {
                    "false" => false,
                    "true" => true,
                    _ => {
                        return Err(NodeError::parse_error(
                            attr,
                            ParseError::new("expected false or true"),
                        ))
                    }
                }),
                _ => (),
            }
        }

        // target_x and target_y depend on order.
        for (_key, attr, value) in pbag.iter() {
            match attr {
                Attribute::TargetX => self.target_x.set(Some(
                    parsers::integer(value)
                        .map_err(|err| NodeError::parse_error(attr, err))
                        .and_then(|x| {
                            if x >= 0 && x < self.order.get().0 as i32 {
                                Ok(x as u32)
                            } else {
                                Err(NodeError::value_error(
                                    attr,
                                    "targetX must be greater or equal to zero and less than orderX",
                                ))
                            }
                        })?,
                )),
                Attribute::TargetY => self.target_y.set(Some(
                    parsers::integer(value)
                        .map_err(|err| NodeError::parse_error(attr, err))
                        .and_then(|x| {
                            if x >= 0 && x < self.order.get().1 as i32 {
                                Ok(x as u32)
                            } else {
                                Err(NodeError::value_error(
                                    attr,
                                    "targetY must be greater or equal to zero and less than orderY",
                                ))
                            }
                        })?,
                )),
                _ => (),
            }
        }

        // Default values for target_x and target_y.
        if self.target_x.get().is_none() {
            self.target_x.set(Some(self.order.get().0 / 2));
        }
        if self.target_y.get().is_none() {
            self.target_y.set(Some(self.order.get().1 / 2));
        }

        // Finally, parse the kernel matrix.
        for (_, attr, value) in pbag
            .iter()
            .filter(|(_, attr, _)| *attr == Attribute::KernelMatrix)
        {
            self.kernel_matrix.replace(Some({
                let number_of_elements = self.order.get().0 as usize * self.order.get().1 as usize;

                Matrix::new(
                    self.order.get().1 as usize,
                    self.order.get().0 as usize,
                    parsers::number_list_from_str(value, ListLength::Exact(number_of_elements))
                        .map_err(|err| {
                            NodeError::parse_error(
                                attr,
                                match err {
                                    NumberListError::IncorrectNumberOfElements => {
                                        ParseError::new(format!(
                                            "incorrect number of elements: expected {}",
                                            number_of_elements
                                        ))
                                    }
                                    NumberListError::Parse(err) => err,
                                },
                            )
                        })?,
                )
            }));
        }

        // Default value for the divisor.
        if self.divisor.get().is_none() {
            self.divisor
                .set(Some(self.kernel_matrix.borrow().as_ref().unwrap().sum()));

            if self.divisor.get().unwrap() == 0.0 {
                self.divisor.set(Some(1.0));
            }
        }

        Ok(())
    }

    #[inline]
    fn get_c_impl(&self) -> *const RsvgCNodeImpl {
        self.base.get_c_impl()
    }
}

impl Filter for ConvolveMatrix {
    fn render(
        &self,
        _node: &RsvgNode,
        ctx: &FilterContext,
        draw_ctx: &mut DrawingCtx,
    ) -> Result<FilterResult, FilterError> {
        let input = self.base.get_input(ctx, draw_ctx)?;
        let mut bounds = self
            .base
            .get_bounds(ctx)
            .add_input(&input)
            .into_irect(draw_ctx);
        let original_bounds = bounds;

        let mut input_surface = if self.preserve_alpha.get() {
            // preserve_alpha means we need to premultiply and unpremultiply the values.
            //
            // HACK: this is storing unpremultiplied pixels in an ARGB32 image surface (which is
            // supposed to be premultiplied pixels).
            let mut unpremultiplied_surface = ImageSurface::create(
                cairo::Format::ARgb32,
                input.surface().width(),
                input.surface().height(),
            ).map_err(FilterError::IntermediateSurfaceCreation)?;

            let stride = unpremultiplied_surface.get_stride() as usize;
            {
                let mut data = unpremultiplied_surface.get_data().unwrap();

                for (x, y, pixel) in Pixels::new(input.surface(), bounds) {
                    let new_pixel = if pixel.a == 0 {
                        pixel
                    } else {
                        let alpha = f64::from(pixel.a) / 255.0;
                        let unpremultiply = |x| (f64::from(x) / alpha).round() as u8;

                        Pixel {
                            r: unpremultiply(pixel.r),
                            g: unpremultiply(pixel.g),
                            b: unpremultiply(pixel.b),
                            a: pixel.a,
                        }
                    };

                    data.set_pixel(stride, new_pixel, x, y);
                }
            }

            SharedImageSurface::new(unpremultiplied_surface)
                .map_err(FilterError::BadIntermediateSurfaceStatus)?
        } else {
            input.surface().clone()
        };

        let scale = self.kernel_unit_length.get().map(|(dx, dy)| {
            let paffine = ctx.paffine();
            let ox = paffine.xx * dx + paffine.xy * dy;
            let oy = paffine.yx * dx + paffine.yy * dy;

            (ox, oy)
        });

        if let Some((ox, oy)) = scale {
            // Scale the input surface to match kernel_unit_length.
            let (new_surface, new_bounds) = input_surface
                .scale(bounds, 1.0 / ox, 1.0 / oy)
                .map_err(FilterError::IntermediateSurfaceCreation)?;

            input_surface = new_surface;
            bounds = new_bounds;
        }

        let matrix = self.kernel_matrix.borrow();
        let matrix = matrix.as_ref().unwrap();

        let mut output_surface = ImageSurface::create(
            cairo::Format::ARgb32,
            input_surface.width(),
            input_surface.height(),
        ).map_err(FilterError::IntermediateSurfaceCreation)?;

        let output_stride = output_surface.get_stride() as usize;
        {
            let mut output_data = output_surface.get_data().unwrap();

            for (x, y, pixel) in Pixels::new(&input_surface, bounds) {
                // Compute the convolution rectangle bounds.
                let kernel_bounds = IRect {
                    x0: x as i32 - self.target_x.get().unwrap() as i32,
                    y0: y as i32 - self.target_y.get().unwrap() as i32,
                    x1: x as i32 - self.target_x.get().unwrap() as i32 + self.order.get().0 as i32,
                    y1: y as i32 - self.target_y.get().unwrap() as i32 + self.order.get().1 as i32,
                };

                // Do the convolution.
                let mut r = 0.0;
                let mut g = 0.0;
                let mut b = 0.0;
                let mut a = 0.0;

                for (x, y, pixel) in
                    PixelRectangle::new(&input_surface, bounds, kernel_bounds, self.edge_mode.get())
                {
                    let kernel_x = (kernel_bounds.x1 - x - 1) as usize;
                    let kernel_y = (kernel_bounds.y1 - y - 1) as usize;

                    r += f64::from(pixel.r) / 255.0 * matrix[[kernel_y, kernel_x]];
                    g += f64::from(pixel.g) / 255.0 * matrix[[kernel_y, kernel_x]];
                    b += f64::from(pixel.b) / 255.0 * matrix[[kernel_y, kernel_x]];

                    if !self.preserve_alpha.get() {
                        a += f64::from(pixel.a) / 255.0 * matrix[[kernel_y, kernel_x]];
                    }
                }

                // If preserve_alpha is true, set a to the source alpha value.
                if self.preserve_alpha.get() {
                    a = f64::from(pixel.a) / 255.0;
                } else {
                    a = a / self.divisor.get().unwrap() + self.bias.get();
                }

                let clamped_a = clamp(a, 0.0, 1.0);

                let compute = |x| {
                    let x = x / self.divisor.get().unwrap() + self.bias.get() * a;

                    let x = if self.preserve_alpha.get() {
                        // Premultiply the output value.
                        clamp(x, 0.0, 1.0) * clamped_a
                    } else {
                        clamp(x, 0.0, clamped_a)
                    };

                    (x * 255.0).round() as u8
                };

                let output_pixel = Pixel {
                    r: compute(r),
                    g: compute(g),
                    b: compute(b),
                    a: (clamped_a * 255.0).round() as u8,
                };

                output_data.set_pixel(output_stride, output_pixel, x, y);
            }
        }

        let mut output_surface = SharedImageSurface::new(output_surface)
            .map_err(FilterError::BadIntermediateSurfaceStatus)?;

        if let Some((ox, oy)) = scale {
            // Scale the output surface back.
            output_surface = output_surface
                .scale_to(
                    ctx.source_graphic().width(),
                    ctx.source_graphic().height(),
                    original_bounds,
                    ox,
                    oy,
                )
                .map_err(FilterError::IntermediateSurfaceCreation)?;
        }

        Ok(FilterResult {
            name: self.base.result.borrow().clone(),
            output: FilterOutput {
                surface: output_surface,
                bounds,
            },
        })
    }

    #[inline]
    fn is_affected_by_color_interpolation_filters() -> bool {
        true
    }
}

impl EdgeMode {
    fn parse(attr: Attribute, s: &str) -> Result<Self, NodeError> {
        match s {
            "duplicate" => Ok(EdgeMode::Duplicate),
            "wrap" => Ok(EdgeMode::Wrap),
            "none" => Ok(EdgeMode::None),
            _ => Err(NodeError::parse_error(
                attr,
                ParseError::new("invalid value"),
            )),
        }
    }
}
<commit_msg>Make convolve_matrix use surface.unpremultiply()<commit_after>use std::cell::{Cell, RefCell};

use cairo::{self, ImageSurface};
use rulinalg::matrix::{BaseMatrix, Matrix};

use attributes::Attribute;
use drawing_ctx::DrawingCtx;
use error::NodeError;
use handle::RsvgHandle;
use node::{NodeResult, NodeTrait, RsvgCNodeImpl, RsvgNode};
use parsers::{self, ListLength, NumberListError, ParseError};
use property_bag::PropertyBag;
use surface_utils::{
    iterators::{PixelRectangle, Pixels},
    shared_surface::SharedImageSurface,
    EdgeMode,
    ImageSurfaceDataExt,
    Pixel,
};
use util::clamp;

use super::context::{FilterContext, FilterOutput, FilterResult, IRect};
use super::{Filter, FilterError, PrimitiveWithInput};

/// The `feConvolveMatrix` filter primitive.
pub struct ConvolveMatrix {
    base: PrimitiveWithInput,
    order: Cell<(u32, u32)>,
    kernel_matrix: RefCell<Option<Matrix<f64>>>,
    divisor: Cell<Option<f64>>,
    bias: Cell<f64>,
    target_x: Cell<Option<u32>>,
    target_y: Cell<Option<u32>>,
    edge_mode: Cell<EdgeMode>,
    kernel_unit_length: Cell<Option<(f64, f64)>>,
    preserve_alpha: Cell<bool>,
}

impl ConvolveMatrix {
    /// Constructs a new `ConvolveMatrix` with empty properties.
    #[inline]
    pub fn new() -> ConvolveMatrix {
        ConvolveMatrix {
            base: PrimitiveWithInput::new::<Self>(),
            order: Cell::new((3, 3)),
            kernel_matrix: RefCell::new(None),
            divisor: Cell::new(None),
            bias: Cell::new(0.0),
            target_x: Cell::new(None),
            target_y: Cell::new(None),
            edge_mode: Cell::new(EdgeMode::Duplicate),
            kernel_unit_length: Cell::new(None),
            preserve_alpha: Cell::new(false),
        }
    }
}

impl NodeTrait for ConvolveMatrix {
    fn set_atts(
        &self,
        node: &RsvgNode,
        handle: *const RsvgHandle,
        pbag: &PropertyBag,
    ) -> NodeResult {
        self.base.set_atts(node, handle, pbag)?;

        for (_key, attr, value) in pbag.iter() {
            match attr {
                Attribute::Order => self.order.set(
                    parsers::integer_optional_integer(value)
                        .map_err(|err| NodeError::parse_error(attr, err))
                        .and_then(|(x, y)| {
                            if x > 0 && y > 0 {
                                Ok((x as u32, y as u32))
                            } else {
                                Err(NodeError::value_error(
                                    attr,
                                    "values must be greater than 0",
                                ))
                            }
                        })?,
                ),
                Attribute::Divisor => self.divisor.set(Some(
                    parsers::number(value)
                        .map_err(|err| NodeError::parse_error(attr, err))
                        .and_then(|x| {
                            if x != 0.0 {
                                Ok(x)
                            } else {
                                Err(NodeError::value_error(attr, "divisor cannot be equal to 0"))
                            }
                        })?,
                )),
                Attribute::Bias => self
                    .bias
                    .set(parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?),
                Attribute::EdgeMode => self.edge_mode.set(EdgeMode::parse(attr, value)?),
                Attribute::KernelUnitLength => self.kernel_unit_length.set(Some(
                    parsers::number_optional_number(value)
                        .map_err(|err| NodeError::parse_error(attr, err))
                        .and_then(|(x, y)| {
                            if x > 0.0 && y > 0.0 {
                                Ok((x, y))
                            } else {
                                Err(NodeError::value_error(
                                    attr,
                                    "kernelUnitLength can't be less or equal to zero",
                                ))
                            }
                        })?,
                )),
                Attribute::PreserveAlpha => self.preserve_alpha.set(match value {
                    "false" => false,
                    "true" => true,
                    _ => {
                        return Err(NodeError::parse_error(
                            attr,
                            ParseError::new("expected false or true"),
                        ))
                    }
                }),
                _ => (),
            }
        }

        // target_x and target_y depend on order.
        for (_key, attr, value) in pbag.iter() {
            match attr {
                Attribute::TargetX => self.target_x.set(Some(
                    parsers::integer(value)
                        .map_err(|err| NodeError::parse_error(attr, err))
                        .and_then(|x| {
                            if x >= 0 && x < self.order.get().0 as i32 {
                                Ok(x as u32)
                            } else {
                                Err(NodeError::value_error(
                                    attr,
                                    "targetX must be greater or equal to zero and less than orderX",
                                ))
                            }
                        })?,
                )),
                Attribute::TargetY => self.target_y.set(Some(
                    parsers::integer(value)
                        .map_err(|err| NodeError::parse_error(attr, err))
                        .and_then(|x| {
                            if x >= 0 && x < self.order.get().1 as i32 {
                                Ok(x as u32)
                            } else {
                                Err(NodeError::value_error(
                                    attr,
                                    "targetY must be greater or equal to zero and less than orderY",
                                ))
                            }
                        })?,
                )),
                _ => (),
            }
        }

        // Default values for target_x and target_y.
        if self.target_x.get().is_none() {
            self.target_x.set(Some(self.order.get().0 / 2));
        }
        if self.target_y.get().is_none() {
            self.target_y.set(Some(self.order.get().1 / 2));
        }

        // Finally, parse the kernel matrix.
        for (_, attr, value) in pbag
            .iter()
            .filter(|(_, attr, _)| *attr == Attribute::KernelMatrix)
        {
            self.kernel_matrix.replace(Some({
                let number_of_elements = self.order.get().0 as usize * self.order.get().1 as usize;

                Matrix::new(
                    self.order.get().1 as usize,
                    self.order.get().0 as usize,
                    parsers::number_list_from_str(value, ListLength::Exact(number_of_elements))
                        .map_err(|err| {
                            NodeError::parse_error(
                                attr,
                                match err {
                                    NumberListError::IncorrectNumberOfElements => {
                                        ParseError::new(format!(
                                            "incorrect number of elements: expected {}",
                                            number_of_elements
                                        ))
                                    }
                                    NumberListError::Parse(err) => err,
                                },
                            )
                        })?,
                )
            }));
        }

        // Default value for the divisor.
        if self.divisor.get().is_none() {
            self.divisor
                .set(Some(self.kernel_matrix.borrow().as_ref().unwrap().sum()));

            if self.divisor.get().unwrap() == 0.0 {
                self.divisor.set(Some(1.0));
            }
        }

        Ok(())
    }

    #[inline]
    fn get_c_impl(&self) -> *const RsvgCNodeImpl {
        self.base.get_c_impl()
    }
}

impl Filter for ConvolveMatrix {
    fn render(
        &self,
        _node: &RsvgNode,
        ctx: &FilterContext,
        draw_ctx: &mut DrawingCtx,
    ) -> Result<FilterResult, FilterError> {
        let input = self.base.get_input(ctx, draw_ctx)?;
        let mut bounds = self
            .base
            .get_bounds(ctx)
            .add_input(&input)
            .into_irect(draw_ctx);
        let original_bounds = bounds;

        let mut input_surface = if self.preserve_alpha.get() {
            // preserve_alpha means we need to premultiply and unpremultiply the values.
            let unpremultiplied_surface = input
                .surface()
                .unpremultiply(bounds)
                .map_err(FilterError::IntermediateSurfaceCreation)?;
            SharedImageSurface::new(unpremultiplied_surface)
                .map_err(FilterError::BadIntermediateSurfaceStatus)?
        } else {
            input.surface().clone()
        };

        let scale = self.kernel_unit_length.get().map(|(dx, dy)| {
            let paffine = ctx.paffine();
            let ox = paffine.xx * dx + paffine.xy * dy;
            let oy = paffine.yx * dx + paffine.yy * dy;

            (ox, oy)
        });

        if let Some((ox, oy)) = scale {
            // Scale the input surface to match kernel_unit_length.
            let (new_surface, new_bounds) = input_surface
                .scale(bounds, 1.0 / ox, 1.0 / oy)
                .map_err(FilterError::IntermediateSurfaceCreation)?;

            input_surface = new_surface;
            bounds = new_bounds;
        }

        let matrix = self.kernel_matrix.borrow();
        let matrix = matrix.as_ref().unwrap();

        let mut output_surface = ImageSurface::create(
            cairo::Format::ARgb32,
            input_surface.width(),
            input_surface.height(),
        ).map_err(FilterError::IntermediateSurfaceCreation)?;

        let output_stride = output_surface.get_stride() as usize;
        {
            let mut output_data = output_surface.get_data().unwrap();

            for (x, y, pixel) in Pixels::new(&input_surface, bounds) {
                // Compute the convolution rectangle bounds.
                let kernel_bounds = IRect {
                    x0: x as i32 - self.target_x.get().unwrap() as i32,
                    y0: y as i32 - self.target_y.get().unwrap() as i32,
                    x1: x as i32 - self.target_x.get().unwrap() as i32 + self.order.get().0 as i32,
                    y1: y as i32 - self.target_y.get().unwrap() as i32 + self.order.get().1 as i32,
                };

                // Do the convolution.
                let mut r = 0.0;
                let mut g = 0.0;
                let mut b = 0.0;
                let mut a = 0.0;

                for (x, y, pixel) in
                    PixelRectangle::new(&input_surface, bounds, kernel_bounds, self.edge_mode.get())
                {
                    let kernel_x = (kernel_bounds.x1 - x - 1) as usize;
                    let kernel_y = (kernel_bounds.y1 - y - 1) as usize;

                    r += f64::from(pixel.r) / 255.0 * matrix[[kernel_y, kernel_x]];
                    g += f64::from(pixel.g) / 255.0 * matrix[[kernel_y, kernel_x]];
                    b += f64::from(pixel.b) / 255.0 * matrix[[kernel_y, kernel_x]];

                    if !self.preserve_alpha.get() {
                        a += f64::from(pixel.a) / 255.0 * matrix[[kernel_y, kernel_x]];
                    }
                }

                // If preserve_alpha is true, set a to the source alpha value.
                if self.preserve_alpha.get() {
                    a = f64::from(pixel.a) / 255.0;
                } else {
                    a = a / self.divisor.get().unwrap() + self.bias.get();
                }

                let clamped_a = clamp(a, 0.0, 1.0);

                let compute = |x| {
                    let x = x / self.divisor.get().unwrap() + self.bias.get() * a;

                    let x = if self.preserve_alpha.get() {
                        // Premultiply the output value.
                        clamp(x, 0.0, 1.0) * clamped_a
                    } else {
                        clamp(x, 0.0, clamped_a)
                    };

                    (x * 255.0).round() as u8
                };

                let output_pixel = Pixel {
                    r: compute(r),
                    g: compute(g),
                    b: compute(b),
                    a: (clamped_a * 255.0).round() as u8,
                };

                output_data.set_pixel(output_stride, output_pixel, x, y);
            }
        }

        let mut output_surface = SharedImageSurface::new(output_surface)
            .map_err(FilterError::BadIntermediateSurfaceStatus)?;

        if let Some((ox, oy)) = scale {
            // Scale the output surface back.
            output_surface = output_surface
                .scale_to(
                    ctx.source_graphic().width(),
                    ctx.source_graphic().height(),
                    original_bounds,
                    ox,
                    oy,
                )
                .map_err(FilterError::IntermediateSurfaceCreation)?;
        }

        Ok(FilterResult {
            name: self.base.result.borrow().clone(),
            output: FilterOutput {
                surface: output_surface,
                bounds,
            },
        })
    }

    #[inline]
    fn is_affected_by_color_interpolation_filters() -> bool {
        true
    }
}

impl EdgeMode {
    fn parse(attr: Attribute, s: &str) -> Result<Self, NodeError> {
        match s {
            "duplicate" => Ok(EdgeMode::Duplicate),
            "wrap" => Ok(EdgeMode::Wrap),
            "none" => Ok(EdgeMode::None),
            _ => Err(NodeError::parse_error(
                attr,
                ParseError::new("invalid value"),
            )),
        }
    }
}
<|endoftext|>