<commit_before>use std::mem;
use std::f64;

use itertools::Itertools;
use ndarray::prelude::*;
use bit_vec::BitVec;
use ordered_float::NotNaN;
use ndarray_rand::RandomExt;
use rand::distributions::Range;

use bio::stats::{Prob, LogProb};

use io::codebook::Codebook;

pub type Readout = BitVec;

pub fn estimate<I: Iterator<Item=(String, Readout)>>(
    codebook: &Codebook,
    readouts: I
) -> (Vec<Prob>, Vec<Prob>) {
    let max_diff = 0.001;
    let shape = (codebook.len(), codebook.N as usize);

    let mut observed_01_errors = Array2::from_elem(shape, 0.0);
    let mut observed_10_errors = Array2::from_elem(shape, 0.0);
    let mut feat_count = Array2::from_elem((codebook.len(), 1), 0.0);
    for (feat, readout) in readouts {
        let feature_id = codebook.get_id(&feat);
        let rec = codebook.record(feature_id);
        if !rec.expressed() {
            continue;
        }
        let encoding = rec.codeword();

        // count features
        feat_count[(feature_id, 0)] += 1.0;

        let mut err_count = 0;
        for k in 0..codebook.N as usize {
            if encoding[k] == false {
                // count 01 errors
                if readout[k] == true {
                    observed_01_errors[(feature_id, k)] += 1.0;
                    err_count += 1;
                }
            } else {
                // count 10 errors
                if readout[k] == false {
                    observed_10_errors[(feature_id, k)] += 1.0;
                    err_count += 1;
                }
            }
        }
        assert!(
            err_count <= 1,
            "unexpected number of errors in readount: {} (<=1 expected)",
            err_count
        );
    }

    // calculate observed (joint) error rates
    let observed_p0 = observed_01_errors / &feat_count;
    let observed_p1 = observed_10_errors / &feat_count;
    debug!("p0 {:?}", observed_p0);
    debug!("p1 {:?}", observed_p1);

    // run EM algorithm to estimate error rates
    let mut prob_no_error = Array2::from_elem(
        (codebook.len(), codebook.N as usize), LogProb::ln_one()
    );

    let mut p0 = Array1::random(codebook.N as usize, Range::new(0.0, 1.0));
    let mut p1 = Array1::random(codebook.N as usize, Range::new(0.0, 1.0));

    let mut p0_last = Array1::from_elem(codebook.N as usize, 0.0);
    let mut p1_last = Array1::from_elem(codebook.N as usize, 0.0);
    for i in 0..1000 {
        // E-step: estimate probability to have no errors in rest of readout
        for feature_id in 0..codebook.len() {
            let encoding = codebook.record(feature_id).codeword();
            for k in 0..codebook.N as usize {
                let p = LogProb((0..codebook.N as usize).filter_map(|l| {
                    if l != k {
                        let p_err = if encoding[l] == false {
                            p0[k]
                        } else {
                            p1[k]
                        };
                        Some(*LogProb((p_err as f64).ln()).ln_one_minus_exp())
                    } else { None }
                }).sum());
                prob_no_error[(feature_id, k)] = p;
            }
        }

        // M-step: find p0 and p1 that maximizes the likelihood
        mem::swap(&mut p0, &mut p0_last);
        mem::swap(&mut p1, &mut p1_last);
        for k in 0..codebook.N as usize {
            // solve least squares: take mean of all estimates
            let p = |observed_p: &Array2<f64>, bit: bool| {
                let mut count = 0.0;
                let p = (0..codebook.len()).filter_map(|feature_id| {
                    let encoding = codebook.record(feature_id).codeword();
                    if feat_count[(feature_id, 0)] < 100.0 || encoding[k] != bit {
                        None
                    } else {
                        count += 1.0;
                        let p = observed_p[(feature_id, k)] * prob_no_error[(feature_id, k)].exp();
                        if k == 4 {
                            debug!("p={}, c={}, obs={}, noerr={}", p, feat_count[(feature_id, 0)], observed_p[(feature_id, k)], prob_no_error[(feature_id, k)].exp());
                        }
                        Some(p)
                    }
                }).sum::<f64>() / count;
                if count == 0.0 {
                    panic!("not enough counts to estimate error rate (at least 1 feature with 50 counts over all cells required)");
                }
                p
            };
            debug!("----------- p0 ------------");
            p0[k] = p(&observed_p0, false);
            //debug!("DEBUG: p0={}", p0[k]);
            debug!("----------- p1 ------------");
            p1[k] = p(&observed_p1, true);
            //debug!("DEBUG: p1={}", p1[k]);
        }

        // check convergence
        let abs = |d: &f64| NotNaN::new(d.abs()).unwrap();
        //debug!("{:?}", p0);
        let convergence = p0.all_close(&p0_last, max_diff) && p1.all_close(&p1_last, max_diff);

        if convergence && i >= 5 {
            debug!("convergence reached");
            debug!("{:?}", p1);
            break;
        }

        debug!("EM-algorithm step {} of {}.", i + 1, 100);
    }

    (
        p0.iter().map(|p| Prob(*p)).collect_vec(),
        p1.iter().map(|p| Prob(*p)).collect_vec()
    )
}
<commit_msg>Implement estimation method from paper.<commit_after>use std::mem;
use std::f64;

use itertools::Itertools;
use ndarray::prelude::*;
use bit_vec::BitVec;
use ordered_float::NotNaN;
use ndarray_rand::RandomExt;
use rand::distributions::Range;

use bio::stats::{Prob, LogProb};

use io::codebook::Codebook;

pub type Readout = BitVec;

pub fn estimate<I: Iterator<Item=(String, Readout)>>(
    codebook: &Codebook,
    readouts: I
) -> (Vec<Prob>, Vec<Prob>) {
    let max_diff = 0.001;
    let shape = (codebook.len(), codebook.N as usize);

    let mut observed_01_errors = Array2::from_elem(shape, 0.0);
    let mut observed_10_errors = Array2::from_elem(shape, 0.0);
    let mut exact_count = Array2::from_elem((codebook.len(), 1), 0.0);

    for (feat, readout) in readouts {
        let feature_id = codebook.get_id(&feat);
        let rec = codebook.record(feature_id);
        if !rec.expressed() {
            continue;
        }
        let encoding = rec.codeword();

        let mut err_count = 0;
        for k in 0..codebook.N as usize {
            match (encoding[k], readout[k]) {
                (true, true) | (false, false) => exact_count[(feature_id, 0)] += 1.0,
                (false, true) => {
                    observed_01_errors[(feature_id, k)] += 1.0;
                    err_count += 1;
                },
                (true, false) => {
                    observed_10_errors[(feature_id, k)] += 1.0;
                    err_count += 1;
                }
            };
        }
        assert!(
            err_count <= 1,
            "unexpected number of errors in readout: {} (<=1 expected)",
            err_count
        );
    }

    debug!("10: {:?}", observed_10_errors);

    // calculate observed (joint) error rates
    let observed_p0 = observed_01_errors / &exact_count;
    let observed_p1 = observed_10_errors / &exact_count;

    // estimate error rates
    let feat_p0 = observed_p0.map(|&o| o / (1.0 + o));
    let feat_p1 = observed_p1.map(|&o| o / (1.0 + o));

    //debug!("p0 {:?}", feat_p0);
    debug!("p1 {:?}", feat_p1);

    let mut p0 = Vec::new();
    let mut p1 = Vec::new();
    for k in 0..codebook.N as usize {
        let p = |feat_p: &Array2<f64>, bit: bool| {
            let mut count = 0.0;
            let p = (0..codebook.len()).filter_map(|feature_id| {
                let encoding = codebook.record(feature_id).codeword();
                if exact_count[(feature_id, 0)] < 10.0 || encoding[k] != bit {
                    None
                } else {
                    count += 1.0;
                    Some(feat_p[(feature_id, k)])
                }
            }).sum::<f64>() / count;
            if count == 0.0 {
                panic!("not enough counts to estimate error rate (at least 1 feature with 50 counts over all cells required)");
            }
            p
        };

        p0.push(Prob(p(&feat_p0, false)));
        p1.push(Prob(p(&feat_p1, true)));
    }

    (p0, p1)
}

// pub fn estimate<I: Iterator<Item=(String, Readout)>>(
//     codebook: &Codebook,
//     readouts: I
// ) -> (Vec<Prob>, Vec<Prob>) {
//     let max_diff = 0.001;
//     let shape = (codebook.len(), codebook.N as usize);
//
//     let mut observed_01_errors = Array2::from_elem(shape, 0.0);
//     let mut observed_10_errors = Array2::from_elem(shape, 0.0);
//     let mut feat_count = Array2::from_elem((codebook.len(), 1), 0.0);
//
//     for (feat, readout) in readouts {
//         let feature_id = codebook.get_id(&feat);
//         let rec = codebook.record(feature_id);
//         if !rec.expressed() {
//             continue;
//         }
//         let encoding = rec.codeword();
//
//         // count features
//         feat_count[(feature_id, 0)] += 1.0;
//
//         let mut err_count = 0;
//         for k in 0..codebook.N as usize {
//             if encoding[k] == false {
//                 // count 01 errors
//                 if readout[k] == true {
//                     observed_01_errors[(feature_id, k)] += 1.0;
//                     err_count += 1;
//                 }
//             } else {
//                 // count 10 errors
//                 if readout[k] == false {
//                     observed_10_errors[(feature_id, k)] += 1.0;
//                     err_count += 1;
//                 }
//             }
//         }
//         assert!(
//             err_count <= 1,
//             "unexpected number of errors in readout: {} (<=1 expected)",
//             err_count
//         );
//     }
//
//     // calculate observed (joint) error rates
//     let observed_p0 = observed_01_errors / &feat_count;
//     let observed_p1 = observed_10_errors / &feat_count;
//     debug!("p0 {:?}", observed_p0);
//     debug!("p1 {:?}", observed_p1);
//
//     // run EM algorithm to estimate error rates
//     let mut prob_no_error = Array2::from_elem(
//         (codebook.len(), codebook.N as usize), LogProb::ln_one()
//     );
//
//
//     let mut p0 = Array1::random(codebook.N as usize, Range::new(0.0, 1.0));
//     let mut p1 = Array1::random(codebook.N as usize, Range::new(0.0, 1.0));
//
//     let mut p0_last = Array1::from_elem(codebook.N as usize, 0.0);
//     let mut p1_last = Array1::from_elem(codebook.N as usize, 0.0);
//     for i in 0..1000 {
//         // E-step: estimate probability to have no errors in rest of readout
//         for feature_id in 0..codebook.len() {
//             let encoding = codebook.record(feature_id).codeword();
//             for k in 0..codebook.N as usize {
//                 let p = LogProb((0..codebook.N as usize).filter_map(|l| {
//                     if l != k {
//                         let p_err = if encoding[l] == false {
//                             p0[k]
//                         } else {
//                             p1[k]
//                         };
//                         Some(*LogProb((p_err as f64).ln()).ln_one_minus_exp())
//                     } else { None }
//                 }).sum());
//                 prob_no_error[(feature_id, k)] = p;
//             }
//         }
//
//         // M-step: find p0 and p1 that maximizes the likelihood
//         mem::swap(&mut p0, &mut p0_last);
//         mem::swap(&mut p1, &mut p1_last);
//         for k in 0..codebook.N as usize {
//             // solve least squares: take mean of all estimates
//             let p = |observed_p: &Array2<f64>, bit: bool| {
//                 let mut count = 0.0;
//                 let p = (0..codebook.len()).filter_map(|feature_id| {
//                     let encoding = codebook.record(feature_id).codeword();
//                     if feat_count[(feature_id, 0)] < 100.0 || encoding[k] != bit {
//                         None
//                     } else {
//                         count += 1.0;
//                         let p = observed_p[(feature_id, k)] * prob_no_error[(feature_id, k)].exp();
//                         if k == 4 {
//                             debug!("p={}, c={}, obs={}, noerr={}", p, feat_count[(feature_id, 0)], observed_p[(feature_id, k)], prob_no_error[(feature_id, k)].exp());
//                         }
//                         Some(p)
//                     }
//                 }).sum::<f64>() / count;
//                 if count == 0.0 {
//                     panic!("not enough counts to estimate error rate (at least 1 feature with 50 counts over all cells required)");
//                 }
//                 p
//             };
//             debug!("----------- p0 ------------");
//             p0[k] = p(&observed_p0, false);
//             //debug!("DEBUG: p0={}", p0[k]);
//             debug!("----------- p1 ------------");
//             p1[k] = p(&observed_p1, true);
//             //debug!("DEBUG: p1={}", p1[k]);
//         }
//
//         // check convergence
//         let abs = |d: &f64| NotNaN::new(d.abs()).unwrap();
//         //debug!("{:?}", p0);
//         let convergence = p0.all_close(&p0_last, max_diff) && p1.all_close(&p1_last, max_diff);
//
//         if convergence && i >= 5 {
//             debug!("convergence reached");
//             debug!("{:?}", p1);
//             break;
//         }
//
//         debug!("EM-algorithm step {} of {}.", i + 1, 100);
//     }
//
//     (
//         p0.iter().map(|p| Prob(*p)).collect_vec(),
//         p1.iter().map(|p| Prob(*p)).collect_vec()
//     )
// }
<|endoftext|>


<commit_before>use std::rc::Rc;
use std::io::{self, Read, Write};
use std::net::Shutdown;

use futures::prelude::*;
use tokio_io::{AsyncRead, AsyncWrite};
use tokio_io::io::shutdown;
use bytes::{Bytes, IntoBuf};
use h2::{self, server as h2s, client as h2c};
use tokio_core::net::TcpStream;

#[async]
pub fn copy_from_h2<
    W: AsyncWrite + 'static,
    B: Stream<Item = Bytes, Error = h2::Error> + 'static,
>(
    src: B,
    mut dst: W,
) -> Result<usize, h2::Error> {
    let mut counter = 0;
    #[async]
    for buf in src {
        let mut buf = buf.into_buf();
        let n = poll!(dst.write_buf(&mut buf))?;
        counter += n;
    }
    await!(shutdown(dst))?;
    Ok(counter)
}

pub trait SendData<B: IntoBuf> {
    fn send_data(&mut self, data: B, end_of_stream: bool) -> Result<(), h2::Error>;
}

impl<B: IntoBuf> SendData<B> for h2c::Stream<B> {
    fn send_data(&mut self, data: B, end_of_stream: bool) -> Result<(), h2::Error> {
        h2c::Stream::send_data(self, data, end_of_stream)
    }
}
impl<B: IntoBuf> SendData<B> for h2s::Stream<B> {
    fn send_data(&mut self, data: B, end_of_stream: bool) -> Result<(), h2::Error> {
        h2s::Stream::send_data(self, data, end_of_stream)
    }
}

#[async]
pub fn copy_to_h2<R: AsyncRead + 'static, H: SendData<Bytes> + 'static>(
    mut src: R,
    mut dst: H,
) -> Result<usize, h2::Error> {
    let mut counter = 0;
    let mut buf = Vec::with_capacity(2048);
    loop {
        let n = poll!(src.read_buf(&mut buf))?;
        if n == 0 {
            dst.send_data(Bytes::from(&buf[..n]), true)?;
            break;
        } else {
            dst.send_data(Bytes::from(&buf[..n]), false)?;
        }
        counter += n;
    }
    Ok(counter)
}

// This is a custom type used to have a custom implementation of the
// `AsyncWrite::shutdown` method which actually calls `TcpStream::shutdown` to
// notify the remote end that we're done writing.
#[derive(Clone)]
pub struct Socket(Rc<TcpStream>);

impl Socket {
    pub fn new(s: TcpStream) -> Socket {
        Socket(Rc::new(s))
    }
}

impl Read for Socket {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        (&*self.0).read(buf)
    }
}

impl Write for Socket {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        (&*self.0).write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl AsyncRead for Socket {}

impl AsyncWrite for Socket {
    fn shutdown(&mut self) -> Poll<(), io::Error> {
        try!(self.0.shutdown(Shutdown::Write));
        Ok(().into())
    }
}

#[cfg(test)]
mod test {
    use std::io::Cursor;
    use std::rc::Rc;
    use std::cell::RefCell;

    use futures::prelude::*;
    use futures::stream::iter_ok;

    use super::*;

    #[derive(Clone)]
    struct Dst(Rc<RefCell<Cursor<Vec<u8>>>>);
    impl Write for Dst {
        fn write(&mut self, buf: &[u8]) -> ::std::io::Result<usize> {
            self.0.borrow_mut().write(buf)
        }
        fn flush(&mut self) -> ::std::io::Result<()> {
            self.0.borrow_mut().flush()
        }
    }
    impl AsyncWrite for Dst {
        fn shutdown(&mut self) -> Poll<(), ::std::io::Error> {
            Ok(().into())
        }
    }
    impl SendData<Bytes> for Dst {
        fn send_data(&mut self, data: Bytes, _end_of_stream: bool) -> Result<(), h2::Error> {
            self.0.borrow_mut().get_mut().extend(data);
            Ok(())
        }
    }

    #[test]
    fn test_copy_from_h2() {
        let dst = Dst(Rc::new(RefCell::new(Cursor::new(Vec::new()))));
        let src = iter_ok(vec![
            Bytes::from("123"),
            Bytes::from("456"),
            Bytes::from("789"),
        ]);
        let r = copy_from_h2(src, dst.clone()).wait().unwrap();
        assert_eq!(r, 9);
        assert_eq!(dst.0.borrow().get_ref(), b"123456789");
    }

    #[test]
    fn test_copy_to_h2() {
        let dst = Dst(Rc::new(RefCell::new(Cursor::new(Vec::new()))));
        let src: &[u8] = b"123456789";
        let r = copy_to_h2(src, dst.clone()).wait().unwrap();
        assert_eq!(r, 9);
        assert_eq!(dst.0.borrow().get_ref(), b"123456789");
    }
}
<commit_msg>Fix dirty buffer in `io::copt_to_h2`<commit_after>use std::rc::Rc;
use std::io::{self, Read, Write};
use std::net::Shutdown;

use futures::prelude::*;
use tokio_io::{AsyncRead, AsyncWrite};
use tokio_io::io::shutdown;
use bytes::{BytesMut, Bytes, BufMut, IntoBuf};
use h2::{self, server as h2s, client as h2c};
use tokio_core::net::TcpStream;

const BUF_SIZE: usize = 2048;

#[async]
pub fn copy_from_h2<
    W: AsyncWrite + 'static,
    B: Stream<Item = Bytes, Error = h2::Error> + 'static,
>(
    src: B,
    mut dst: W,
) -> Result<usize, h2::Error> {
    let mut counter = 0;
    #[async]
    for buf in src {
        let mut buf = buf.into_buf();
        let n = poll!(dst.write_buf(&mut buf))?;
        counter += n;
    }
    await!(shutdown(dst))?;
    Ok(counter)
}

pub trait SendData<B: IntoBuf> {
    fn send_data(&mut self, data: B, end_of_stream: bool) -> Result<(), h2::Error>;
}

impl<B: IntoBuf> SendData<B> for h2c::Stream<B> {
    fn send_data(&mut self, data: B, end_of_stream: bool) -> Result<(), h2::Error> {
        h2c::Stream::send_data(self, data, end_of_stream)
    }
}
impl<B: IntoBuf> SendData<B> for h2s::Stream<B> {
    fn send_data(&mut self, data: B, end_of_stream: bool) -> Result<(), h2::Error> {
        h2s::Stream::send_data(self, data, end_of_stream)
    }
}

#[async]
pub fn copy_to_h2<R: AsyncRead + 'static, H: SendData<Bytes> + 'static>(
    mut src: R,
    mut dst: H,
) -> Result<usize, h2::Error> {
    let mut counter = 0;
    let mut buf = BytesMut::with_capacity(BUF_SIZE);
    loop {
        let n = poll!(src.read_buf(&mut buf))?;
        if n == 0 {
            dst.send_data(buf.take().freeze(), true)?;
            break;
        } else {
            dst.send_data(buf.take().freeze(), false)?;
        }
        counter += n;
        let rem = buf.remaining_mut();
        if rem < BUF_SIZE {
            buf.reserve(BUF_SIZE - rem);
        }
    }
    Ok(counter)
}

// This is a custom type used to have a custom implementation of the
// `AsyncWrite::shutdown` method which actually calls `TcpStream::shutdown` to
// notify the remote end that we're done writing.
#[derive(Clone)]
pub struct Socket(Rc<TcpStream>);

impl Socket {
    pub fn new(s: TcpStream) -> Socket {
        Socket(Rc::new(s))
    }
}

impl Read for Socket {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        (&*self.0).read(buf)
    }
}

impl Write for Socket {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        (&*self.0).write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl AsyncRead for Socket {}

impl AsyncWrite for Socket {
    fn shutdown(&mut self) -> Poll<(), io::Error> {
        try!(self.0.shutdown(Shutdown::Write));
        Ok(().into())
    }
}

#[cfg(test)]
mod test {
    use std::io::Cursor;
    use std::rc::Rc;
    use std::cell::RefCell;

    use futures::prelude::*;
    use futures::stream::iter_ok;

    use super::*;

    #[derive(Clone)]
    struct Dst(Rc<RefCell<Cursor<Vec<u8>>>>);
    impl Write for Dst {
        fn write(&mut self, buf: &[u8]) -> ::std::io::Result<usize> {
            self.0.borrow_mut().write(buf)
        }
        fn flush(&mut self) -> ::std::io::Result<()> {
            self.0.borrow_mut().flush()
        }
    }
    impl AsyncWrite for Dst {
        fn shutdown(&mut self) -> Poll<(), ::std::io::Error> {
            Ok(().into())
        }
    }
    impl SendData<Bytes> for Dst {
        fn send_data(&mut self, data: Bytes, _end_of_stream: bool) -> Result<(), h2::Error> {
            self.0.borrow_mut().get_mut().extend(data);
            Ok(())
        }
    }

    #[test]
    fn test_copy_from_h2() {
        let dst = Dst(Rc::new(RefCell::new(Cursor::new(Vec::new()))));
        let src = iter_ok(vec![
            Bytes::from("123"),
            Bytes::from("456"),
            Bytes::from("789"),
        ]);
        let r = copy_from_h2(src, dst.clone()).wait().unwrap();
        assert_eq!(r, 9);
        assert_eq!(dst.0.borrow().get_ref(), b"123456789");
    }

    #[test]
    fn test_copy_to_h2() {
        let dst = Dst(Rc::new(RefCell::new(Cursor::new(Vec::new()))));
        let src: &[u8] = b"123456789";
        let r = copy_to_h2(src, dst.clone()).wait().unwrap();
        assert_eq!(r, 9);
        assert_eq!(dst.0.borrow().get_ref(), b"123456789");
    }
}
<|endoftext|>


<commit_before>use ffi;
use std::os::raw::c_int;
use std::ptr;
use types::*;
use ffi::MaybeError;
use device::DeviceInfo;

/// Represents the input port of a PortMidi device.
pub struct InputPort {
    stream: *const ffi::PortMidiStream,
    device: ffi::PmDeviceId,
    buffer_size: usize,
}
impl InputPort {
    /// Construct a new `InputPort` for the given device and buffer size.
    ///
    /// If the `device` is not an input device an `Error::NotAnInputDevice` is returned.
    pub fn new(device: DeviceInfo, buffer_size: usize) -> Result<InputPort> {
        if device.is_output() {
            return Err(Error::NotAnInputDevice);
        }
        let raw_stream: *const ffi::PortMidiStream = ptr::null();
        try!(Result::from(unsafe {
            ffi::Pm_OpenInput(&raw_stream as *const *const _,
                              device.id(),
                              ptr::null(), // *inputDriverInfo, not needed for normal operation
                              buffer_size as c_int,
                              ptr::null(), // PmTimeProcPtr, a procedure that returns time in ms,
                              ptr::null()) // time_info, a pointer passed to the time procedure
        }));

        Ok(InputPort {
            stream: raw_stream,
            device: device.id(),
            buffer_size: buffer_size,
        })
    }

    /// Returns a `Vec<MidiEvent>` with at most `cnt` elements.
    /// If there was no Midi event available, `None` is returned.
    /// If PortMidi fails to read from the device an `Error::PortMidi(_)` is returned.
    pub fn read_n(&self, cnt: usize) -> Result<Option<Vec<MidiEvent>>> {
        let read_cnt = if cnt > self.buffer_size {
            self.buffer_size as c_int
        } else {
            cnt as c_int
        };
        let mut event_buffer = vec![ffi::PmEvent::default(); self.buffer_size];
        let res = unsafe { ffi::Pm_Read(self.stream, event_buffer.as_mut_ptr(), read_cnt) };
        ::std::thread::sleep_ms(20);
        match ffi::PmError::try_from(res) {
            Ok(event_cnt) => {
                let events = (0..event_cnt as usize)
                                 .map(|i| MidiEvent::from(event_buffer[i].clone()))
                                 .collect::<Vec<MidiEvent>>();
                Ok(Some(events))
            }
            err @ Err(ffi::PmError::PmNoError) => Ok(None),
            Err(err) => return Err(Error::PortMidi(err)),
        }
    }

    /// Reads a single `MidiEvent` if one is avaible.
    ///
    /// A `Result` of `None` means no event was available.
    pub fn read(&mut self) -> Result<Option<MidiEvent>> {
        match self.read_n(1) {
            Ok(Some(mut vec)) => Ok(vec.pop()),
            Ok(_) => Ok(None),
            Err(e) => Err(e),
        }
    }

    /// Polls for available Midi events.
    /// Returns `true` if there are events available, otherwise `false` is returned.
    /// If the polling fails an `Error::PortMidi(_)` is returned.
    pub fn poll(&self) -> Result<bool> {
        let pm_error = unsafe { ffi::Pm_Poll(self.stream) };
        match pm_error {
            ffi::PmError::PmNoError => Ok(false),
            ffi::PmError::PmGotData => Ok(true),
            err @ _ => Err(Error::PortMidi(err)),
        }
    }
}
impl Drop for InputPort {
    fn drop(&mut self) {
        if let Err(err) = Result::from(unsafe { ffi::Pm_Close(self.stream) }) {
            println!("{}", err);
        }
    }
}

/// Representation the output port of a PortMidi device.
pub struct OutputPort {
    stream: *const ffi::PortMidiStream,
    device: ffi::PmDeviceId,
    buffer_size: usize,
}
impl OutputPort {
    /// Construct a new `OutputPort` for the given device and buffer size.
    ///
    /// If the `device` is not an output device an `Error::NotAnOutputDevice` is returned.
    pub fn new(device: DeviceInfo, buffer_size: usize) -> Result<OutputPort> {
        if device.is_input() {
            return Err(Error::NotAnOutputDevice);
        }
        let raw_stream: *const ffi::PortMidiStream = ptr::null();
        try!(Result::from(unsafe {
            ffi::Pm_OpenOutput(&raw_stream as *const *const _,
                               device.id(),
                               ptr::null(), // *inputDriverInfo, not needed for normal operation
                               buffer_size as c_int,
                               ptr::null(), // PmTimeProcPtr, a procedure that returns time in ms,
                               ptr::null(), // time_info, a pointer passed to the time procedure
                               0) //latency
        }));

        Ok(OutputPort {
            stream: raw_stream,
            device: device.id(),
            buffer_size: buffer_size,
        })
    }

    /// Terminates outgoing messages immediately.
    ///
    /// The caller should immediately close the output port, this may
    /// result in transmission of a partial midi message. Note, not all platforms
    /// support abort.
    ///
    /// NOTE: This is unsafe, either mark the device as invalid or try to reopen it afterwards.
    fn abort(&mut self) -> Result<()> {
        Result::from(unsafe { ffi::Pm_Abort(self.stream) })
    }

    /// Write a single `MidiEvent`
    pub fn write_event(&mut self, midi_event: MidiEvent) -> Result<()> {
        let event = midi_event.into();
        Result::from(unsafe { ffi::Pm_Write(self.stream, &event, 1) })

    /// Write a buffer of midi events to the output port.
    /// Returns an `Error::PortMidi(_)` if something went wrong.
    pub fn write_events<T: Into<MidiEvent>>(&mut self, midi_events: Vec<T>) -> Result<()> {
        let events: Vec<ffi::PmEvent> = midi_events.into_iter()
                                                   .map(|event| event.into().into())
                                                   .collect();
        Result::from(unsafe { ffi::Pm_Write(self.stream, events.as_ptr(), events.len() as c_int) })
    }

    /// Write a single `MidiMessage`.
    /// Returns an `Error::PortMidi(_)` if something went wrong.
    pub fn write_message(&mut self, midi_message: MidiMessage) -> Result<()> {
        let message = midi_message.into();
        Result::from(unsafe { ffi::Pm_WriteShort(self.stream, 0, message) })
    }
}
impl Drop for OutputPort {
    fn drop(&mut self) {
        if let Err(err) = Result::from(unsafe { ffi::Pm_Close(self.stream) }) {
            println!("{}", err);
        }
    }
}
<commit_msg>Use call `write_events` in `write_event`<commit_after>use ffi;
use std::os::raw::c_int;
use std::ptr;
use types::*;
use ffi::MaybeError;
use device::DeviceInfo;

/// Represents the input port of a PortMidi device.
pub struct InputPort {
    stream: *const ffi::PortMidiStream,
    device: ffi::PmDeviceId,
    buffer_size: usize,
}
impl InputPort {
    /// Construct a new `InputPort` for the given device and buffer size.
    ///
    /// If the `device` is not an input device an `Error::NotAnInputDevice` is returned.
    pub fn new(device: DeviceInfo, buffer_size: usize) -> Result<InputPort> {
        if device.is_output() {
            return Err(Error::NotAnInputDevice);
        }
        let raw_stream: *const ffi::PortMidiStream = ptr::null();
        try!(Result::from(unsafe {
            ffi::Pm_OpenInput(&raw_stream as *const *const _,
                              device.id(),
                              ptr::null(), // *inputDriverInfo, not needed for normal operation
                              buffer_size as c_int,
                              ptr::null(), // PmTimeProcPtr, a procedure that returns time in ms,
                              ptr::null()) // time_info, a pointer passed to the time procedure
        }));

        Ok(InputPort {
            stream: raw_stream,
            device: device.id(),
            buffer_size: buffer_size,
        })
    }

    /// Returns a `Vec<MidiEvent>` with at most `cnt` elements.
    /// If there was no Midi event available, `None` is returned.
    /// If PortMidi fails to read from the device an `Error::PortMidi(_)` is returned.
    pub fn read_n(&self, cnt: usize) -> Result<Option<Vec<MidiEvent>>> {
        let read_cnt = if cnt > self.buffer_size {
            self.buffer_size as c_int
        } else {
            cnt as c_int
        };
        let mut event_buffer = vec![ffi::PmEvent::default(); self.buffer_size];
        let res = unsafe { ffi::Pm_Read(self.stream, event_buffer.as_mut_ptr(), read_cnt) };
        ::std::thread::sleep_ms(20);
        match ffi::PmError::try_from(res) {
            Ok(event_cnt) => {
                let events = (0..event_cnt as usize)
                                 .map(|i| MidiEvent::from(event_buffer[i].clone()))
                                 .collect::<Vec<MidiEvent>>();
                Ok(Some(events))
            }
            err @ Err(ffi::PmError::PmNoError) => Ok(None),
            Err(err) => return Err(Error::PortMidi(err)),
        }
    }

    /// Reads a single `MidiEvent` if one is avaible.
    ///
    /// A `Result` of `None` means no event was available.
    pub fn read(&mut self) -> Result<Option<MidiEvent>> {
        match self.read_n(1) {
            Ok(Some(mut vec)) => Ok(vec.pop()),
            Ok(_) => Ok(None),
            Err(e) => Err(e),
        }
    }

    /// Polls for available Midi events.
    /// Returns `true` if there are events available, otherwise `false` is returned.
    /// If the polling fails an `Error::PortMidi(_)` is returned.
    pub fn poll(&self) -> Result<bool> {
        let pm_error = unsafe { ffi::Pm_Poll(self.stream) };
        match pm_error {
            ffi::PmError::PmNoError => Ok(false),
            ffi::PmError::PmGotData => Ok(true),
            err @ _ => Err(Error::PortMidi(err)),
        }
    }
}
impl Drop for InputPort {
    fn drop(&mut self) {
        if let Err(err) = Result::from(unsafe { ffi::Pm_Close(self.stream) }) {
            println!("{}", err);
        }
    }
}

/// Representation the output port of a PortMidi device.
pub struct OutputPort {
    stream: *const ffi::PortMidiStream,
    device: ffi::PmDeviceId,
    buffer_size: usize,
}
impl OutputPort {
    /// Construct a new `OutputPort` for the given device and buffer size.
    ///
    /// If the `device` is not an output device an `Error::NotAnOutputDevice` is returned.
    pub fn new(device: DeviceInfo, buffer_size: usize) -> Result<OutputPort> {
        if device.is_input() {
            return Err(Error::NotAnOutputDevice);
        }
        let raw_stream: *const ffi::PortMidiStream = ptr::null();
        try!(Result::from(unsafe {
            ffi::Pm_OpenOutput(&raw_stream as *const *const _,
                               device.id(),
                               ptr::null(), // *inputDriverInfo, not needed for normal operation
                               buffer_size as c_int,
                               ptr::null(), // PmTimeProcPtr, a procedure that returns time in ms,
                               ptr::null(), // time_info, a pointer passed to the time procedure
                               0) //latency
        }));

        Ok(OutputPort {
            stream: raw_stream,
            device: device.id(),
            buffer_size: buffer_size,
        })
    }

    /// Terminates outgoing messages immediately.
    ///
    /// The caller should immediately close the output port, this may
    /// result in transmission of a partial midi message. Note, not all platforms
    /// support abort.
    ///
    /// NOTE: This is unsafe, either mark the device as invalid or try to reopen it afterwards.
    fn abort(&mut self) -> Result<()> {
        Result::from(unsafe { ffi::Pm_Abort(self.stream) })
    }

    /// Write a single `MidiEvent`.
    /// Returns an `Error::PortMidi(_)` if something went wrong.
    pub fn write_event<T: Into<MidiEvent>>(&mut self, midi_event: T) -> Result<()> {
        self.write_events(vec![midi_event])
    }

    /// Write a buffer of midi events to the output port.
    /// Returns an `Error::PortMidi(_)` if something went wrong.
    pub fn write_events<T: Into<MidiEvent>>(&mut self, midi_events: Vec<T>) -> Result<()> {
        let events: Vec<ffi::PmEvent> = midi_events.into_iter()
                                                   .map(|event| event.into().into())
                                                   .collect();
        Result::from(unsafe { ffi::Pm_Write(self.stream, events.as_ptr(), events.len() as c_int) })
    }

    /// Write a single `MidiMessage`.
    /// Returns an `Error::PortMidi(_)` if something went wrong.
    pub fn write_message(&mut self, midi_message: MidiMessage) -> Result<()> {
        let message = midi_message.into();
        Result::from(unsafe { ffi::Pm_WriteShort(self.stream, 0, message) })
    }
}
impl Drop for OutputPort {
    fn drop(&mut self) {
        if let Err(err) = Result::from(unsafe { ffi::Pm_Close(self.stream) }) {
            println!("{}", err);
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

#![forbid(unsafe_code)]
use std::cmp::min;

use crate::experiments::ExperimentParam;
use crate::{
    cluster::Cluster,
    experiments::{
        Experiment, PerformanceBenchmarkNodesDownParams,
        PerformanceBenchmarkThreeRegionSimulationParams, RebootRandomValidatorsParams,
        RecoveryTimeParams,
    },
};

pub struct ExperimentSuite {
    pub experiments: Vec<Box<dyn Experiment>>,
}

impl ExperimentSuite {
    pub fn new_pre_release(cluster: &Cluster) -> Self {
        let mut experiments: Vec<Box<dyn Experiment>> = vec![];
        experiments.push(Box::new(
            RecoveryTimeParams {
                num_accounts_to_mint: 100_000,
            }
            .build(cluster),
        ));
        let count = min(3, cluster.instances().len() / 3);
        // Reboot different sets of 3 validators *100 times
        for _ in 0..10 {
            let b = Box::new(RebootRandomValidatorsParams { count }.build(cluster));
            experiments.push(b);
        }
        experiments.push(Box::new(
            PerformanceBenchmarkNodesDownParams { num_nodes_down: 0 }.build(cluster),
        ));
        experiments.push(Box::new(
            PerformanceBenchmarkNodesDownParams { num_nodes_down: 10 }.build(cluster),
        ));
        experiments.push(Box::new(
            PerformanceBenchmarkThreeRegionSimulationParams {}.build(cluster),
        ));
        Self { experiments }
    }

    pub fn new_perf_suite(cluster: &Cluster) -> Self {
        let mut experiments: Vec<Box<dyn Experiment>> = vec![];
        experiments.push(Box::new(
            PerformanceBenchmarkNodesDownParams { num_nodes_down: 0 }.build(cluster),
        ));
        experiments.push(Box::new(
            PerformanceBenchmarkNodesDownParams { num_nodes_down: 10 }.build(cluster),
        ));
        experiments.push(Box::new(
            PerformanceBenchmarkThreeRegionSimulationParams {}.build(cluster),
        ));
        Self { experiments }
    }
}
<commit_msg>[cluster-test] Disable recovery experiment by default<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

#![forbid(unsafe_code)]
use std::cmp::min;
use std::env;

use crate::experiments::ExperimentParam;
use crate::{
    cluster::Cluster,
    experiments::{
        Experiment, PerformanceBenchmarkNodesDownParams,
        PerformanceBenchmarkThreeRegionSimulationParams, RebootRandomValidatorsParams,
        RecoveryTimeParams,
    },
};

pub struct ExperimentSuite {
    pub experiments: Vec<Box<dyn Experiment>>,
}

impl ExperimentSuite {
    pub fn new_pre_release(cluster: &Cluster) -> Self {
        let mut experiments: Vec<Box<dyn Experiment>> = vec![];
        if env::var("RECOVERY_EXP").is_ok() {
            experiments.push(Box::new(
                RecoveryTimeParams {
                    num_accounts_to_mint: 100_000,
                }
                .build(cluster),
            ));
        }
        let count = min(3, cluster.instances().len() / 3);
        // Reboot different sets of 3 validators *100 times
        for _ in 0..10 {
            let b = Box::new(RebootRandomValidatorsParams { count }.build(cluster));
            experiments.push(b);
        }
        experiments.push(Box::new(
            PerformanceBenchmarkNodesDownParams { num_nodes_down: 0 }.build(cluster),
        ));
        experiments.push(Box::new(
            PerformanceBenchmarkNodesDownParams { num_nodes_down: 10 }.build(cluster),
        ));
        experiments.push(Box::new(
            PerformanceBenchmarkThreeRegionSimulationParams {}.build(cluster),
        ));
        Self { experiments }
    }

    pub fn new_perf_suite(cluster: &Cluster) -> Self {
        let mut experiments: Vec<Box<dyn Experiment>> = vec![];
        experiments.push(Box::new(
            PerformanceBenchmarkNodesDownParams { num_nodes_down: 0 }.build(cluster),
        ));
        experiments.push(Box::new(
            PerformanceBenchmarkNodesDownParams { num_nodes_down: 10 }.build(cluster),
        ));
        experiments.push(Box::new(
            PerformanceBenchmarkThreeRegionSimulationParams {}.build(cluster),
        ));
        Self { experiments }
    }
}
<|endoftext|>


<commit_before>use byte_conv::As as AsBytes;
use libc::{self, c_char, c_ushort, c_int, c_uint};
use netlink_rs::socket::{Msg as NetlinkMessage, Socket as NetlinkSocket, NetlinkAddr,
                         Payload as NetlinkPayload, NlMsgHeader};
use netlink_rs::Protocol as NetlinkProtocol;
use std::{mem, io};

// linux/rtnetlink.h
const RTM_NEWLINK: u16 = 16;

// linux/socket.h
const AF_UNSPEC: c_char = 0;

// linux/if.h; netdevice(7)
const IFF_UP: c_uint = 1;

/// Mirrors the `struct ifinfomsg` (see rtnetlink(7))
#[repr(C)]
#[derive(Clone, Copy, Debug)]
struct IfInfoMsg {
    /// Address family, should always be `AF_UNSPEC`
    family: c_char,

    /// Padding bytes, should be set to 0.
    _pad: c_char, // must be 0

    /// Device type (FIXME: ?)
    dev_type: c_ushort,

    /// The interface index, can be retrieved using `if_nametoindex` from the
    /// `nix` crate.
    index: c_int,

    /// Device flags (FIXME: ?)
    flags: c_uint,

    /// Change mask
    change: c_uint,
}

impl IfInfoMsg {
    fn new(if_index: i32, flags: c_uint, change: c_uint) -> IfInfoMsg {
        IfInfoMsg {
            family: AF_UNSPEC,
            _pad: 0,

            // dev_type: ARPHRD_CAN,
            dev_type: 0,
            index: if_index,
            flags: flags,

            change: change,
        }
    }
}

fn send_and_read_ack(sock: &mut NetlinkSocket,
                     msg: NetlinkMessage,
                     dest: &NetlinkAddr)
                     -> io::Result<()> {
    // FIXME: check return length
    let _ = sock.send(msg, dest)?;

    // receive all pending messages
    let (addr, msgs) = sock.recv()?;

    match msgs.into_iter().nth(0) {
        Some(msg) => {
            println!("Received Address: {:?}", addr);
            println!("Received Message: {:?}", msg);
            match *msg.payload() {
                NetlinkPayload::Ack(_) => (),
                _ => panic!("Message received is not an ACK"),
            }
        }
        None => panic!("Expect ACK, but no ACK received"),
    }

    Ok(())

}

/// Opens a new netlink socket, bound to this process' PID
fn open_nl_route_socket() -> io::Result<NetlinkSocket> {
    let sock = NetlinkSocket::new(NetlinkProtocol::Route)?;

    // retrieve PID
    let pid = unsafe { libc::getpid() } as u32;
    let pid = 0;  // FIXME: is this necessary?

    // after opening the socket, bind it to be able to receive messages back
    // groups is set to 0, because we want no notifications
    let bind_addr = NetlinkAddr::new(pid, 0);
    sock.bind(bind_addr)?;

    Ok(sock)
}

fn bring_down(if_index: c_uint) -> io::Result<()> {
    let mut nl = open_nl_route_socket()?;

    // prepare message
    let mut header = NlMsgHeader::user_defined(RTM_NEWLINK, mem::size_of::<IfInfoMsg>() as u32);
    header.ack();

    let info = IfInfoMsg::new(if_index as i32, 0, IFF_UP);
    let msg = NetlinkMessage::new(header, NetlinkPayload::Data(info.as_bytes()));

    let kernel_addr = NetlinkAddr::new(0, 0);

    // send the message
    send_and_read_ack(&mut nl, msg, &kernel_addr)
}
<commit_msg>Better docs in nl.rs module.<commit_after>use byte_conv::As as AsBytes;
use libc::{self, c_char, c_ushort, c_int, c_uint};
use netlink_rs::socket::{Msg as NetlinkMessage, Socket as NetlinkSocket, NetlinkAddr,
                         Payload as NetlinkPayload, NlMsgHeader};
use netlink_rs::Protocol as NetlinkProtocol;
use std::{mem, io};

// linux/rtnetlink.h
const RTM_NEWLINK: u16 = 16;

// linux/socket.h
const AF_UNSPEC: c_char = 0;

// linux/if.h; netdevice(7)
const IFF_UP: c_uint = 1;

/// Mirrors the `struct ifinfomsg` (see rtnetlink(7))
#[repr(C)]
#[derive(Clone, Copy, Debug)]
struct IfInfoMsg {
    /// Address family, should always be `AF_UNSPEC`
    family: c_char,

    /// Padding bytes, should be set to 0.
    _pad: c_char, // must be 0

    /// Device type (FIXME: ?)
    dev_type: c_ushort,

    /// The interface index, can be retrieved using `if_nametoindex` from the
    /// `nix` crate.
    index: c_int,

    /// Device flags (FIXME: ?)
    flags: c_uint,

    /// Change mask
    change: c_uint,
}

impl IfInfoMsg {
    fn new(if_index: i32, flags: c_uint, change: c_uint) -> IfInfoMsg {
        IfInfoMsg {
            family: AF_UNSPEC,
            _pad: 0,

            // dev_type: ARPHRD_CAN,
            dev_type: 0,
            index: if_index,
            flags: flags,

            change: change,
        }
    }
}

/// Sends a netlink message down a netlink socket, and checks if an ACK was
/// properly received.
fn send_and_read_ack(sock: &mut NetlinkSocket,
                     msg: NetlinkMessage,
                     dest: &NetlinkAddr)
                     -> io::Result<()> {
    // FIXME: check return length
    let _ = sock.send(msg, dest)?;

    // receive all pending messages
    let (addr, msgs) = sock.recv()?;

    match msgs.into_iter().nth(0) {
        Some(msg) => {
            println!("Received Address: {:?}", addr);
            println!("Received Message: {:?}", msg);
            match *msg.payload() {
                NetlinkPayload::Ack(_) => (),
                _ => panic!("Message received is not an ACK"),
            }
        }
        None => panic!("Expect ACK, but no ACK received"),
    }

    Ok(())

}

/// Opens a new netlink socket, bound to this process' PID
fn open_nl_route_socket() -> io::Result<NetlinkSocket> {
    let sock = NetlinkSocket::new(NetlinkProtocol::Route)?;

    // retrieve PID
    let pid = unsafe { libc::getpid() } as u32;
    let pid = 0;  // FIXME: is this necessary?

    // after opening the socket, bind it to be able to receive messages back
    // groups is set to 0, because we want no notifications
    let bind_addr = NetlinkAddr::new(pid, 0);
    sock.bind(bind_addr)?;

    Ok(sock)
}

/// Brings down a CAN interface
fn bring_down(if_index: c_uint) -> io::Result<()> {
    let mut nl = open_nl_route_socket()?;

    // prepare message
    let mut header = NlMsgHeader::user_defined(RTM_NEWLINK, mem::size_of::<IfInfoMsg>() as u32);
    header.ack();

    let info = IfInfoMsg::new(if_index as i32, 0, IFF_UP);
    let msg = NetlinkMessage::new(header, NetlinkPayload::Data(info.as_bytes()));

    let kernel_addr = NetlinkAddr::new(0, 0);

    // send the message
    send_and_read_ack(&mut nl, msg, &kernel_addr)
}
<|endoftext|>


<commit_before>//! Entry point for the CSS filters infrastructure.

use cssparser::{BasicParseError, Parser};
use markup5ever::{expanded_name, local_name, namespace_url, ns};
use std::time::Instant;

use crate::bbox::BoundingBox;
use crate::coord_units::CoordUnits;
use crate::document::AcquiredNodes;
use crate::drawing_ctx::DrawingCtx;
use crate::element::{Draw, ElementResult, SetAttributes};
use crate::error::{ElementError, ParseError, RenderingError};
use crate::length::*;
use crate::node::{Node, NodeBorrow};
use crate::parsers::{CustomIdent, Parse, ParseValue};
use crate::properties::ComputedValues;
use crate::property_defs::ColorInterpolationFilters;
use crate::surface_utils::shared_surface::{SharedImageSurface, SurfaceType};
use crate::transform::Transform;
use crate::xml::Attributes;

mod bounds;
use self::bounds::BoundsBuilder;

pub mod context;
use self::context::{FilterContext, FilterResult};

mod error;
use self::error::FilterError;

/// A filter primitive interface.
pub trait FilterEffect: SetAttributes + Draw {
    fn resolve(&self, node: &Node) -> Result<(Primitive, PrimitiveParams), FilterError>;
}

// Filter Effects do not need to draw themselves
impl<T: FilterEffect> Draw for T {}

pub mod blend;
pub mod color_matrix;
pub mod component_transfer;
pub mod composite;
pub mod convolve_matrix;
pub mod displacement_map;
pub mod flood;
pub mod gaussian_blur;
pub mod image;
pub mod lighting;
pub mod merge;
pub mod morphology;
pub mod offset;
pub mod tile;
pub mod turbulence;

/// Resolved parameters for each filter primitive.
///
/// These gather all the data that a primitive may need during rendering:
/// the `feFoo` element's attributes, any computed values from its properties,
/// and parameters extracted from the element's children (for example,
/// `feMerge` gathers info from its `feMergNode` children).
pub enum PrimitiveParams {
    Blend(blend::Blend),
    ColorMatrix(color_matrix::ColorMatrix),
    ComponentTransfer(component_transfer::ComponentTransfer),
    Composite(composite::Composite),
    ConvolveMatrix(convolve_matrix::ConvolveMatrix),
    DiffuseLighting(lighting::DiffuseLighting),
    DisplacementMap(displacement_map::DisplacementMap),
    Flood(flood::Flood),
    GaussianBlur(gaussian_blur::GaussianBlur),
    Image(image::Image),
    Merge(merge::Merge),
    Morphology(morphology::Morphology),
    Offset(offset::Offset),
    SpecularLighting(lighting::SpecularLighting),
    Tile(tile::Tile),
    Turbulence(turbulence::Turbulence),
}

/// The base filter primitive node containing common properties.
#[derive(Default, Clone)]
pub struct Primitive {
    x: Option<Length<Horizontal>>,
    y: Option<Length<Vertical>>,
    width: Option<ULength<Horizontal>>,
    height: Option<ULength<Vertical>>,
    result: Option<CustomIdent>,
}

pub struct ResolvedPrimitive {
    x: Option<Length<Horizontal>>,
    y: Option<Length<Vertical>>,
    width: Option<ULength<Horizontal>>,
    height: Option<ULength<Vertical>>,
    result: Option<CustomIdent>,
}

/// An enumeration of possible inputs for a filter primitive.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub enum Input {
    Unspecified,
    SourceGraphic,
    SourceAlpha,
    BackgroundImage,
    BackgroundAlpha,
    FillPaint,
    StrokePaint,
    FilterOutput(CustomIdent),
}

enum_default!(Input, Input::Unspecified);

impl Parse for Input {
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Self, ParseError<'i>> {
        parser
            .try_parse(|p| {
                Ok(parse_identifiers!(
                    p,
                    "SourceGraphic" => Input::SourceGraphic,
                    "SourceAlpha" => Input::SourceAlpha,
                    "BackgroundImage" => Input::BackgroundImage,
                    "BackgroundAlpha" => Input::BackgroundAlpha,
                    "FillPaint" => Input::FillPaint,
                    "StrokePaint" => Input::StrokePaint,
                )?)
            })
            .or_else(|_: BasicParseError<'_>| {
                let ident = CustomIdent::parse(parser)?;
                Ok(Input::FilterOutput(ident))
            })
    }
}

impl Primitive {
    fn resolve(&self) -> ResolvedPrimitive {
        ResolvedPrimitive {
            x: self.x,
            y: self.y,
            width: self.width,
            height: self.height,
            result: self.result.clone(),
        }
    }
}

impl ResolvedPrimitive {
    /// Validates attributes and returns the `BoundsBuilder` for bounds computation.
    #[inline]
    fn get_bounds(&self, ctx: &FilterContext) -> Result<BoundsBuilder, FilterError> {
        // With ObjectBoundingBox, only fractions and percents are allowed.
        if ctx.primitive_units() == CoordUnits::ObjectBoundingBox {
            check_px_or_percent_units(self.x)?;
            check_px_or_percent_units(self.y)?;
            check_px_or_percent_units(self.width)?;
            check_px_or_percent_units(self.height)?;
        }

        let transform = ctx.paffine();
        if !transform.is_invertible() {
            return Err(FilterError::InvalidParameter(
                "transform is not invertible".to_string(),
            ));
        }

        Ok(BoundsBuilder::new(
            self.x,
            self.y,
            self.width,
            self.height,
            transform,
        ))
    }
}

fn check_px_or_percent_units<N: Normalize, V: Validate>(
    length: Option<CssLength<N, V>>,
) -> Result<(), FilterError> {
    match length {
        Some(l) if l.unit == LengthUnit::Px || l.unit == LengthUnit::Percent => Ok(()),
        Some(_) => Err(FilterError::InvalidUnits),
        None => Ok(()),
    }
}

impl Primitive {
    fn parse_standard_attributes(
        &mut self,
        attrs: &Attributes,
    ) -> Result<(Input, Input), ElementError> {
        let mut input_1 = Input::Unspecified;
        let mut input_2 = Input::Unspecified;

        for (attr, value) in attrs.iter() {
            match attr.expanded() {
                expanded_name!("", "x") => self.x = attr.parse(value)?,
                expanded_name!("", "y") => self.y = attr.parse(value)?,
                expanded_name!("", "width") => self.width = attr.parse(value)?,
                expanded_name!("", "height") => self.height = attr.parse(value)?,
                expanded_name!("", "result") => self.result = attr.parse(value)?,
                expanded_name!("", "in") => input_1 = attr.parse(value)?,
                expanded_name!("", "in2") => input_2 = attr.parse(value)?,
                _ => (),
            }
        }

        Ok((input_1, input_2))
    }

    pub fn parse_no_inputs(&mut self, attrs: &Attributes) -> ElementResult {
        let (_, _) = self.parse_standard_attributes(attrs)?;
        Ok(())
    }

    pub fn parse_one_input(&mut self, attrs: &Attributes) -> Result<Input, ElementError> {
        let (input_1, _) = self.parse_standard_attributes(attrs)?;
        Ok(input_1)
    }

    pub fn parse_two_inputs(&mut self, attrs: &Attributes) -> Result<(Input, Input), ElementError> {
        self.parse_standard_attributes(attrs)
    }
}

/// Applies a filter and returns the resulting surface.
pub fn render(
    filter_node: &Node,
    computed_from_node_being_filtered: &ComputedValues,
    source_surface: SharedImageSurface,
    acquired_nodes: &mut AcquiredNodes<'_>,
    draw_ctx: &mut DrawingCtx,
    transform: Transform,
    node_bbox: BoundingBox,
) -> Result<SharedImageSurface, RenderingError> {
    let filter_node = &*filter_node;
    assert!(is_element_of_type!(filter_node, Filter));

    if filter_node.borrow_element().is_in_error() {
        return Ok(source_surface);
    }

    let filter = borrow_element_as!(filter_node, Filter);

    let values = computed_from_node_being_filtered;

    let stroke_paint_source = values
        .stroke()
        .0
        .resolve(acquired_nodes, values.stroke_opacity().0, values.color().0)?
        .to_user_space(&node_bbox, draw_ctx, values);

    let fill_paint_source = values
        .fill()
        .0
        .resolve(acquired_nodes, values.fill_opacity().0, values.color().0)?
        .to_user_space(&node_bbox, draw_ctx, values);

    if let Ok(mut filter_ctx) = FilterContext::new(
        &filter,
        computed_from_node_being_filtered,
        stroke_paint_source,
        fill_paint_source,
        &source_surface,
        draw_ctx,
        transform,
        node_bbox,
    ) {
        let primitives = filter_node
            .children()
            .filter(|c| c.is_element())
            // Skip nodes in error.
            .filter(|c| {
                let in_error = c.borrow_element().is_in_error();

                if in_error {
                    rsvg_log!("(ignoring filter primitive {} because it is in error)", c);
                }

                !in_error
            })
            // Keep only filter primitives (those that implement the Filter trait)
            .filter(|c| c.borrow_element().as_filter_effect().is_some());

        for c in primitives {
            let elt = c.borrow_element();
            let filter = elt.as_filter_effect().unwrap();

            let start = Instant::now();

            if let Err(err) = filter
                .resolve(&c)
                .and_then(|(primitive, params)| {
                    render_primitive(
                        &primitive.resolve(),
                        &params,
                        &filter_ctx,
                        acquired_nodes,
                        draw_ctx,
                    )
                })
                .and_then(|result| filter_ctx.store_result(result))
            {
                rsvg_log!("(filter primitive {} returned an error: {})", c, err);

                // Exit early on Cairo errors. Continue rendering otherwise.
                if let FilterError::CairoError(status) = err {
                    return Err(RenderingError::from(status));
                }
            }

            let elapsed = start.elapsed();
            rsvg_log!(
                "(rendered filter primitive {} in\n    {} seconds)",
                c,
                elapsed.as_secs() as f64 + f64::from(elapsed.subsec_nanos()) / 1e9
            );
        }

        Ok(filter_ctx.into_output()?)
    } else {
        // Ignore errors that happened when creating the FilterContext
        Ok(SharedImageSurface::empty(
            source_surface.width(),
            source_surface.height(),
            SurfaceType::AlphaOnly,
        )?)
    }
}

#[rustfmt::skip]
fn render_primitive(
    primitive: &ResolvedPrimitive,
    params: &PrimitiveParams,
    ctx: &FilterContext,
    acquired_nodes: &mut AcquiredNodes<'_>,
    draw_ctx: &mut DrawingCtx,
) -> Result<FilterResult, FilterError> {
    use PrimitiveParams::*;

    match params {
        Blend(p)             => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        ColorMatrix(p)       => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        ComponentTransfer(p) => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        Composite(p)         => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        ConvolveMatrix(p)    => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        DiffuseLighting(p)   => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        DisplacementMap(p)   => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        Flood(p)             => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        GaussianBlur(p)      => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        Image(p)             => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        Merge(p)             => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        Morphology(p)        => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        Offset(p)            => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        SpecularLighting(p)  => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        Tile(p)              => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        Turbulence(p)        => p.render(primitive, ctx, acquired_nodes, draw_ctx),
    }
}

impl From<ColorInterpolationFilters> for SurfaceType {
    fn from(c: ColorInterpolationFilters) -> Self {
        match c {
            ColorInterpolationFilters::LinearRgb => SurfaceType::LinearRgb,
            _ => SurfaceType::SRgb,
        }
    }
}
<commit_msg>ResolvedPrimitive: now we can assume that the ctx's transform is valid<commit_after>//! Entry point for the CSS filters infrastructure.

use cssparser::{BasicParseError, Parser};
use markup5ever::{expanded_name, local_name, namespace_url, ns};
use std::time::Instant;

use crate::bbox::BoundingBox;
use crate::coord_units::CoordUnits;
use crate::document::AcquiredNodes;
use crate::drawing_ctx::DrawingCtx;
use crate::element::{Draw, ElementResult, SetAttributes};
use crate::error::{ElementError, ParseError, RenderingError};
use crate::length::*;
use crate::node::{Node, NodeBorrow};
use crate::parsers::{CustomIdent, Parse, ParseValue};
use crate::properties::ComputedValues;
use crate::property_defs::ColorInterpolationFilters;
use crate::surface_utils::shared_surface::{SharedImageSurface, SurfaceType};
use crate::transform::Transform;
use crate::xml::Attributes;

mod bounds;
use self::bounds::BoundsBuilder;

pub mod context;
use self::context::{FilterContext, FilterResult};

mod error;
use self::error::FilterError;

/// A filter primitive interface.
pub trait FilterEffect: SetAttributes + Draw {
    fn resolve(&self, node: &Node) -> Result<(Primitive, PrimitiveParams), FilterError>;
}

// Filter Effects do not need to draw themselves
impl<T: FilterEffect> Draw for T {}

pub mod blend;
pub mod color_matrix;
pub mod component_transfer;
pub mod composite;
pub mod convolve_matrix;
pub mod displacement_map;
pub mod flood;
pub mod gaussian_blur;
pub mod image;
pub mod lighting;
pub mod merge;
pub mod morphology;
pub mod offset;
pub mod tile;
pub mod turbulence;

/// Resolved parameters for each filter primitive.
///
/// These gather all the data that a primitive may need during rendering:
/// the `feFoo` element's attributes, any computed values from its properties,
/// and parameters extracted from the element's children (for example,
/// `feMerge` gathers info from its `feMergNode` children).
pub enum PrimitiveParams {
    Blend(blend::Blend),
    ColorMatrix(color_matrix::ColorMatrix),
    ComponentTransfer(component_transfer::ComponentTransfer),
    Composite(composite::Composite),
    ConvolveMatrix(convolve_matrix::ConvolveMatrix),
    DiffuseLighting(lighting::DiffuseLighting),
    DisplacementMap(displacement_map::DisplacementMap),
    Flood(flood::Flood),
    GaussianBlur(gaussian_blur::GaussianBlur),
    Image(image::Image),
    Merge(merge::Merge),
    Morphology(morphology::Morphology),
    Offset(offset::Offset),
    SpecularLighting(lighting::SpecularLighting),
    Tile(tile::Tile),
    Turbulence(turbulence::Turbulence),
}

/// The base filter primitive node containing common properties.
#[derive(Default, Clone)]
pub struct Primitive {
    x: Option<Length<Horizontal>>,
    y: Option<Length<Vertical>>,
    width: Option<ULength<Horizontal>>,
    height: Option<ULength<Vertical>>,
    result: Option<CustomIdent>,
}

pub struct ResolvedPrimitive {
    x: Option<Length<Horizontal>>,
    y: Option<Length<Vertical>>,
    width: Option<ULength<Horizontal>>,
    height: Option<ULength<Vertical>>,
    result: Option<CustomIdent>,
}

/// An enumeration of possible inputs for a filter primitive.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub enum Input {
    Unspecified,
    SourceGraphic,
    SourceAlpha,
    BackgroundImage,
    BackgroundAlpha,
    FillPaint,
    StrokePaint,
    FilterOutput(CustomIdent),
}

enum_default!(Input, Input::Unspecified);

impl Parse for Input {
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Self, ParseError<'i>> {
        parser
            .try_parse(|p| {
                Ok(parse_identifiers!(
                    p,
                    "SourceGraphic" => Input::SourceGraphic,
                    "SourceAlpha" => Input::SourceAlpha,
                    "BackgroundImage" => Input::BackgroundImage,
                    "BackgroundAlpha" => Input::BackgroundAlpha,
                    "FillPaint" => Input::FillPaint,
                    "StrokePaint" => Input::StrokePaint,
                )?)
            })
            .or_else(|_: BasicParseError<'_>| {
                let ident = CustomIdent::parse(parser)?;
                Ok(Input::FilterOutput(ident))
            })
    }
}

impl Primitive {
    fn resolve(&self) -> ResolvedPrimitive {
        ResolvedPrimitive {
            x: self.x,
            y: self.y,
            width: self.width,
            height: self.height,
            result: self.result.clone(),
        }
    }
}

impl ResolvedPrimitive {
    /// Validates attributes and returns the `BoundsBuilder` for bounds computation.
    #[inline]
    fn get_bounds(&self, ctx: &FilterContext) -> Result<BoundsBuilder, FilterError> {
        // With ObjectBoundingBox, only fractions and percents are allowed.
        if ctx.primitive_units() == CoordUnits::ObjectBoundingBox {
            check_px_or_percent_units(self.x)?;
            check_px_or_percent_units(self.y)?;
            check_px_or_percent_units(self.width)?;
            check_px_or_percent_units(self.height)?;
        }

        Ok(BoundsBuilder::new(
            self.x,
            self.y,
            self.width,
            self.height,
            ctx.paffine(),
        ))
    }
}

fn check_px_or_percent_units<N: Normalize, V: Validate>(
    length: Option<CssLength<N, V>>,
) -> Result<(), FilterError> {
    match length {
        Some(l) if l.unit == LengthUnit::Px || l.unit == LengthUnit::Percent => Ok(()),
        Some(_) => Err(FilterError::InvalidUnits),
        None => Ok(()),
    }
}

impl Primitive {
    fn parse_standard_attributes(
        &mut self,
        attrs: &Attributes,
    ) -> Result<(Input, Input), ElementError> {
        let mut input_1 = Input::Unspecified;
        let mut input_2 = Input::Unspecified;

        for (attr, value) in attrs.iter() {
            match attr.expanded() {
                expanded_name!("", "x") => self.x = attr.parse(value)?,
                expanded_name!("", "y") => self.y = attr.parse(value)?,
                expanded_name!("", "width") => self.width = attr.parse(value)?,
                expanded_name!("", "height") => self.height = attr.parse(value)?,
                expanded_name!("", "result") => self.result = attr.parse(value)?,
                expanded_name!("", "in") => input_1 = attr.parse(value)?,
                expanded_name!("", "in2") => input_2 = attr.parse(value)?,
                _ => (),
            }
        }

        Ok((input_1, input_2))
    }

    pub fn parse_no_inputs(&mut self, attrs: &Attributes) -> ElementResult {
        let (_, _) = self.parse_standard_attributes(attrs)?;
        Ok(())
    }

    pub fn parse_one_input(&mut self, attrs: &Attributes) -> Result<Input, ElementError> {
        let (input_1, _) = self.parse_standard_attributes(attrs)?;
        Ok(input_1)
    }

    pub fn parse_two_inputs(&mut self, attrs: &Attributes) -> Result<(Input, Input), ElementError> {
        self.parse_standard_attributes(attrs)
    }
}

/// Applies a filter and returns the resulting surface.
pub fn render(
    filter_node: &Node,
    computed_from_node_being_filtered: &ComputedValues,
    source_surface: SharedImageSurface,
    acquired_nodes: &mut AcquiredNodes<'_>,
    draw_ctx: &mut DrawingCtx,
    transform: Transform,
    node_bbox: BoundingBox,
) -> Result<SharedImageSurface, RenderingError> {
    let filter_node = &*filter_node;
    assert!(is_element_of_type!(filter_node, Filter));

    if filter_node.borrow_element().is_in_error() {
        return Ok(source_surface);
    }

    let filter = borrow_element_as!(filter_node, Filter);

    let values = computed_from_node_being_filtered;

    let stroke_paint_source = values
        .stroke()
        .0
        .resolve(acquired_nodes, values.stroke_opacity().0, values.color().0)?
        .to_user_space(&node_bbox, draw_ctx, values);

    let fill_paint_source = values
        .fill()
        .0
        .resolve(acquired_nodes, values.fill_opacity().0, values.color().0)?
        .to_user_space(&node_bbox, draw_ctx, values);

    if let Ok(mut filter_ctx) = FilterContext::new(
        &filter,
        computed_from_node_being_filtered,
        stroke_paint_source,
        fill_paint_source,
        &source_surface,
        draw_ctx,
        transform,
        node_bbox,
    ) {
        let primitives = filter_node
            .children()
            .filter(|c| c.is_element())
            // Skip nodes in error.
            .filter(|c| {
                let in_error = c.borrow_element().is_in_error();

                if in_error {
                    rsvg_log!("(ignoring filter primitive {} because it is in error)", c);
                }

                !in_error
            })
            // Keep only filter primitives (those that implement the Filter trait)
            .filter(|c| c.borrow_element().as_filter_effect().is_some());

        for c in primitives {
            let elt = c.borrow_element();
            let filter = elt.as_filter_effect().unwrap();

            let start = Instant::now();

            if let Err(err) = filter
                .resolve(&c)
                .and_then(|(primitive, params)| {
                    render_primitive(
                        &primitive.resolve(),
                        &params,
                        &filter_ctx,
                        acquired_nodes,
                        draw_ctx,
                    )
                })
                .and_then(|result| filter_ctx.store_result(result))
            {
                rsvg_log!("(filter primitive {} returned an error: {})", c, err);

                // Exit early on Cairo errors. Continue rendering otherwise.
                if let FilterError::CairoError(status) = err {
                    return Err(RenderingError::from(status));
                }
            }

            let elapsed = start.elapsed();
            rsvg_log!(
                "(rendered filter primitive {} in\n    {} seconds)",
                c,
                elapsed.as_secs() as f64 + f64::from(elapsed.subsec_nanos()) / 1e9
            );
        }

        Ok(filter_ctx.into_output()?)
    } else {
        // Ignore errors that happened when creating the FilterContext
        Ok(SharedImageSurface::empty(
            source_surface.width(),
            source_surface.height(),
            SurfaceType::AlphaOnly,
        )?)
    }
}

#[rustfmt::skip]
fn render_primitive(
    primitive: &ResolvedPrimitive,
    params: &PrimitiveParams,
    ctx: &FilterContext,
    acquired_nodes: &mut AcquiredNodes<'_>,
    draw_ctx: &mut DrawingCtx,
) -> Result<FilterResult, FilterError> {
    use PrimitiveParams::*;

    match params {
        Blend(p)             => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        ColorMatrix(p)       => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        ComponentTransfer(p) => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        Composite(p)         => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        ConvolveMatrix(p)    => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        DiffuseLighting(p)   => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        DisplacementMap(p)   => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        Flood(p)             => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        GaussianBlur(p)      => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        Image(p)             => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        Merge(p)             => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        Morphology(p)        => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        Offset(p)            => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        SpecularLighting(p)  => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        Tile(p)              => p.render(primitive, ctx, acquired_nodes, draw_ctx),
        Turbulence(p)        => p.render(primitive, ctx, acquired_nodes, draw_ctx),
    }
}

impl From<ColorInterpolationFilters> for SurfaceType {
    fn from(c: ColorInterpolationFilters) -> Self {
        match c {
            ColorInterpolationFilters::LinearRgb => SurfaceType::LinearRgb,
            _ => SurfaceType::SRgb,
        }
    }
}
<|endoftext|>


<commit_before>//! OpenGL back-end for Rust-Graphics.

// External crates.
use graphics::BackEnd;
use gl;
use gl::types::{
    GLint,
    GLsizei,
    GLuint,
};
use shader_utils::{
    compile_shader,
    DynamicAttribute,
};

// Local crate.
use Texture;

static VERTEX_SHADER_TRI_LIST_XY_RGBA: &'static str = "
#version 330
in vec4 a_v4Position;
in vec4 a_v4FillColor;

out vec4 v_v4FillColor;

void main()
{
    v_v4FillColor = a_v4FillColor;
    gl_Position = a_v4Position;
}
";

static FRAGMENT_SHADER_TRI_LIST_XY_RGBA: &'static str = "
#version 330
out vec4 out_color;
in vec4 v_v4FillColor;

void main()
{
    out_color = v_v4FillColor;
}
";

static VERTEX_SHADER_TRI_LIST_XY_RGBA_UV: &'static str = "
#version 330
in vec4 a_v4Position;
in vec4 a_v4FillColor;
in vec2 a_v2TexCoord;

uniform sampler2D s_texture;

out vec2 v_v2TexCoord;
out vec4 v_v4FillColor;

void main()
{
    v_v2TexCoord = a_v2TexCoord;
    v_v4FillColor = a_v4FillColor;
    gl_Position = a_v4Position;
}
";

static FRAGMENT_SHADER_TRI_LIST_XY_RGBA_UV: &'static str = "
#version 330
out vec4 out_color;

uniform sampler2D s_texture;

in vec2 v_v2TexCoord;
in vec4 v_v4FillColor;

void main()
{
    out_color = texture(s_texture, v_v2TexCoord) * v_v4FillColor;
}
";

struct TriListXYRGBA {
    vao: GLuint,
    vertex_shader: GLuint,
    fragment_shader: GLuint,
    program: GLuint,
    a_v4Position: DynamicAttribute,
    a_v4FillColor: DynamicAttribute,
}

impl Drop for TriListXYRGBA {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteVertexArrays(1, &self.vao);
        }
        gl::DeleteProgram(self.program);
        gl::DeleteShader(self.vertex_shader);
        gl::DeleteShader(self.fragment_shader);
    }
}

impl TriListXYRGBA {
    fn new() -> TriListXYRGBA {
        let vertex_shader = match compile_shader(
            gl::VERTEX_SHADER,                  // shader type
            VERTEX_SHADER_TRI_LIST_XY_RGBA      // shader source
        ) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };
        let fragment_shader = match compile_shader(
            gl::FRAGMENT_SHADER,                // shader type
            FRAGMENT_SHADER_TRI_LIST_XY_RGBA    // shader source
        ) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };
        let program = gl::CreateProgram();

        gl::AttachShader(program, vertex_shader);
        gl::AttachShader(program, fragment_shader);

        unsafe {
            "out_color".with_c_str(
                |ptr| gl::BindFragDataLocation(program, 0, ptr)
            );
        }

        let mut vao = 0;
        unsafe {
            gl::GenVertexArrays(1, &mut vao);
        }
        gl::LinkProgram(program);
        let a_v4Position = DynamicAttribute::xy(
                program,
                "a_v4Position",
                vao
            ).unwrap();
        let a_v4FillColor = DynamicAttribute::rgba(
                program,
                "a_v4FillColor",
                vao
            ).unwrap();
        TriListXYRGBA {
            vao: vao,
            vertex_shader: vertex_shader,
            fragment_shader: fragment_shader,
            program: program,
            a_v4Position: a_v4Position,
            a_v4FillColor: a_v4FillColor,
        }
    }
}

struct TriListXYRGBAUV {
    vertex_shader: GLuint,
    fragment_shader: GLuint,
    program: GLuint,
    vao: GLuint,
    a_v4Position: DynamicAttribute,
    a_v4FillColor: DynamicAttribute,
    a_v2TexCoord: DynamicAttribute,
}

impl Drop for TriListXYRGBAUV {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteVertexArrays(1, &self.vao);
        }
        gl::DeleteProgram(self.program);
        gl::DeleteShader(self.vertex_shader);
        gl::DeleteShader(self.fragment_shader);
    }
}

impl TriListXYRGBAUV {
    fn new() -> TriListXYRGBAUV {
        let vertex_shader = match compile_shader(
            gl::VERTEX_SHADER,                  // shader type
            VERTEX_SHADER_TRI_LIST_XY_RGBA_UV   // shader type
        ) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };
        let fragment_shader = match compile_shader(
            gl::FRAGMENT_SHADER,                // shader type
            FRAGMENT_SHADER_TRI_LIST_XY_RGBA_UV // shader source
        ) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };

        let program = gl::CreateProgram();
        gl::AttachShader(program, vertex_shader);
        gl::AttachShader(program, fragment_shader);

        unsafe {
            "out_color".with_c_str(
                |ptr| gl::BindFragDataLocation(program, 0, ptr)
            );
        }

        let mut vao = 0;
        unsafe {
            gl::GenVertexArrays(1, &mut vao);
        }
        gl::LinkProgram(program);
        let a_v4Position = DynamicAttribute::xy(
                program,
                "a_v4Position",
                vao
            ).unwrap();
        let a_v4FillColor = DynamicAttribute::rgba(
                program,
                "a_v4FillColor",
                vao
            ).unwrap();
        let a_v2TexCoord = DynamicAttribute::uv(
                program,
                "a_v2TexCoord",
                vao
            ).unwrap();
        TriListXYRGBAUV {
            vao: vao,
            vertex_shader: vertex_shader,
            fragment_shader: fragment_shader,
            program: program,
            a_v4Position: a_v4Position,
            a_v4FillColor: a_v4FillColor,
            a_v2TexCoord: a_v2TexCoord,
        }
    }
}

/// Contains OpenGL data.
pub struct Gl {
    tri_list_xy_rgba: TriListXYRGBA,
    tri_list_xy_rgba_uv: TriListXYRGBAUV,
    // Keeps track of the current shader program.
    current_program: Option<GLuint>,
}

impl<'a> Gl {
    /// Creates a new OpenGl back-end.
    pub fn new() -> Gl {
        // Load the vertices, color and texture coord buffers.
        Gl {
            tri_list_xy_rgba: TriListXYRGBA::new(),
            tri_list_xy_rgba_uv: TriListXYRGBAUV::new(),
            current_program: None,
       }
    }

    /// Sets viewport with normalized coordinates and center as origin.
    pub fn viewport(
        &mut self,
        x: i32,
        y: i32,
        w: i32,
        h: i32
    ) {
        gl::Viewport(x as GLint, y as GLint, w as GLsizei, h as GLsizei);
    }

    /// Sets the current program only if the program is not in use.
    pub fn use_program(&mut self, program: GLuint) {
        match self.current_program {
            None => {},
            Some(current_program) => {
                if program == current_program { return; }
            },
        }

        gl::UseProgram(program);
        self.current_program = Some(program);
    }
}

impl BackEnd<Texture> for Gl {
    fn supports_clear_rgba(&self) -> bool { true }

    fn clear_rgba(&mut self, r: f32, g: f32, b: f32, a: f32) {
        gl::ClearColor(r, g, b, a);
        gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
    }

    fn enable_alpha_blend(&mut self) {
        gl::Enable(gl::BLEND);
        gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
    }

    fn disable_alpha_blend(&mut self) {
        gl::Disable(gl::BLEND);
    }

    fn supports_single_texture(&self) -> bool { true }

    fn enable_single_texture(&mut self, texture: &Texture) {
        let texture = texture.get_id();
        gl::BindTexture(gl::TEXTURE_2D, texture);
    }

    fn disable_single_texture(&mut self) {}

    // Assume all textures has alpha channel for now.
    fn has_texture_alpha(&self, _texture: &Texture) -> bool { true }

    fn supports_tri_list_xy_f32_rgba_f32(&self) -> bool { true }

    fn tri_list_xy_f32_rgba_f32(
        &mut self,
        vertices: &[f32],
        colors: &[f32]
    ) {
        {
            // Set shader program.
            let shader_program = self.tri_list_xy_rgba.program;
            self.use_program(shader_program);
        }
        let ref mut shader = self.tri_list_xy_rgba;
        gl::BindVertexArray(shader.vao);

        // xy makes two floats.
        let size_vertices: i32 = 2;

        unsafe {
            shader.a_v4Position.set(vertices);
            shader.a_v4FillColor.set(colors);
        }

        // Render triangles whether they are facing
        // clockwise or counter clockwise.
        gl::CullFace(gl::FRONT_AND_BACK);

        let items: i32 = vertices.len() as i32 / size_vertices;
        gl::DrawArrays(gl::TRIANGLES, 0, items);

        gl::BindVertexArray(0);
    }

    fn supports_tri_list_xy_f32_rgba_f32_uv_f32(&self) -> bool { true }

    fn tri_list_xy_f32_rgba_f32_uv_f32(
        &mut self,
        vertices: &[f32],
        colors: &[f32],
        texture_coords: &[f32]
    ) {
        {
            // Set shader program.
            let shader_program = self.tri_list_xy_rgba_uv.program;
            self.use_program(shader_program);
        }
        let ref mut shader = self.tri_list_xy_rgba_uv;
        gl::BindVertexArray(shader.vao);

        let size_vertices: i32 = 2;

        unsafe {
            shader.a_v4Position.set(vertices);
            shader.a_v4FillColor.set(colors);
            shader.a_v2TexCoord.set(texture_coords);
        }

        // Render triangles whether they are facing
        // clockwise or counter clockwise.
        gl::CullFace(gl::FRONT_AND_BACK);

        let items: i32 = vertices.len() as i32 / size_vertices;
        gl::DrawArrays(gl::TRIANGLES, 0, items);

        gl::BindVertexArray(0);
    }
}

<commit_msg>Add a way to clear a shader<commit_after>//! OpenGL back-end for Rust-Graphics.

// External crates.
use graphics::BackEnd;
use gl;
use gl::types::{
    GLint,
    GLsizei,
    GLuint,
};
use shader_utils::{
    compile_shader,
    DynamicAttribute,
};

// Local crate.
use Texture;

static VERTEX_SHADER_TRI_LIST_XY_RGBA: &'static str = "
#version 330
in vec4 a_v4Position;
in vec4 a_v4FillColor;

out vec4 v_v4FillColor;

void main()
{
    v_v4FillColor = a_v4FillColor;
    gl_Position = a_v4Position;
}
";

static FRAGMENT_SHADER_TRI_LIST_XY_RGBA: &'static str = "
#version 330
out vec4 out_color;
in vec4 v_v4FillColor;

void main()
{
    out_color = v_v4FillColor;
}
";

static VERTEX_SHADER_TRI_LIST_XY_RGBA_UV: &'static str = "
#version 330
in vec4 a_v4Position;
in vec4 a_v4FillColor;
in vec2 a_v2TexCoord;

uniform sampler2D s_texture;

out vec2 v_v2TexCoord;
out vec4 v_v4FillColor;

void main()
{
    v_v2TexCoord = a_v2TexCoord;
    v_v4FillColor = a_v4FillColor;
    gl_Position = a_v4Position;
}
";

static FRAGMENT_SHADER_TRI_LIST_XY_RGBA_UV: &'static str = "
#version 330
out vec4 out_color;

uniform sampler2D s_texture;

in vec2 v_v2TexCoord;
in vec4 v_v4FillColor;

void main()
{
    out_color = texture(s_texture, v_v2TexCoord) * v_v4FillColor;
}
";

struct TriListXYRGBA {
    vao: GLuint,
    vertex_shader: GLuint,
    fragment_shader: GLuint,
    program: GLuint,
    a_v4Position: DynamicAttribute,
    a_v4FillColor: DynamicAttribute,
}

impl Drop for TriListXYRGBA {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteVertexArrays(1, &self.vao);
        }
        gl::DeleteProgram(self.program);
        gl::DeleteShader(self.vertex_shader);
        gl::DeleteShader(self.fragment_shader);
    }
}

impl TriListXYRGBA {
    fn new() -> TriListXYRGBA {
        let vertex_shader = match compile_shader(
            gl::VERTEX_SHADER,                  // shader type
            VERTEX_SHADER_TRI_LIST_XY_RGBA      // shader source
        ) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };
        let fragment_shader = match compile_shader(
            gl::FRAGMENT_SHADER,                // shader type
            FRAGMENT_SHADER_TRI_LIST_XY_RGBA    // shader source
        ) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };
        let program = gl::CreateProgram();

        gl::AttachShader(program, vertex_shader);
        gl::AttachShader(program, fragment_shader);

        unsafe {
            "out_color".with_c_str(
                |ptr| gl::BindFragDataLocation(program, 0, ptr)
            );
        }

        let mut vao = 0;
        unsafe {
            gl::GenVertexArrays(1, &mut vao);
        }
        gl::LinkProgram(program);
        let a_v4Position = DynamicAttribute::xy(
                program,
                "a_v4Position",
                vao
            ).unwrap();
        let a_v4FillColor = DynamicAttribute::rgba(
                program,
                "a_v4FillColor",
                vao
            ).unwrap();
        TriListXYRGBA {
            vao: vao,
            vertex_shader: vertex_shader,
            fragment_shader: fragment_shader,
            program: program,
            a_v4Position: a_v4Position,
            a_v4FillColor: a_v4FillColor,
        }
    }
}

struct TriListXYRGBAUV {
    vertex_shader: GLuint,
    fragment_shader: GLuint,
    program: GLuint,
    vao: GLuint,
    a_v4Position: DynamicAttribute,
    a_v4FillColor: DynamicAttribute,
    a_v2TexCoord: DynamicAttribute,
}

impl Drop for TriListXYRGBAUV {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteVertexArrays(1, &self.vao);
        }
        gl::DeleteProgram(self.program);
        gl::DeleteShader(self.vertex_shader);
        gl::DeleteShader(self.fragment_shader);
    }
}

impl TriListXYRGBAUV {
    fn new() -> TriListXYRGBAUV {
        let vertex_shader = match compile_shader(
            gl::VERTEX_SHADER,                  // shader type
            VERTEX_SHADER_TRI_LIST_XY_RGBA_UV   // shader type
        ) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };
        let fragment_shader = match compile_shader(
            gl::FRAGMENT_SHADER,                // shader type
            FRAGMENT_SHADER_TRI_LIST_XY_RGBA_UV // shader source
        ) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };

        let program = gl::CreateProgram();
        gl::AttachShader(program, vertex_shader);
        gl::AttachShader(program, fragment_shader);

        unsafe {
            "out_color".with_c_str(
                |ptr| gl::BindFragDataLocation(program, 0, ptr)
            );
        }

        let mut vao = 0;
        unsafe {
            gl::GenVertexArrays(1, &mut vao);
        }
        gl::LinkProgram(program);
        let a_v4Position = DynamicAttribute::xy(
                program,
                "a_v4Position",
                vao
            ).unwrap();
        let a_v4FillColor = DynamicAttribute::rgba(
                program,
                "a_v4FillColor",
                vao
            ).unwrap();
        let a_v2TexCoord = DynamicAttribute::uv(
                program,
                "a_v2TexCoord",
                vao
            ).unwrap();
        TriListXYRGBAUV {
            vao: vao,
            vertex_shader: vertex_shader,
            fragment_shader: fragment_shader,
            program: program,
            a_v4Position: a_v4Position,
            a_v4FillColor: a_v4FillColor,
            a_v2TexCoord: a_v2TexCoord,
        }
    }
}

/// Contains OpenGL data.
pub struct Gl {
    tri_list_xy_rgba: TriListXYRGBA,
    tri_list_xy_rgba_uv: TriListXYRGBAUV,
    // Keeps track of the current shader program.
    current_program: Option<GLuint>,
}

impl<'a> Gl {
    /// Creates a new OpenGl back-end.
    pub fn new() -> Gl {
        // Load the vertices, color and texture coord buffers.
        Gl {
            tri_list_xy_rgba: TriListXYRGBA::new(),
            tri_list_xy_rgba_uv: TriListXYRGBAUV::new(),
            current_program: None,
       }
    }

    /// Sets viewport with normalized coordinates and center as origin.
    pub fn viewport(
        &mut self,
        x: i32,
        y: i32,
        w: i32,
        h: i32
    ) {
        gl::Viewport(x as GLint, y as GLint, w as GLsizei, h as GLsizei);
    }

    /// Sets the current program only if the program is not in use.
    pub fn use_program(&mut self, program: GLuint) {
        match self.current_program {
            None => {},
            Some(current_program) => {
                if program == current_program { return; }
            },
        }

        gl::UseProgram(program);
        self.current_program = Some(program);
    }

    /// Unset the current program.
    pub fn clear_shader(&mut self) {
        self.current_program = None
    }
}

impl BackEnd<Texture> for Gl {
    fn supports_clear_rgba(&self) -> bool { true }

    fn clear_rgba(&mut self, r: f32, g: f32, b: f32, a: f32) {
        gl::ClearColor(r, g, b, a);
        gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
    }

    fn enable_alpha_blend(&mut self) {
        gl::Enable(gl::BLEND);
        gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
    }

    fn disable_alpha_blend(&mut self) {
        gl::Disable(gl::BLEND);
    }

    fn supports_single_texture(&self) -> bool { true }

    fn enable_single_texture(&mut self, texture: &Texture) {
        let texture = texture.get_id();
        gl::BindTexture(gl::TEXTURE_2D, texture);
    }

    fn disable_single_texture(&mut self) {}

    // Assume all textures has alpha channel for now.
    fn has_texture_alpha(&self, _texture: &Texture) -> bool { true }

    fn supports_tri_list_xy_f32_rgba_f32(&self) -> bool { true }

    fn tri_list_xy_f32_rgba_f32(
        &mut self,
        vertices: &[f32],
        colors: &[f32]
    ) {
        {
            // Set shader program.
            let shader_program = self.tri_list_xy_rgba.program;
            self.use_program(shader_program);
        }
        let ref mut shader = self.tri_list_xy_rgba;
        gl::BindVertexArray(shader.vao);

        // xy makes two floats.
        let size_vertices: i32 = 2;

        unsafe {
            shader.a_v4Position.set(vertices);
            shader.a_v4FillColor.set(colors);
        }

        // Render triangles whether they are facing
        // clockwise or counter clockwise.
        gl::CullFace(gl::FRONT_AND_BACK);

        let items: i32 = vertices.len() as i32 / size_vertices;
        gl::DrawArrays(gl::TRIANGLES, 0, items);

        gl::BindVertexArray(0);
    }

    fn supports_tri_list_xy_f32_rgba_f32_uv_f32(&self) -> bool { true }

    fn tri_list_xy_f32_rgba_f32_uv_f32(
        &mut self,
        vertices: &[f32],
        colors: &[f32],
        texture_coords: &[f32]
    ) {
        {
            // Set shader program.
            let shader_program = self.tri_list_xy_rgba_uv.program;
            self.use_program(shader_program);
        }
        let ref mut shader = self.tri_list_xy_rgba_uv;
        gl::BindVertexArray(shader.vao);

        let size_vertices: i32 = 2;

        unsafe {
            shader.a_v4Position.set(vertices);
            shader.a_v4FillColor.set(colors);
            shader.a_v2TexCoord.set(texture_coords);
        }

        // Render triangles whether they are facing
        // clockwise or counter clockwise.
        gl::CullFace(gl::FRONT_AND_BACK);

        let items: i32 = vertices.len() as i32 / size_vertices;
        gl::DrawArrays(gl::TRIANGLES, 0, items);

        gl::BindVertexArray(0);
    }
}

<|endoftext|>


<commit_before>use std::collections::HashMap;
use graphics::character::{CharacterCache, Character};
use graphics::types::FontSize;
use graphics::ImageSize;
use glium::{Texture2d, Texture, Display};
use image::{Luma, ImageBuffer};
use freetype::{self, Face};

pub struct GlyphTexture(pub Texture2d);

impl ImageSize for GlyphTexture {
    fn get_size(&self) -> (u32, u32) {
        let GlyphTexture(ref tex) = *self;
        (tex.get_width(), tex.get_height().unwrap())
    }
}

fn load_character(face: &Face, display: &Display, font_size: FontSize, character: char)
    -> Character<GlyphTexture>
{
    face.set_pixel_sizes(0, font_size).unwrap();
    face.load_char(character as usize, freetype::face::DEFAULT).unwrap();
    let glyph = face.glyph().get_glyph().unwrap();
    let bitmap_glyph = glyph.to_bitmap(freetype::render_mode::RenderMode::Normal, None).unwrap();
    let bitmap = bitmap_glyph.bitmap();
    let texture = Texture2d::new(
        display,
        ImageBuffer::<Luma<u8>, _>::from_raw(
            bitmap.width() as u32, bitmap.rows() as u32,
            bitmap.buffer().iter().map(|&pix| pix).collect::<Vec<_>>()
        ).expect("failed to create glyph texture")
    );
    let glyph_size = glyph.advance();
    Character {
        offset: [
            bitmap_glyph.left() as f64,
            bitmap_glyph.top() as f64
        ],
        size: [
            (glyph_size.x >> 16) as f64,
            (glyph_size.y >> 16) as f64
        ],
        texture: GlyphTexture(texture),
    }
}

pub struct GlyphCache {
    face: Face,
    data: HashMap<FontSize, HashMap<char, Character<GlyphTexture>>>,
    display: Display,
}

impl CharacterCache for GlyphCache {
    type Texture = GlyphTexture;

    fn character<'a>(&'a mut self, font_size: FontSize, character: char)
        -> &'a Character<GlyphTexture>
    {
        use std::collections::hash_map::Entry::{Vacant, Occupied};
        let size_cache: &'a mut HashMap<char, _> = match self.data.entry(font_size) {
            Vacant(entry) => entry.insert(HashMap::new()),
            Occupied(entry) => entry.into_mut(),
        };
        match size_cache.entry(character) {
            Vacant(entry) => entry.insert(load_character(&self.face, &self.display, font_size, character)),
            Occupied(entry) => entry.into_mut(),
        }
    }
}
<commit_msg>Upgrade to latest freetype<commit_after>use std::collections::HashMap;
use graphics::character::{CharacterCache, Character};
use graphics::types::FontSize;
use graphics::ImageSize;
use glium::{Texture2d, Texture, Display};
use image::{Luma, ImageBuffer};
use freetype::{self, Face};

pub struct GlyphTexture(pub Texture2d);

impl ImageSize for GlyphTexture {
    fn get_size(&self) -> (u32, u32) {
        let GlyphTexture(ref tex) = *self;
        (tex.get_width(), tex.get_height().unwrap())
    }
}

fn load_character(face: &Face, display: &Display, font_size: FontSize, character: char)
    -> Character<GlyphTexture>
{
    face.set_pixel_sizes(0, font_size).unwrap();
    face.load_char(character as usize, freetype::face::DEFAULT).unwrap();
    let glyph = face.glyph().get_glyph().unwrap();
    let bitmap_glyph = glyph.to_bitmap(freetype::render_mode::RenderMode::Normal, None).unwrap();
    let bitmap = bitmap_glyph.bitmap();
    let texture = Texture2d::new(
        display,
        ImageBuffer::<Luma<u8>, _>::from_raw(
            bitmap.width() as u32, bitmap.rows() as u32,
            bitmap.buffer().iter().map(|&pix| pix).collect::<Vec<_>>()
        ).expect("failed to create glyph texture")
    );
    let glyph_size = glyph.advance();
    Character {
        offset: [
            bitmap_glyph.left() as f64,
            bitmap_glyph.top() as f64
        ],
        size: [
            (glyph_size.x >> 16) as f64,
            (glyph_size.y >> 16) as f64
        ],
        texture: GlyphTexture(texture),
    }
}

pub struct GlyphCache<'a> {
    face: Face<'a>,
    data: HashMap<FontSize, HashMap<char, Character<GlyphTexture>>>,
    display: Display,
}

impl<'b> CharacterCache for GlyphCache<'b> {
    type Texture = GlyphTexture;

    fn character<'a>(&'a mut self, font_size: FontSize, character: char)
        -> &'a Character<GlyphTexture>
    {
        use std::collections::hash_map::Entry::{Vacant, Occupied};
        let size_cache: &'a mut HashMap<char, _> = match self.data.entry(font_size) {
            Vacant(entry) => entry.insert(HashMap::new()),
            Occupied(entry) => entry.into_mut(),
        };
        match size_cache.entry(character) {
            Vacant(entry) => entry.insert(load_character(&self.face, &self.display, font_size, character)),
            Occupied(entry) => entry.into_mut(),
        }
    }
}
<|endoftext|>