<commit_before>use ::subtitles::* ;

pub struct EditorState {
    pub current_sentence : u16,
    pub current_syllable : u16,
    /// if this is `Some(t)`, key is being held since
    /// `t`, otherwise it isn't being held.
    pub start_frame_key_1 : Option<u32>,
    pub start_frame_key_2 : Option<u32>
}

impl EditorState {
    pub fn new() -> EditorState {
        EditorState {
            current_sentence:0,
            current_syllable:0,
            start_frame_key_1:None,
            start_frame_key_2:None,
        }
    }

    pub fn holding(&self) -> bool {
        self.start_frame_key_1.is_some() || self.start_frame_key_2.is_some()
    }

    pub fn get_sentence<'a>(&'a self,subs:&'a Subtitles) -> Option<&Sentence> {
       subs.sentences.get(self.current_sentence as usize)
    }

    pub fn get_syllable<'a>(&'a self,subs:&'a Subtitles) -> Option<&Syllable> {
        if let Some(sentence) = self.get_sentence(subs) {
            sentence.syllables.get(self.current_syllable as usize)
        } else {
            None
        }
    }

    pub fn get_sentence_mut<'a>(&'a self,subs:&'a mut Subtitles) -> Option<&mut Sentence> {
       subs.sentences.get_mut(self.current_sentence as usize)
    }

    pub fn get_syllable_mut<'a>(&'a self,subs:&'a mut Subtitles) -> Option<&mut Syllable> {
        if let Some(sentence) = self.get_sentence_mut(subs) {
            sentence.syllables.get_mut(self.current_syllable as usize)
        } else {
            None
        }
    }

    fn reset(&mut self) {
        self.current_sentence = 0 ;
        self.current_syllable = 0 ;
    }

    pub fn prev_sentence(&mut self,subs:&Subtitles) {
        if ( self.current_sentence <= 1 ) {
            self.current_sentence = 0 ;
        } else {
            self.current_sentence -= 1 ;
        }
        self.current_syllable = 0 ;
    }

    pub fn next_sentence(&mut self,subs:&Subtitles) {
        if subs.sentences.len() > self.current_sentence as usize + 1 {
            self.current_syllable = 0 ;
            self.current_sentence += 1 ;
        } // Otherwise do nothing (already at max)
    }

    pub fn prev_syllable(&mut self,subs:&Subtitles) {
        if self.get_sentence(subs).is_some() {
            if self.current_syllable == 0 {
                self.prev_sentence(subs);
                self.current_syllable =
                    subs.sentences[self.current_sentence as usize].syllables.len() as u16 - 1;
            } else {
                self.current_syllable -= 1 ;
            }
        } else {
            self.reset();
        }
    }

    pub fn next_syllable(&mut self,subs:&Subtitles) {
        let sentence_len_opt : Option<usize> = self.get_sentence(subs).map(|s| s.syllables.len());
        if let Some(sentence_len) = sentence_len_opt {
            if sentence_len == self.current_syllable as usize + 1 {
                self.next_sentence(subs);
            } else {
                self.current_syllable += 1 ;
            }
        } else {
            self.reset();
        }
    }

    pub fn start_timing_syllable(&mut self,subs:&mut Subtitles,frame:u32,key:u8) {
        if key == 0 {
            if let Some(_) = self.start_frame_key_2 {
                self.end_timing_syllable(subs,frame,1);
            };
            self.start_frame_key_1 = Some(frame);
        } else {
            if let Some(_) = self.start_frame_key_1 {
                self.end_timing_syllable(subs,frame,0);
            };
            self.start_frame_key_2 = Some(frame);
        };
    }

    pub fn end_timing_syllable(&mut self,subs:&mut Subtitles,frame:u32,key:u8) {
        let b : bool = if let Some(syllable) = self.get_syllable_mut(subs) {
            if key == 0 {
                if let Some(begin_frame) = self.start_frame_key_1 {
                    syllable.begin = begin_frame ;
                    syllable.end = Some(frame) ;
                    true
                } else {
                    false
                }
            } else {
                if let Some(begin_frame) = self.start_frame_key_2 {
                    syllable.begin = begin_frame ;
                    syllable.end = Some(frame) ;
                    true
                } else {
                    false
                }
            }
        } else {
            false
        };
        if b {
            if key == 0 {
                self.start_frame_key_1 = None;
            } else {
                self.start_frame_key_2 = None;
            }
            self.next_syllable(subs);
        };
    }
}
<commit_msg>Fix "unused variable" warning.<commit_after>use ::subtitles::* ;

pub struct EditorState {
    pub current_sentence : u16,
    pub current_syllable : u16,
    /// if this is `Some(t)`, key is being held since
    /// `t`, otherwise it isn't being held.
    pub start_frame_key_1 : Option<u32>,
    pub start_frame_key_2 : Option<u32>
}

impl EditorState {
    pub fn new() -> EditorState {
        EditorState {
            current_sentence:0,
            current_syllable:0,
            start_frame_key_1:None,
            start_frame_key_2:None,
        }
    }

    pub fn holding(&self) -> bool {
        self.start_frame_key_1.is_some() || self.start_frame_key_2.is_some()
    }

    pub fn get_sentence<'a>(&'a self,subs:&'a Subtitles) -> Option<&Sentence> {
       subs.sentences.get(self.current_sentence as usize)
    }

    pub fn get_syllable<'a>(&'a self,subs:&'a Subtitles) -> Option<&Syllable> {
        if let Some(sentence) = self.get_sentence(subs) {
            sentence.syllables.get(self.current_syllable as usize)
        } else {
            None
        }
    }

    pub fn get_sentence_mut<'a>(&'a self,subs:&'a mut Subtitles) -> Option<&mut Sentence> {
       subs.sentences.get_mut(self.current_sentence as usize)
    }

    pub fn get_syllable_mut<'a>(&'a self,subs:&'a mut Subtitles) -> Option<&mut Syllable> {
        if let Some(sentence) = self.get_sentence_mut(subs) {
            sentence.syllables.get_mut(self.current_syllable as usize)
        } else {
            None
        }
    }

    fn reset(&mut self) {
        self.current_sentence = 0 ;
        self.current_syllable = 0 ;
    }

    pub fn prev_sentence(&mut self, _subs:&Subtitles) {
        if ( self.current_sentence <= 1 ) {
            self.current_sentence = 0 ;
        } else {
            self.current_sentence -= 1 ;
        }
        self.current_syllable = 0 ;
    }

    pub fn next_sentence(&mut self,subs:&Subtitles) {
        if subs.sentences.len() > self.current_sentence as usize + 1 {
            self.current_syllable = 0 ;
            self.current_sentence += 1 ;
        } // Otherwise do nothing (already at max)
    }

    pub fn prev_syllable(&mut self,subs:&Subtitles) {
        if self.get_sentence(subs).is_some() {
            if self.current_syllable == 0 {
                self.prev_sentence(subs);
                self.current_syllable =
                    subs.sentences[self.current_sentence as usize].syllables.len() as u16 - 1;
            } else {
                self.current_syllable -= 1 ;
            }
        } else {
            self.reset();
        }
    }

    pub fn next_syllable(&mut self,subs:&Subtitles) {
        let sentence_len_opt : Option<usize> = self.get_sentence(subs).map(|s| s.syllables.len());
        if let Some(sentence_len) = sentence_len_opt {
            if sentence_len == self.current_syllable as usize + 1 {
                self.next_sentence(subs);
            } else {
                self.current_syllable += 1 ;
            }
        } else {
            self.reset();
        }
    }

    pub fn start_timing_syllable(&mut self,subs:&mut Subtitles,frame:u32,key:u8) {
        if key == 0 {
            if let Some(_) = self.start_frame_key_2 {
                self.end_timing_syllable(subs,frame,1);
            };
            self.start_frame_key_1 = Some(frame);
        } else {
            if let Some(_) = self.start_frame_key_1 {
                self.end_timing_syllable(subs,frame,0);
            };
            self.start_frame_key_2 = Some(frame);
        };
    }

    pub fn end_timing_syllable(&mut self,subs:&mut Subtitles,frame:u32,key:u8) {
        let b : bool = if let Some(syllable) = self.get_syllable_mut(subs) {
            if key == 0 {
                if let Some(begin_frame) = self.start_frame_key_1 {
                    syllable.begin = begin_frame ;
                    syllable.end = Some(frame) ;
                    true
                } else {
                    false
                }
            } else {
                if let Some(begin_frame) = self.start_frame_key_2 {
                    syllable.begin = begin_frame ;
                    syllable.end = Some(frame) ;
                    true
                } else {
                    false
                }
            }
        } else {
            false
        };
        if b {
            if key == 0 {
                self.start_frame_key_1 = None;
            } else {
                self.start_frame_key_2 = None;
            }
            self.next_syllable(subs);
        };
    }
}
<|endoftext|>


<commit_before>use { Color, InnerWindow, Window, List, Entry, Label };
use traits::{ Place, Text, Click };

use std::{fs, io};
use std::cell::RefCell;
use std::cmp::Ordering;
use std::ops::Deref;
use std::path::{Path, PathBuf};
use std::rc::Rc;

#[derive(Clone, Debug, Eq, PartialEq)]
struct FolderItem {
    path: PathBuf,
    name: String,
    dir: bool,
}

impl Ord for FolderItem {
    fn cmp(&self, other: &Self) -> Ordering {
        if self.dir && ! other.dir {
            Ordering::Less
        } else if ! self.dir && other.dir {
            Ordering::Greater
        } else {
            self.name.cmp(&other.name)
        }
    }
}

impl PartialOrd for FolderItem {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl FolderItem {
    fn scan<P: AsRef<Path>>(path: P) -> io::Result<Vec<Result<Self, String>>> {
        let canon = path.as_ref().canonicalize()?;

        let mut items = vec![];

        if let Some(parent) = canon.parent() {
            items.push(Ok(FolderItem {
                path: parent.to_owned(),
                name: "..".to_string(),
                dir: true,
            }));
        }

        for entry_res in fs::read_dir(&canon)? {
            let item = match entry_res {
                Ok(entry) => match entry.file_name().into_string() {
                    Ok(name) => match entry.file_type() {
                        Ok(file_type) => Ok(FolderItem {
                            path: entry.path(),
                            name: name,
                            dir: file_type.is_dir(),
                        }),
                        Err(err) => Err(format!("{}", err))
                    },
                    Err(os_str) => Err(format!("Invalid filename: {:?}", os_str))
                },
                Err(err) => Err(format!("{}", err))
            };

            items.push(item);
        }

        items.sort();

        Ok(items)
    }
}

pub struct FileDialog {
    pub title: String,
    pub path: PathBuf,
    pub hidden: bool,
}

impl FileDialog {
    pub fn new() -> Self {
        FileDialog {
            title: "File Dialog".to_string(),
            path: PathBuf::from("."),
            hidden: false,
        }
    }

    pub fn exec(&self) -> Option<PathBuf> {
        let path_opt = Rc::new(RefCell::new(
            Some(self.path.clone())
        ));

        let w = 644;
        let h = 484;

        let mut orb_window = Some(InnerWindow::new(-1, -1, w, h, &self.title).unwrap());

        loop {
            let path = match path_opt.borrow_mut().take() {
                Some(path) => if ! path.is_dir() {
                    return Some(path);
                } else {
                    path
                },
                None => return None
            };

            let mut window = Box::new(Window::from_inner(orb_window.take().unwrap()));

            let list = List::new();
            list.position(2, 2).size(w - 4, h - 4);

            match FolderItem::scan(&path) {
                Ok(items) => for item_res in items {
                    match item_res {
                        Ok(item) => if self.hidden || ! item.name.starts_with(".") || item.name == ".." {
                            let mut name = item.name.clone();
                            if item.dir {
                                name.push('/');
                            }

                            let entry = Entry::new(24);

                            let label = Label::new();
                            label.position(2, 2).size(w - 8, 20).text_offset(2, 2);
                            label.bg.set(Color::rgb(255, 255, 255));
                            label.text(name);
                            entry.add(&label);

                            let window = window.deref() as *const Window;
                            let path_opt = path_opt.clone();
                            entry.on_click(move |_, _| {
                                *path_opt.borrow_mut() = Some(item.path.clone());
                                unsafe { (*window).close(); }
                            });

                            list.push(&entry);
                        },
                        Err(err) => {
                            let entry = Entry::new(24);

                            let label = Label::new();
                            label.position(2, 2).size(w - 8, 20).text_offset(2, 2);
                            label.bg.set(Color::rgb(242, 222, 222));
                            label.text(err);
                            entry.add(&label);

                            list.push(&entry);
                        }
                    }
                },
                Err(err) => {
                    let entry = Entry::new(24);

                    let label = Label::new();
                    label.position(2, 2).size(w - 8, 20).text_offset(2, 2);
                    label.bg.set(Color::rgb(242, 222, 222));
                    label.text(format!("{}", err));
                    entry.add(&label);

                    list.push(&entry);
                }
            }

            window.add(&list);

            window.exec();

            orb_window = Some(window.into_inner());
        }
    }
}
<commit_msg>Do not set label background<commit_after>use { InnerWindow, Window, List, Entry, Label };
use traits::{ Place, Text, Click };

use std::{fs, io};
use std::cell::RefCell;
use std::cmp::Ordering;
use std::ops::Deref;
use std::path::{Path, PathBuf};
use std::rc::Rc;

#[derive(Clone, Debug, Eq, PartialEq)]
struct FolderItem {
    path: PathBuf,
    name: String,
    dir: bool,
}

impl Ord for FolderItem {
    fn cmp(&self, other: &Self) -> Ordering {
        if self.dir && ! other.dir {
            Ordering::Less
        } else if ! self.dir && other.dir {
            Ordering::Greater
        } else {
            self.name.cmp(&other.name)
        }
    }
}

impl PartialOrd for FolderItem {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl FolderItem {
    fn scan<P: AsRef<Path>>(path: P) -> io::Result<Vec<Result<Self, String>>> {
        let canon = path.as_ref().canonicalize()?;

        let mut items = vec![];

        if let Some(parent) = canon.parent() {
            items.push(Ok(FolderItem {
                path: parent.to_owned(),
                name: "..".to_string(),
                dir: true,
            }));
        }

        for entry_res in fs::read_dir(&canon)? {
            let item = match entry_res {
                Ok(entry) => match entry.file_name().into_string() {
                    Ok(name) => match entry.file_type() {
                        Ok(file_type) => Ok(FolderItem {
                            path: entry.path(),
                            name: name,
                            dir: file_type.is_dir(),
                        }),
                        Err(err) => Err(format!("{}", err))
                    },
                    Err(os_str) => Err(format!("Invalid filename: {:?}", os_str))
                },
                Err(err) => Err(format!("{}", err))
            };

            items.push(item);
        }

        items.sort();

        Ok(items)
    }
}

pub struct FileDialog {
    pub title: String,
    pub path: PathBuf,
    pub hidden: bool,
}

impl FileDialog {
    pub fn new() -> Self {
        FileDialog {
            title: "File Dialog".to_string(),
            path: PathBuf::from("."),
            hidden: false,
        }
    }

    pub fn exec(&self) -> Option<PathBuf> {
        let path_opt = Rc::new(RefCell::new(
            Some(self.path.clone())
        ));

        let w = 644;
        let h = 484;

        let mut orb_window = Some(InnerWindow::new(-1, -1, w, h, &self.title).unwrap());

        loop {
            let path = match path_opt.borrow_mut().take() {
                Some(path) => if ! path.is_dir() {
                    return Some(path);
                } else {
                    path
                },
                None => return None
            };

            let mut window = Box::new(Window::from_inner(orb_window.take().unwrap()));

            let list = List::new();
            list.position(2, 2).size(w - 4, h - 4);

            match FolderItem::scan(&path) {
                Ok(items) => for item_res in items {
                    match item_res {
                        Ok(item) => if self.hidden || ! item.name.starts_with(".") || item.name == ".." {
                            let mut name = item.name.clone();
                            if item.dir {
                                name.push('/');
                            }

                            let entry = Entry::new(24);

                            let label = Label::new();
                            label.position(2, 2).size(w - 8, 20).text_offset(2, 2);
                            //label.bg.set(Color::rgb(255, 255, 255));
                            label.text(name);
                            entry.add(&label);

                            let window = window.deref() as *const Window;
                            let path_opt = path_opt.clone();
                            entry.on_click(move |_, _| {
                                *path_opt.borrow_mut() = Some(item.path.clone());
                                unsafe { (*window).close(); }
                            });

                            list.push(&entry);
                        },
                        Err(err) => {
                            let entry = Entry::new(24);

                            let label = Label::new();
                            label.position(2, 2).size(w - 8, 20).text_offset(2, 2);
                            //label.bg.set(Color::rgb(242, 222, 222));
                            label.text(err);
                            entry.add(&label);

                            list.push(&entry);
                        }
                    }
                },
                Err(err) => {
                    let entry = Entry::new(24);

                    let label = Label::new();
                    label.position(2, 2).size(w - 8, 20).text_offset(2, 2);
                    //label.bg.set(Color::rgb(242, 222, 222));
                    label.text(format!("{}", err));
                    entry.add(&label);

                    list.push(&entry);
                }
            }

            window.add(&list);

            window.exec();

            orb_window = Some(window.into_inner());
        }
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#![feature(borrow_state)]
#![feature(box_syntax)]
#![feature(core_intrinsics)]
#![feature(filling_drop)]
#![feature(iter_arith)]
#![feature(link_args)]
#![feature(plugin)]
#![feature(unicode)]
#![feature(unsafe_no_drop_flag)]

#![allow(non_camel_case_types)]

#![plugin(plugins)]

#[macro_use]
extern crate log;

extern crate servo;
extern crate compositing;

extern crate euclid;
extern crate gleam;
extern crate glutin_app;
extern crate layers;
extern crate rustc_unicode;
extern crate script_traits;

extern crate net_traits;
extern crate msg;
extern crate util;
extern crate style_traits;

extern crate libc;
extern crate url as std_url;

#[cfg(target_os="macos")]
#[link_args="-Xlinker -undefined -Xlinker dynamic_lookup"]
extern { }

#[cfg(target_os="macos")]
extern crate cocoa;
#[cfg(target_os="macos")]
#[macro_use]
extern crate objc;
#[cfg(target_os="linux")] extern crate x11;

// Must come first.
pub mod macros;

pub mod browser;
pub mod browser_host;
pub mod command_line;
pub mod cookie;
pub mod core;
pub mod drag_data;
pub mod eutil;
pub mod frame;
pub mod interfaces;
pub mod print_settings;
pub mod process_message;
pub mod render_handler;
pub mod request;
pub mod request_context;
pub mod response;
pub mod stream;
pub mod string;
pub mod string_list;
pub mod string_map;
pub mod string_multimap;
pub mod stubs;
pub mod switches;
pub mod task;
pub mod types;
pub mod urlrequest;
pub mod v8;
pub mod values;
pub mod window;
pub mod wrappers;
pub mod xml_reader;
pub mod zip_reader;
<commit_msg>Fix iter_arith warning when running ./mach build-cef<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#![feature(borrow_state)]
#![feature(box_syntax)]
#![feature(core_intrinsics)]
#![feature(filling_drop)]
#![feature(link_args)]
#![feature(plugin)]
#![feature(unicode)]
#![feature(unsafe_no_drop_flag)]

#![allow(non_camel_case_types)]

#![plugin(plugins)]

#[macro_use]
extern crate log;

extern crate servo;
extern crate compositing;

extern crate euclid;
extern crate gleam;
extern crate glutin_app;
extern crate layers;
extern crate rustc_unicode;
extern crate script_traits;

extern crate net_traits;
extern crate msg;
extern crate util;
extern crate style_traits;

extern crate libc;
extern crate url as std_url;

#[cfg(target_os="macos")]
#[link_args="-Xlinker -undefined -Xlinker dynamic_lookup"]
extern { }

#[cfg(target_os="macos")]
extern crate cocoa;
#[cfg(target_os="macos")]
#[macro_use]
extern crate objc;
#[cfg(target_os="linux")] extern crate x11;

// Must come first.
pub mod macros;

pub mod browser;
pub mod browser_host;
pub mod command_line;
pub mod cookie;
pub mod core;
pub mod drag_data;
pub mod eutil;
pub mod frame;
pub mod interfaces;
pub mod print_settings;
pub mod process_message;
pub mod render_handler;
pub mod request;
pub mod request_context;
pub mod response;
pub mod stream;
pub mod string;
pub mod string_list;
pub mod string_map;
pub mod string_multimap;
pub mod stubs;
pub mod switches;
pub mod task;
pub mod types;
pub mod urlrequest;
pub mod v8;
pub mod values;
pub mod window;
pub mod wrappers;
pub mod xml_reader;
pub mod zip_reader;
<|endoftext|>


<commit_before>use sdl2;
use sdl2::audio::{AudioDevice, AudioCallback, AudioSpecDesired};

pub struct AudioDriver {
    device: AudioDevice<SquareWave>,
}

impl AudioDriver {
    pub fn new(sdl_context: &sdl2::Sdl) -> Self {
        let audio_subsystem = sdl_context.audio().unwrap();

        let desired_spec = AudioSpecDesired {
            freq: Some(44100),
            channels: Some(1), // mono
            samples: None, // default sample size
        };

        let device = audio_subsystem
            .open_playback(None, &desired_spec, |spec| {
                // Show obtained AudioSpec
                println!("{:?}", spec);

                // initialize the audio callback
                SquareWave {
                    phase_inc: 240.0 / spec.freq as f32,
                    phase: 0.0,
                    volume: 0.25,
                }
            })
            .unwrap();

        AudioDriver { device: device }
    }

    pub fn start_beep(&self) {
        self.device.resume();
    }
    pub fn stop_beep(&self) {
        self.device.pause();
    }
}

struct SquareWave {
    phase_inc: f32,
    phase: f32,
    volume: f32,
}

impl AudioCallback for SquareWave {
    type Channel = f32;

    fn callback(&mut self, out: &mut [f32]) {
        // Generate a square wave
        for x in out.iter_mut() {
            *x = match self.phase {
                0.0...0.5 => self.volume,
                _ => -self.volume,
            };
            self.phase = (self.phase + self.phase_inc) % 1.0;
        }
    }
}
<commit_msg>don't use floats in pattern<commit_after>use sdl2;
use sdl2::audio::{AudioDevice, AudioCallback, AudioSpecDesired};

pub struct AudioDriver {
    device: AudioDevice<SquareWave>,
}

impl AudioDriver {
    pub fn new(sdl_context: &sdl2::Sdl) -> Self {
        let audio_subsystem = sdl_context.audio().unwrap();

        let desired_spec = AudioSpecDesired {
            freq: Some(44100),
            channels: Some(1), // mono
            samples: None, // default sample size
        };

        let device = audio_subsystem
            .open_playback(None, &desired_spec, |spec| {
                // Show obtained AudioSpec
                println!("{:?}", spec);

                // initialize the audio callback
                SquareWave {
                    phase_inc: 240.0 / spec.freq as f32,
                    phase: 0.0,
                    volume: 0.25,
                }
            })
            .unwrap();

        AudioDriver { device: device }
    }

    pub fn start_beep(&self) {
        self.device.resume();
    }
    pub fn stop_beep(&self) {
        self.device.pause();
    }
}

struct SquareWave {
    phase_inc: f32,
    phase: f32,
    volume: f32,
}

impl AudioCallback for SquareWave {
    type Channel = f32;

    fn callback(&mut self, out: &mut [f32]) {
        // Generate a square wave
        for x in out.iter_mut() {
            *x = self.volume * if self.phase < 0.5 { 1.0 } else { -1.0 };
            self.phase = (self.phase + self.phase_inc) % 1.0;
        }
    }
}
<|endoftext|>


<commit_before>/// A tree is comprised of a cylindrical trunk, a spherical bunch of leaves, and a spherical
/// rounding to the bottom of the trunk.

use cgmath::{Point, Point3, Vector3, EuclideanVector};
use std::f32;

mod voxel {
  pub use super::super::super::*;
}

// TODO: More obviously compose this tree out of simpler shapes.

#[derive(Debug, Clone, Copy)]
pub struct T {
  // bottom-center of the trunk
  pub bottom: Point3<f32>,
  pub trunk_radius: f32,
  pub trunk_height: f32,
  pub leaf_radius: f32,
}

unsafe impl Send for T {}

fn leaf_center(this: &T) -> Point3<f32> {
  this.bottom.add_v(&Vector3::new(0.0, this.trunk_height, 0.0))
}

fn trunk_density(this: &T, p: &Point3<f32>) -> f32 {
  let center = this.bottom.add_v(&Vector3::new(0.0, this.trunk_height / 2.0, 0.0));

  let dbottom = p.sub_p(&this.bottom);
  let dtrunk = p.sub_p(&center);
  let mut dxz = dtrunk;
  dxz.y = 0.0;

  f32::max(
    this.trunk_radius - dbottom.length(),
    f32::min(
      this.trunk_height - dtrunk.length(),
      this.trunk_radius - dxz.length(),
    ),
  )
}

fn leaf_density(this: &T, p: &Point3<f32>) -> f32 {
  let d = leaf_center(this).sub_p(p);
  this.leaf_radius*this.leaf_radius - (d.x*d.x + d.y*d.y + d.z*d.z)
}

impl ::voxel::field::T for T {
  fn density_at(this: &Self, p: &Point3<f32>) -> f32 {
    f32::max(trunk_density(this, p), leaf_density(this, p)).abs()
  }

  fn material_at(this: &Self, p: &Point3<f32>) -> Option<::voxel::Material> {
    let trunk_density = trunk_density(this, p);
    let leaf_density = leaf_density(this, p);
    if trunk_density < 0.0 && leaf_density < 0.0 {
      None
    } else {
      Some(
        if trunk_density >= leaf_density {
          ::voxel::Material::Bark
        } else {
          ::voxel::Material::Leaves
        }
      )
    }
  }

  fn normal_at(this: &Self, _: f32, p: &Point3<f32>) -> Vector3<f32> {
    let trunk_density = trunk_density(this, p);
    let leaf_density = leaf_density(this, p);
    if trunk_density < leaf_density {
      let leaf_center = leaf_center(this);
      p.sub_p(&leaf_center).normalize()
    } else {
      let n = p.sub_p(&this.bottom);
      if p.y <= this.bottom.y {
        // inside the rounded bottom of the trunk
        n.normalize()
      } else {
        let mut n = n;
        // inside the main trunk
        n.y = 0.0;
        n.normalize()
      }
    }
  }
}
<commit_msg>fix trunk height bug in tree brush<commit_after>/// A tree is comprised of a cylindrical trunk, a spherical bunch of leaves, and a spherical
/// rounding to the bottom of the trunk.

use cgmath::{Point, Point3, Vector3, EuclideanVector};
use std::f32;

mod voxel {
  pub use super::super::super::*;
}

// TODO: More obviously compose this tree out of simpler shapes.

#[derive(Debug, Clone, Copy)]
pub struct T {
  // bottom-center of the trunk
  pub bottom: Point3<f32>,
  pub trunk_radius: f32,
  pub trunk_height: f32,
  pub leaf_radius: f32,
}

unsafe impl Send for T {}

fn leaf_center(this: &T) -> Point3<f32> {
  this.bottom.add_v(&Vector3::new(0.0, this.trunk_height, 0.0))
}

fn trunk_density(this: &T, p: &Point3<f32>) -> f32 {
  let center = this.bottom.add_v(&Vector3::new(0.0, this.trunk_height / 2.0, 0.0));

  let dbottom = p.sub_p(&this.bottom);
  let dtrunk = p.sub_p(&center);
  let mut dxz = dtrunk;
  dxz.y = 0.0;

  f32::max(
    this.trunk_radius - dbottom.length(),
    f32::min(
      this.trunk_height / 2.0 - dtrunk.length(),
      this.trunk_radius - dxz.length(),
    ),
  )
}

fn leaf_density(this: &T, p: &Point3<f32>) -> f32 {
  let d = leaf_center(this).sub_p(p);
  this.leaf_radius*this.leaf_radius - (d.x*d.x + d.y*d.y + d.z*d.z)
}

impl ::voxel::field::T for T {
  fn density_at(this: &Self, p: &Point3<f32>) -> f32 {
    f32::max(trunk_density(this, p), leaf_density(this, p)).abs()
  }

  fn material_at(this: &Self, p: &Point3<f32>) -> Option<::voxel::Material> {
    let trunk_density = trunk_density(this, p);
    let leaf_density = leaf_density(this, p);
    if trunk_density < 0.0 && leaf_density < 0.0 {
      None
    } else {
      Some(
        if trunk_density >= leaf_density {
          ::voxel::Material::Bark
        } else {
          ::voxel::Material::Leaves
        }
      )
    }
  }

  fn normal_at(this: &Self, _: f32, p: &Point3<f32>) -> Vector3<f32> {
    let trunk_density = trunk_density(this, p);
    let leaf_density = leaf_density(this, p);
    if trunk_density < leaf_density {
      let leaf_center = leaf_center(this);
      p.sub_p(&leaf_center).normalize()
    } else {
      let n = p.sub_p(&this.bottom);
      if p.y <= this.bottom.y {
        // inside the rounded bottom of the trunk
        n.normalize()
      } else {
        let mut n = n;
        // inside the main trunk
        n.y = 0.0;
        n.normalize()
      }
    }
  }
}
<|endoftext|>


<commit_before>//! Shared access to Cairo image surfaces.
use std::ptr::NonNull;

use cairo::prelude::SurfaceExt;
use cairo::{self, ImageSurface};
use cairo_sys;
use glib::translate::{Stash, ToGlibPtr};
use rulinalg::matrix::{BaseMatrix, Matrix};

use filters::context::IRect;
use util::clamp;

use super::{
    iterators::{PixelRectangle, Pixels},
    EdgeMode,
    ImageSurfaceDataExt,
    Pixel,
};

/// Wrapper for a Cairo image surface that allows shared access.
///
/// There doesn't seem to be any good way of making safe shared access to `ImageSurface` pixel
/// data, since a read-only borrowed reference can still be cloned and then modified (for example,
/// via a `Context`). We can't simply use `ImageSurface::get_data()` because in the filter code we
/// have surfaces referenced from multiple places and it would probably add more complexity to
/// remove that and start passing around references.
///
/// This wrapper asserts the uniqueness of its image surface and doesn't permit modifying it.
///
/// Note: originally I had an idea of using `Rc<RefCell<ImageSurface>>` here which allows to create
/// both read-only and unique read-write accessors safely, however then I realized a read-write
/// accessor isn't of much use if it can't expose a Cairo context interface. Cairo contexts have
/// the very same issue that they can be cloned from a read-only reference and break all safety
/// constraints in this way. Thus the only safe way of exposing a Cairo context seemed to be to
/// manually add all Cairo context methods on the accessor forwarding to the underlying Cairo
/// context (without exposing the context itself to prevent cloning), which would result in too
/// much code. Unless it's absolutely required, I'd like to avoid that.
///
/// Having just read-only access simplifies things further dropping the need for `Rc<RefCell<>>`
/// altogether.
#[derive(Debug, Clone)]
pub struct SharedImageSurface {
    surface: ImageSurface,

    data_ptr: NonNull<u8>, // *const.
    width: i32,
    height: i32,
    stride: isize,

    /// Whether this surface contains meaningful data only in the alpha channel.
    ///
    /// This is used for optimizations, particularly in `convolve()` to skip processing other
    /// channels.
    alpha_only: bool,
}

impl SharedImageSurface {
    /// Creates a `SharedImageSurface` from a unique `ImageSurface`.
    ///
    /// # Panics
    /// Panics if the surface format isn't `ARgb32` and if the surface is not unique, that is, its
    /// reference count isn't 1.
    #[inline]
    pub fn new(surface: ImageSurface) -> Result<Self, cairo::Status> {
        // get_pixel() assumes ARgb32.
        assert_eq!(surface.get_format(), cairo::Format::ARgb32);

        let reference_count =
            unsafe { cairo_sys::cairo_surface_get_reference_count(surface.to_raw_none()) };
        assert_eq!(reference_count, 1);

        surface.flush();
        if surface.status() != cairo::Status::Success {
            return Err(surface.status());
        }

        let data_ptr = NonNull::new(unsafe {
            cairo_sys::cairo_image_surface_get_data(surface.to_raw_none())
        }).unwrap();

        let width = surface.get_width();
        let height = surface.get_height();
        let stride = surface.get_stride() as isize;

        Ok(Self {
            surface,
            data_ptr,
            width,
            height,
            stride,
            alpha_only: false,
        })
    }

    /// Creates a `SharedImageSurface` from a unique `ImageSurface` with meaningful data only in
    /// the alpha channel.
    ///
    /// # Panics
    /// Panics if the surface format isn't `ARgb32` and if the surface is not unique, that is, its
    /// reference count isn't 1.
    #[inline]
    pub fn new_alpha_only(surface: ImageSurface) -> Result<Self, cairo::Status> {
        let mut rv = Self::new(surface)?;
        rv.alpha_only = true;
        Ok(rv)
    }

    /// Converts this `SharedImageSurface` back into a Cairo image surface.
    #[inline]
    pub fn into_image_surface(self) -> Result<ImageSurface, cairo::Status> {
        let reference_count =
            unsafe { cairo_sys::cairo_surface_get_reference_count(self.surface.to_raw_none()) };

        if reference_count == 1 {
            Ok(self.surface)
        } else {
            // If there are any other references, copy the underlying surface.
            let bounds = IRect {
                x0: 0,
                y0: 0,
                x1: self.width,
                y1: self.height,
            };

            self.copy_surface(bounds)
        }
    }

    /// Returns the surface width.
    #[inline]
    pub fn width(&self) -> i32 {
        self.width
    }

    /// Returns the surface height.
    #[inline]
    pub fn height(&self) -> i32 {
        self.height
    }

    /// Returns `true` if the surface contains meaningful data only in the alpha channel.
    #[inline]
    pub fn is_alpha_only(&self) -> bool {
        self.alpha_only
    }

    /// Retrieves the pixel value at the given coordinates.
    #[inline]
    pub fn get_pixel(&self, x: u32, y: u32) -> Pixel {
        assert!(x < self.width as u32);
        assert!(y < self.height as u32);

        let value = unsafe {
            *(self
                .data_ptr
                .as_ptr()
                .offset(y as isize * self.stride + x as isize * 4) as *const u32)
        };

        Pixel {
            r: ((value >> 16) & 0xFF) as u8,
            g: ((value >> 8) & 0xFF) as u8,
            b: (value & 0xFF) as u8,
            a: ((value >> 24) & 0xFF) as u8,
        }
    }

    /// Calls `set_source_surface()` on the given Cairo context.
    #[inline]
    pub fn set_as_source_surface(&self, cr: &cairo::Context, x: f64, y: f64) {
        cr.set_source_surface(&self.surface, x, y);
    }

    /// Returns a new `ImageSurface` with the same contents as the one stored in this
    /// `SharedImageSurface` within the given bounds.
    pub fn copy_surface(&self, bounds: IRect) -> Result<ImageSurface, cairo::Status> {
        let output_surface = ImageSurface::create(cairo::Format::ARgb32, self.width, self.height)?;

        let cr = cairo::Context::new(&output_surface);
        cr.rectangle(
            bounds.x0 as f64,
            bounds.y0 as f64,
            (bounds.x1 - bounds.x0) as f64,
            (bounds.y1 - bounds.y0) as f64,
        );
        cr.clip();

        cr.set_source_surface(&self.surface, 0f64, 0f64);
        cr.paint();

        Ok(output_surface)
    }

    /// Scales the given surface by `x` and `y` into a surface `width`×`height` in size, clipped by
    /// `bounds`.
    pub fn scale_to(
        &self,
        width: i32,
        height: i32,
        bounds: IRect,
        x: f64,
        y: f64,
    ) -> Result<SharedImageSurface, cairo::Status> {
        let output_surface = ImageSurface::create(cairo::Format::ARgb32, width, height)?;

        {
            let cr = cairo::Context::new(&output_surface);
            cr.rectangle(
                bounds.x0 as f64,
                bounds.y0 as f64,
                (bounds.x1 - bounds.x0) as f64,
                (bounds.y1 - bounds.y0) as f64,
            );
            cr.clip();

            cr.scale(x, y);
            self.set_as_source_surface(&cr, 0.0, 0.0);
            cr.paint();
        }

        if self.alpha_only {
            SharedImageSurface::new_alpha_only(output_surface)
        } else {
            SharedImageSurface::new(output_surface)
        }
    }

    /// Returns a scaled version of a surface and bounds.
    #[inline]
    pub fn scale(
        &self,
        bounds: IRect,
        x: f64,
        y: f64,
    ) -> Result<(SharedImageSurface, IRect), cairo::Status> {
        let new_width = (f64::from(self.width) * x).ceil() as i32;
        let new_height = (f64::from(self.height) * y).ceil() as i32;
        let new_bounds = bounds.scale(x, y);

        Ok((
            self.scale_to(new_width, new_height, new_bounds, x, y)?,
            new_bounds,
        ))
    }

    /// Returns a surface with black background and alpha channel matching this surface.
    pub fn extract_alpha(&self, bounds: IRect) -> Result<SharedImageSurface, cairo::Status> {
        let mut output_surface =
            ImageSurface::create(cairo::Format::ARgb32, self.width, self.height)?;

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

            for (x, y, Pixel { a, .. }) in Pixels::new(self, bounds) {
                let output_pixel = Pixel {
                    r: 0,
                    g: 0,
                    b: 0,
                    a,
                };
                output_data.set_pixel(output_stride, output_pixel, x, y);
            }
        }

        SharedImageSurface::new_alpha_only(output_surface)
    }

    /// Returns a surface with pre-multiplication of color values undone.
    ///
    /// HACK: this is storing unpremultiplied pixels in an ARGB32 image surface (which is supposed
    /// to be premultiplied pixels).
    pub fn unpremultiply(&self, bounds: IRect) -> Result<SharedImageSurface, cairo::Status> {
        // Unpremultiplication doesn't affect the alpha channel.
        if self.alpha_only {
            return Ok(self.clone());
        }

        let mut output_surface =
            ImageSurface::create(cairo::Format::ARgb32, self.width, self.height)?;

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

            for (x, y, pixel) in Pixels::new(self, bounds) {
                data.set_pixel(stride, pixel.unpremultiply(), x, y);
            }
        }

        SharedImageSurface::new(output_surface)
    }

    /// Performs a convolution.
    ///
    /// Note that `kernel` is rotated 180 degrees.
    ///
    /// The `target` parameter determines the position of the kernel relative to each pixel of the
    /// image. The value of `(0, 0)` indicates that the top left pixel of the (180-degrees-rotated)
    /// kernel corresponds to the current pixel, and the rest of the kernel is to the right and
    /// bottom of the pixel. The value of `(cols / 2, rows / 2)` centers a kernel with an odd
    /// number of rows and columns.
    ///
    /// # Panics
    /// Panics if `kernel` has zero rows or columns.
    pub fn convolve(
        &self,
        bounds: IRect,
        target: (i32, i32),
        kernel: &Matrix<f64>,
        edge_mode: EdgeMode,
    ) -> Result<SharedImageSurface, cairo::Status> {
        assert!(kernel.rows() >= 1);
        assert!(kernel.cols() >= 1);

        let mut output_surface =
            ImageSurface::create(cairo::Format::ARgb32, self.width, self.height)?;

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

            if self.alpha_only {
                for (x, y, _pixel) in Pixels::new(self, bounds) {
                    let kernel_bounds = IRect {
                        x0: x as i32 - target.0,
                        y0: y as i32 - target.1,
                        x1: x as i32 - target.0 + kernel.cols() as i32,
                        y1: y as i32 - target.1 + kernel.rows() as i32,
                    };

                    let mut a = 0.0;

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

                        a += f64::from(pixel.a) * factor;
                    }

                    let convert = |x: f64| clamp(x, 0.0, 255.0).round() as u8;

                    let output_pixel = Pixel {
                        r: 0,
                        g: 0,
                        b: 0,
                        a: convert(a),
                    };

                    output_data.set_pixel(output_stride, output_pixel, x, y);
                }
            } else {
                for (x, y, _pixel) in Pixels::new(self, bounds) {
                    let kernel_bounds = IRect {
                        x0: x as i32 - target.0,
                        y0: y as i32 - target.1,
                        x1: x as i32 - target.0 + kernel.cols() as i32,
                        y1: y as i32 - target.1 + kernel.rows() as i32,
                    };

                    let mut r = 0.0;
                    let mut g = 0.0;
                    let mut b = 0.0;
                    let mut a = 0.0;

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

                        r += f64::from(pixel.r) * factor;
                        g += f64::from(pixel.g) * factor;
                        b += f64::from(pixel.b) * factor;
                        a += f64::from(pixel.a) * factor;
                    }

                    let convert = |x: f64| clamp(x, 0.0, 255.0).round() as u8;

                    let output_pixel = Pixel {
                        r: convert(r),
                        g: convert(g),
                        b: convert(b),
                        a: convert(a),
                    };

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

        if self.alpha_only {
            SharedImageSurface::new_alpha_only(output_surface)
        } else {
            SharedImageSurface::new(output_surface)
        }
    }

    /// Returns a raw pointer to the underlying surface.
    ///
    /// # Safety
    /// The returned pointer must not be used to modify the surface.
    #[inline]
    pub unsafe fn to_glib_none(&self) -> Stash<*mut cairo_sys::cairo_surface_t, ImageSurface> {
        self.surface.to_glib_none()
    }
}
<commit_msg>Add SharedImageSurface::get_pixel_or_transparent()<commit_after>//! Shared access to Cairo image surfaces.
use std::ptr::NonNull;

use cairo::prelude::SurfaceExt;
use cairo::{self, ImageSurface};
use cairo_sys;
use glib::translate::{Stash, ToGlibPtr};
use rulinalg::matrix::{BaseMatrix, Matrix};

use filters::context::IRect;
use util::clamp;

use super::{
    iterators::{PixelRectangle, Pixels},
    EdgeMode,
    ImageSurfaceDataExt,
    Pixel,
};

/// Wrapper for a Cairo image surface that allows shared access.
///
/// There doesn't seem to be any good way of making safe shared access to `ImageSurface` pixel
/// data, since a read-only borrowed reference can still be cloned and then modified (for example,
/// via a `Context`). We can't simply use `ImageSurface::get_data()` because in the filter code we
/// have surfaces referenced from multiple places and it would probably add more complexity to
/// remove that and start passing around references.
///
/// This wrapper asserts the uniqueness of its image surface and doesn't permit modifying it.
///
/// Note: originally I had an idea of using `Rc<RefCell<ImageSurface>>` here which allows to create
/// both read-only and unique read-write accessors safely, however then I realized a read-write
/// accessor isn't of much use if it can't expose a Cairo context interface. Cairo contexts have
/// the very same issue that they can be cloned from a read-only reference and break all safety
/// constraints in this way. Thus the only safe way of exposing a Cairo context seemed to be to
/// manually add all Cairo context methods on the accessor forwarding to the underlying Cairo
/// context (without exposing the context itself to prevent cloning), which would result in too
/// much code. Unless it's absolutely required, I'd like to avoid that.
///
/// Having just read-only access simplifies things further dropping the need for `Rc<RefCell<>>`
/// altogether.
#[derive(Debug, Clone)]
pub struct SharedImageSurface {
    surface: ImageSurface,

    data_ptr: NonNull<u8>, // *const.
    width: i32,
    height: i32,
    stride: isize,

    /// Whether this surface contains meaningful data only in the alpha channel.
    ///
    /// This is used for optimizations, particularly in `convolve()` to skip processing other
    /// channels.
    alpha_only: bool,
}

impl SharedImageSurface {
    /// Creates a `SharedImageSurface` from a unique `ImageSurface`.
    ///
    /// # Panics
    /// Panics if the surface format isn't `ARgb32` and if the surface is not unique, that is, its
    /// reference count isn't 1.
    #[inline]
    pub fn new(surface: ImageSurface) -> Result<Self, cairo::Status> {
        // get_pixel() assumes ARgb32.
        assert_eq!(surface.get_format(), cairo::Format::ARgb32);

        let reference_count =
            unsafe { cairo_sys::cairo_surface_get_reference_count(surface.to_raw_none()) };
        assert_eq!(reference_count, 1);

        surface.flush();
        if surface.status() != cairo::Status::Success {
            return Err(surface.status());
        }

        let data_ptr = NonNull::new(unsafe {
            cairo_sys::cairo_image_surface_get_data(surface.to_raw_none())
        }).unwrap();

        let width = surface.get_width();
        let height = surface.get_height();
        let stride = surface.get_stride() as isize;

        Ok(Self {
            surface,
            data_ptr,
            width,
            height,
            stride,
            alpha_only: false,
        })
    }

    /// Creates a `SharedImageSurface` from a unique `ImageSurface` with meaningful data only in
    /// the alpha channel.
    ///
    /// # Panics
    /// Panics if the surface format isn't `ARgb32` and if the surface is not unique, that is, its
    /// reference count isn't 1.
    #[inline]
    pub fn new_alpha_only(surface: ImageSurface) -> Result<Self, cairo::Status> {
        let mut rv = Self::new(surface)?;
        rv.alpha_only = true;
        Ok(rv)
    }

    /// Converts this `SharedImageSurface` back into a Cairo image surface.
    #[inline]
    pub fn into_image_surface(self) -> Result<ImageSurface, cairo::Status> {
        let reference_count =
            unsafe { cairo_sys::cairo_surface_get_reference_count(self.surface.to_raw_none()) };

        if reference_count == 1 {
            Ok(self.surface)
        } else {
            // If there are any other references, copy the underlying surface.
            let bounds = IRect {
                x0: 0,
                y0: 0,
                x1: self.width,
                y1: self.height,
            };

            self.copy_surface(bounds)
        }
    }

    /// Returns the surface width.
    #[inline]
    pub fn width(&self) -> i32 {
        self.width
    }

    /// Returns the surface height.
    #[inline]
    pub fn height(&self) -> i32 {
        self.height
    }

    /// Returns `true` if the surface contains meaningful data only in the alpha channel.
    #[inline]
    pub fn is_alpha_only(&self) -> bool {
        self.alpha_only
    }

    /// Retrieves the pixel value at the given coordinates.
    #[inline]
    pub fn get_pixel(&self, x: u32, y: u32) -> Pixel {
        assert!(x < self.width as u32);
        assert!(y < self.height as u32);

        let value = unsafe {
            *(self
                .data_ptr
                .as_ptr()
                .offset(y as isize * self.stride + x as isize * 4) as *const u32)
        };

        Pixel {
            r: ((value >> 16) & 0xFF) as u8,
            g: ((value >> 8) & 0xFF) as u8,
            b: (value & 0xFF) as u8,
            a: ((value >> 24) & 0xFF) as u8,
        }
    }

    /// Retrieves the pixel value if it is within `bounds`, otherwise returns a transparent black
    /// pixel.
    #[inline]
    pub fn get_pixel_or_transparent(&self, bounds: IRect, x: i32, y: i32) -> Pixel {
        if bounds.contains(x, y) {
            self.get_pixel(x as u32, y as u32)
        } else {
            Pixel {
                r: 0,
                g: 0,
                b: 0,
                a: 0,
            }
        }
    }

    /// Calls `set_source_surface()` on the given Cairo context.
    #[inline]
    pub fn set_as_source_surface(&self, cr: &cairo::Context, x: f64, y: f64) {
        cr.set_source_surface(&self.surface, x, y);
    }

    /// Returns a new `ImageSurface` with the same contents as the one stored in this
    /// `SharedImageSurface` within the given bounds.
    pub fn copy_surface(&self, bounds: IRect) -> Result<ImageSurface, cairo::Status> {
        let output_surface = ImageSurface::create(cairo::Format::ARgb32, self.width, self.height)?;

        let cr = cairo::Context::new(&output_surface);
        cr.rectangle(
            bounds.x0 as f64,
            bounds.y0 as f64,
            (bounds.x1 - bounds.x0) as f64,
            (bounds.y1 - bounds.y0) as f64,
        );
        cr.clip();

        cr.set_source_surface(&self.surface, 0f64, 0f64);
        cr.paint();

        Ok(output_surface)
    }

    /// Scales the given surface by `x` and `y` into a surface `width`×`height` in size, clipped by
    /// `bounds`.
    pub fn scale_to(
        &self,
        width: i32,
        height: i32,
        bounds: IRect,
        x: f64,
        y: f64,
    ) -> Result<SharedImageSurface, cairo::Status> {
        let output_surface = ImageSurface::create(cairo::Format::ARgb32, width, height)?;

        {
            let cr = cairo::Context::new(&output_surface);
            cr.rectangle(
                bounds.x0 as f64,
                bounds.y0 as f64,
                (bounds.x1 - bounds.x0) as f64,
                (bounds.y1 - bounds.y0) as f64,
            );
            cr.clip();

            cr.scale(x, y);
            self.set_as_source_surface(&cr, 0.0, 0.0);
            cr.paint();
        }

        if self.alpha_only {
            SharedImageSurface::new_alpha_only(output_surface)
        } else {
            SharedImageSurface::new(output_surface)
        }
    }

    /// Returns a scaled version of a surface and bounds.
    #[inline]
    pub fn scale(
        &self,
        bounds: IRect,
        x: f64,
        y: f64,
    ) -> Result<(SharedImageSurface, IRect), cairo::Status> {
        let new_width = (f64::from(self.width) * x).ceil() as i32;
        let new_height = (f64::from(self.height) * y).ceil() as i32;
        let new_bounds = bounds.scale(x, y);

        Ok((
            self.scale_to(new_width, new_height, new_bounds, x, y)?,
            new_bounds,
        ))
    }

    /// Returns a surface with black background and alpha channel matching this surface.
    pub fn extract_alpha(&self, bounds: IRect) -> Result<SharedImageSurface, cairo::Status> {
        let mut output_surface =
            ImageSurface::create(cairo::Format::ARgb32, self.width, self.height)?;

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

            for (x, y, Pixel { a, .. }) in Pixels::new(self, bounds) {
                let output_pixel = Pixel {
                    r: 0,
                    g: 0,
                    b: 0,
                    a,
                };
                output_data.set_pixel(output_stride, output_pixel, x, y);
            }
        }

        SharedImageSurface::new_alpha_only(output_surface)
    }

    /// Returns a surface with pre-multiplication of color values undone.
    ///
    /// HACK: this is storing unpremultiplied pixels in an ARGB32 image surface (which is supposed
    /// to be premultiplied pixels).
    pub fn unpremultiply(&self, bounds: IRect) -> Result<SharedImageSurface, cairo::Status> {
        // Unpremultiplication doesn't affect the alpha channel.
        if self.alpha_only {
            return Ok(self.clone());
        }

        let mut output_surface =
            ImageSurface::create(cairo::Format::ARgb32, self.width, self.height)?;

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

            for (x, y, pixel) in Pixels::new(self, bounds) {
                data.set_pixel(stride, pixel.unpremultiply(), x, y);
            }
        }

        SharedImageSurface::new(output_surface)
    }

    /// Performs a convolution.
    ///
    /// Note that `kernel` is rotated 180 degrees.
    ///
    /// The `target` parameter determines the position of the kernel relative to each pixel of the
    /// image. The value of `(0, 0)` indicates that the top left pixel of the (180-degrees-rotated)
    /// kernel corresponds to the current pixel, and the rest of the kernel is to the right and
    /// bottom of the pixel. The value of `(cols / 2, rows / 2)` centers a kernel with an odd
    /// number of rows and columns.
    ///
    /// # Panics
    /// Panics if `kernel` has zero rows or columns.
    pub fn convolve(
        &self,
        bounds: IRect,
        target: (i32, i32),
        kernel: &Matrix<f64>,
        edge_mode: EdgeMode,
    ) -> Result<SharedImageSurface, cairo::Status> {
        assert!(kernel.rows() >= 1);
        assert!(kernel.cols() >= 1);

        let mut output_surface =
            ImageSurface::create(cairo::Format::ARgb32, self.width, self.height)?;

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

            if self.alpha_only {
                for (x, y, _pixel) in Pixels::new(self, bounds) {
                    let kernel_bounds = IRect {
                        x0: x as i32 - target.0,
                        y0: y as i32 - target.1,
                        x1: x as i32 - target.0 + kernel.cols() as i32,
                        y1: y as i32 - target.1 + kernel.rows() as i32,
                    };

                    let mut a = 0.0;

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

                        a += f64::from(pixel.a) * factor;
                    }

                    let convert = |x: f64| clamp(x, 0.0, 255.0).round() as u8;

                    let output_pixel = Pixel {
                        r: 0,
                        g: 0,
                        b: 0,
                        a: convert(a),
                    };

                    output_data.set_pixel(output_stride, output_pixel, x, y);
                }
            } else {
                for (x, y, _pixel) in Pixels::new(self, bounds) {
                    let kernel_bounds = IRect {
                        x0: x as i32 - target.0,
                        y0: y as i32 - target.1,
                        x1: x as i32 - target.0 + kernel.cols() as i32,
                        y1: y as i32 - target.1 + kernel.rows() as i32,
                    };

                    let mut r = 0.0;
                    let mut g = 0.0;
                    let mut b = 0.0;
                    let mut a = 0.0;

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

                        r += f64::from(pixel.r) * factor;
                        g += f64::from(pixel.g) * factor;
                        b += f64::from(pixel.b) * factor;
                        a += f64::from(pixel.a) * factor;
                    }

                    let convert = |x: f64| clamp(x, 0.0, 255.0).round() as u8;

                    let output_pixel = Pixel {
                        r: convert(r),
                        g: convert(g),
                        b: convert(b),
                        a: convert(a),
                    };

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

        if self.alpha_only {
            SharedImageSurface::new_alpha_only(output_surface)
        } else {
            SharedImageSurface::new(output_surface)
        }
    }

    /// Returns a raw pointer to the underlying surface.
    ///
    /// # Safety
    /// The returned pointer must not be used to modify the surface.
    #[inline]
    pub unsafe fn to_glib_none(&self) -> Stash<*mut cairo_sys::cairo_surface_t, ImageSurface> {
        self.surface.to_glib_none()
    }
}
<|endoftext|>


<commit_before>//! Shared access to Cairo image surfaces.
use std::ptr::NonNull;

use cairo::prelude::SurfaceExt;
use cairo::{self, ImageSurface};
use cairo_sys;
use glib::translate::{Stash, ToGlibPtr};
use rulinalg::matrix::{BaseMatrix, Matrix};

use filters::context::IRect;
use util::clamp;

use super::{
    iterators::{PixelRectangle, Pixels},
    EdgeMode,
    ImageSurfaceDataExt,
    Pixel,
};

/// Wrapper for a Cairo image surface that allows shared access.
///
/// There doesn't seem to be any good way of making safe shared access to `ImageSurface` pixel
/// data, since a read-only borrowed reference can still be cloned and then modified (for example,
/// via a `Context`). We can't simply use `ImageSurface::get_data()` because in the filter code we
/// have surfaces referenced from multiple places and it would probably add more complexity to
/// remove that and start passing around references.
///
/// This wrapper asserts the uniqueness of its image surface and doesn't permit modifying it.
///
/// Note: originally I had an idea of using `Rc<RefCell<ImageSurface>>` here which allows to create
/// both read-only and unique read-write accessors safely, however then I realized a read-write
/// accessor isn't of much use if it can't expose a Cairo context interface. Cairo contexts have
/// the very same issue that they can be cloned from a read-only reference and break all safety
/// constraints in this way. Thus the only safe way of exposing a Cairo context seemed to be to
/// manually add all Cairo context methods on the accessor forwarding to the underlying Cairo
/// context (without exposing the context itself to prevent cloning), which would result in too
/// much code. Unless it's absolutely required, I'd like to avoid that.
///
/// Having just read-only access simplifies things further dropping the need for `Rc<RefCell<>>`
/// altogether.
#[derive(Debug, Clone)]
pub struct SharedImageSurface {
    surface: ImageSurface,

    data_ptr: NonNull<u8>, // *const.
    width: i32,
    height: i32,
    stride: isize,
}

impl SharedImageSurface {
    /// Creates a `SharedImageSurface` from a unique `ImageSurface`.
    ///
    /// # Panics
    /// Panics if the surface format isn't `ARgb32` and if the surface is not unique, that is, its
    /// reference count isn't 1.
    #[inline]
    pub fn new(surface: ImageSurface) -> Result<Self, cairo::Status> {
        // get_pixel() assumes ARgb32.
        assert_eq!(surface.get_format(), cairo::Format::ARgb32);

        let reference_count =
            unsafe { cairo_sys::cairo_surface_get_reference_count(surface.to_raw_none()) };
        assert_eq!(reference_count, 1);

        surface.flush();
        if surface.status() != cairo::Status::Success {
            return Err(surface.status());
        }

        let data_ptr = NonNull::new(unsafe {
            cairo_sys::cairo_image_surface_get_data(surface.to_raw_none())
        }).unwrap();

        let width = surface.get_width();
        let height = surface.get_height();
        let stride = surface.get_stride() as isize;

        Ok(Self {
            surface,
            data_ptr,
            width,
            height,
            stride,
        })
    }

    /// Converts this `SharedImageSurface` back into a Cairo image surface.
    ///
    /// # Panics
    /// Panics if the underlying Cairo image surface is not unique, that is, there are other
    /// instances of `SharedImageSurface` pointing at the same Cairo image surface.
    #[inline]
    pub fn into_image_surface(self) -> ImageSurface {
        let reference_count =
            unsafe { cairo_sys::cairo_surface_get_reference_count(self.surface.to_raw_none()) };
        assert_eq!(reference_count, 1);

        self.surface
    }

    /// Returns the surface width.
    #[inline]
    pub fn width(&self) -> i32 {
        self.width
    }

    /// Returns the surface height.
    #[inline]
    pub fn height(&self) -> i32 {
        self.height
    }

    /// Retrieves the pixel value at the given coordinates.
    #[inline]
    pub fn get_pixel(&self, x: u32, y: u32) -> Pixel {
        assert!(x < self.width as u32);
        assert!(y < self.height as u32);

        let value = unsafe {
            *(self
                .data_ptr
                .as_ptr()
                .offset(y as isize * self.stride + x as isize * 4) as *const u32)
        };

        Pixel {
            r: ((value >> 16) & 0xFF) as u8,
            g: ((value >> 8) & 0xFF) as u8,
            b: (value & 0xFF) as u8,
            a: ((value >> 24) & 0xFF) as u8,
        }
    }

    /// Calls `set_source_surface()` on the given Cairo context.
    #[inline]
    pub fn set_as_source_surface(&self, cr: &cairo::Context, x: f64, y: f64) {
        cr.set_source_surface(&self.surface, x, y);
    }

    /// Returns a new `ImageSurface` with the same contents as the one stored in this
    /// `SharedImageSurface` within the given bounds.
    pub fn copy_surface(&self, bounds: IRect) -> Result<ImageSurface, cairo::Status> {
        let output_surface = ImageSurface::create(cairo::Format::ARgb32, self.width, self.height)?;

        let cr = cairo::Context::new(&output_surface);
        cr.rectangle(
            bounds.x0 as f64,
            bounds.y0 as f64,
            (bounds.x1 - bounds.x0) as f64,
            (bounds.y1 - bounds.y0) as f64,
        );
        cr.clip();

        cr.set_source_surface(&self.surface, 0f64, 0f64);
        cr.paint();

        Ok(output_surface)
    }

    /// Scales the given surface by `x` and `y` into a surface `width`×`height` in size, clipped by
    /// `bounds`.
    pub fn scale_to(
        &self,
        width: i32,
        height: i32,
        bounds: IRect,
        x: f64,
        y: f64,
    ) -> Result<SharedImageSurface, cairo::Status> {
        let output_surface = ImageSurface::create(cairo::Format::ARgb32, width, height)?;

        {
            let cr = cairo::Context::new(&output_surface);
            cr.rectangle(
                bounds.x0 as f64,
                bounds.y0 as f64,
                (bounds.x1 - bounds.x0) as f64,
                (bounds.y1 - bounds.y0) as f64,
            );
            cr.clip();

            cr.scale(x, y);
            self.set_as_source_surface(&cr, 0.0, 0.0);
            cr.paint();
        }

        SharedImageSurface::new(output_surface)
    }

    /// Returns a scaled version of a surface and bounds.
    #[inline]
    pub fn scale(
        &self,
        bounds: IRect,
        x: f64,
        y: f64,
    ) -> Result<(SharedImageSurface, IRect), cairo::Status> {
        let new_width = (f64::from(self.width) * x).ceil() as i32;
        let new_height = (f64::from(self.height) * y).ceil() as i32;
        let new_bounds = bounds.scale(x, y);

        Ok((
            self.scale_to(new_width, new_height, new_bounds, x, y)?,
            new_bounds,
        ))
    }

    /// Returns a surface with black background and alpha channel matching this surface.
    pub fn extract_alpha(&self, bounds: IRect) -> Result<SharedImageSurface, cairo::Status> {
        let mut output_surface =
            ImageSurface::create(cairo::Format::ARgb32, self.width, self.height)?;

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

            for (x, y, Pixel { a, .. }) in Pixels::new(self, bounds) {
                let output_pixel = Pixel {
                    r: 0,
                    g: 0,
                    b: 0,
                    a,
                };
                output_data.set_pixel(output_stride, output_pixel, x, y);
            }
        }

        SharedImageSurface::new(output_surface)
    }

    /// Returns a surface with pre-multiplication of color values undone.
    ///
    /// HACK: this is storing unpremultiplied pixels in an ARGB32 image surface (which is supposed
    /// to be premultiplied pixels).
    pub fn unpremultiply(&self, bounds: IRect) -> Result<SharedImageSurface, cairo::Status> {
        let mut output_surface =
            ImageSurface::create(cairo::Format::ARgb32, self.width, self.height)?;

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

            for (x, y, pixel) in Pixels::new(self, bounds) {
                data.set_pixel(stride, pixel.unpremultiply(), x, y);
            }
        }

        SharedImageSurface::new(output_surface)
    }

    /// Performs a convolution.
    ///
    /// Note that `kernel` is rotated 180 degrees.
    ///
    /// The `target` parameter determines the position of the kernel relative to each pixel of the
    /// image. The value of `(0, 0)` indicates that the top left pixel of the (180-degrees-rotated)
    /// kernel corresponds to the current pixel, and the rest of the kernel is to the right and
    /// bottom of the pixel. The value of `(cols / 2, rows / 2)` centers a kernel with an odd
    /// number of rows and columns.
    ///
    /// # Panics
    /// Panics if `kernel` has zero rows or columns.
    pub fn convolve(
        &self,
        bounds: IRect,
        target: (i32, i32),
        kernel: &Matrix<f64>,
        edge_mode: EdgeMode,
    ) -> Result<SharedImageSurface, cairo::Status> {
        assert!(kernel.rows() >= 1);
        assert!(kernel.cols() >= 1);

        let mut output_surface =
            ImageSurface::create(cairo::Format::ARgb32, self.width, self.height)?;

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

            for (x, y, _pixel) in Pixels::new(self, bounds) {
                let kernel_bounds = IRect {
                    x0: x as i32 - target.0,
                    y0: y as i32 - target.1,
                    x1: x as i32 - target.0 + kernel.cols() as i32,
                    y1: y as i32 - target.1 + kernel.rows() as i32,
                };

                let mut r = 0.0;
                let mut g = 0.0;
                let mut b = 0.0;
                let mut a = 0.0;

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

                    r += f64::from(pixel.r) * factor;
                    g += f64::from(pixel.g) * factor;
                    b += f64::from(pixel.b) * factor;
                    a += f64::from(pixel.a) * factor;
                }

                let convert = |x: f64| clamp(x, 0.0, 255.0).round() as u8;

                let output_pixel = Pixel {
                    r: convert(r),
                    g: convert(g),
                    b: convert(b),
                    a: convert(a),
                };

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

        SharedImageSurface::new(output_surface)
    }

    /// Returns a raw pointer to the underlying surface.
    ///
    /// # Safety
    /// The returned pointer must not be used to modify the surface.
    #[inline]
    pub unsafe fn to_glib_none(&self) -> Stash<*mut cairo_sys::cairo_surface_t, ImageSurface> {
        self.surface.to_glib_none()
    }
}
<commit_msg>Add an alpha-only flag to SharedImageSurface<commit_after>//! Shared access to Cairo image surfaces.
use std::ptr::NonNull;

use cairo::prelude::SurfaceExt;
use cairo::{self, ImageSurface};
use cairo_sys;
use glib::translate::{Stash, ToGlibPtr};
use rulinalg::matrix::{BaseMatrix, Matrix};

use filters::context::IRect;
use util::clamp;

use super::{
    iterators::{PixelRectangle, Pixels},
    EdgeMode,
    ImageSurfaceDataExt,
    Pixel,
};

/// Wrapper for a Cairo image surface that allows shared access.
///
/// There doesn't seem to be any good way of making safe shared access to `ImageSurface` pixel
/// data, since a read-only borrowed reference can still be cloned and then modified (for example,
/// via a `Context`). We can't simply use `ImageSurface::get_data()` because in the filter code we
/// have surfaces referenced from multiple places and it would probably add more complexity to
/// remove that and start passing around references.
///
/// This wrapper asserts the uniqueness of its image surface and doesn't permit modifying it.
///
/// Note: originally I had an idea of using `Rc<RefCell<ImageSurface>>` here which allows to create
/// both read-only and unique read-write accessors safely, however then I realized a read-write
/// accessor isn't of much use if it can't expose a Cairo context interface. Cairo contexts have
/// the very same issue that they can be cloned from a read-only reference and break all safety
/// constraints in this way. Thus the only safe way of exposing a Cairo context seemed to be to
/// manually add all Cairo context methods on the accessor forwarding to the underlying Cairo
/// context (without exposing the context itself to prevent cloning), which would result in too
/// much code. Unless it's absolutely required, I'd like to avoid that.
///
/// Having just read-only access simplifies things further dropping the need for `Rc<RefCell<>>`
/// altogether.
#[derive(Debug, Clone)]
pub struct SharedImageSurface {
    surface: ImageSurface,

    data_ptr: NonNull<u8>, // *const.
    width: i32,
    height: i32,
    stride: isize,

    /// Whether this surface contains meaningful data only in the alpha channel.
    ///
    /// This is used for optimizations, particularly in `convolve()` to skip processing other
    /// channels.
    alpha_only: bool,
}

impl SharedImageSurface {
    /// Creates a `SharedImageSurface` from a unique `ImageSurface`.
    ///
    /// # Panics
    /// Panics if the surface format isn't `ARgb32` and if the surface is not unique, that is, its
    /// reference count isn't 1.
    #[inline]
    pub fn new(surface: ImageSurface) -> Result<Self, cairo::Status> {
        // get_pixel() assumes ARgb32.
        assert_eq!(surface.get_format(), cairo::Format::ARgb32);

        let reference_count =
            unsafe { cairo_sys::cairo_surface_get_reference_count(surface.to_raw_none()) };
        assert_eq!(reference_count, 1);

        surface.flush();
        if surface.status() != cairo::Status::Success {
            return Err(surface.status());
        }

        let data_ptr = NonNull::new(unsafe {
            cairo_sys::cairo_image_surface_get_data(surface.to_raw_none())
        }).unwrap();

        let width = surface.get_width();
        let height = surface.get_height();
        let stride = surface.get_stride() as isize;

        Ok(Self {
            surface,
            data_ptr,
            width,
            height,
            stride,
            alpha_only: false,
        })
    }

    /// Creates a `SharedImageSurface` from a unique `ImageSurface` with meaningful data only in
    /// the alpha channel.
    ///
    /// # Panics
    /// Panics if the surface format isn't `ARgb32` and if the surface is not unique, that is, its
    /// reference count isn't 1.
    #[inline]
    pub fn new_alpha_only(surface: ImageSurface) -> Result<Self, cairo::Status> {
        let mut rv = Self::new(surface)?;
        rv.alpha_only = true;
        Ok(rv)
    }

    /// Converts this `SharedImageSurface` back into a Cairo image surface.
    ///
    /// # Panics
    /// Panics if the underlying Cairo image surface is not unique, that is, there are other
    /// instances of `SharedImageSurface` pointing at the same Cairo image surface.
    #[inline]
    pub fn into_image_surface(self) -> ImageSurface {
        let reference_count =
            unsafe { cairo_sys::cairo_surface_get_reference_count(self.surface.to_raw_none()) };
        assert_eq!(reference_count, 1);

        self.surface
    }

    /// Returns the surface width.
    #[inline]
    pub fn width(&self) -> i32 {
        self.width
    }

    /// Returns the surface height.
    #[inline]
    pub fn height(&self) -> i32 {
        self.height
    }

    /// Returns `true` if the surface contains meaningful data only in the alpha channel.
    #[inline]
    pub fn is_alpha_only(&self) -> bool {
        self.alpha_only
    }

    /// Retrieves the pixel value at the given coordinates.
    #[inline]
    pub fn get_pixel(&self, x: u32, y: u32) -> Pixel {
        assert!(x < self.width as u32);
        assert!(y < self.height as u32);

        let value = unsafe {
            *(self
                .data_ptr
                .as_ptr()
                .offset(y as isize * self.stride + x as isize * 4) as *const u32)
        };

        Pixel {
            r: ((value >> 16) & 0xFF) as u8,
            g: ((value >> 8) & 0xFF) as u8,
            b: (value & 0xFF) as u8,
            a: ((value >> 24) & 0xFF) as u8,
        }
    }

    /// Calls `set_source_surface()` on the given Cairo context.
    #[inline]
    pub fn set_as_source_surface(&self, cr: &cairo::Context, x: f64, y: f64) {
        cr.set_source_surface(&self.surface, x, y);
    }

    /// Returns a new `ImageSurface` with the same contents as the one stored in this
    /// `SharedImageSurface` within the given bounds.
    pub fn copy_surface(&self, bounds: IRect) -> Result<ImageSurface, cairo::Status> {
        let output_surface = ImageSurface::create(cairo::Format::ARgb32, self.width, self.height)?;

        let cr = cairo::Context::new(&output_surface);
        cr.rectangle(
            bounds.x0 as f64,
            bounds.y0 as f64,
            (bounds.x1 - bounds.x0) as f64,
            (bounds.y1 - bounds.y0) as f64,
        );
        cr.clip();

        cr.set_source_surface(&self.surface, 0f64, 0f64);
        cr.paint();

        Ok(output_surface)
    }

    /// Scales the given surface by `x` and `y` into a surface `width`×`height` in size, clipped by
    /// `bounds`.
    pub fn scale_to(
        &self,
        width: i32,
        height: i32,
        bounds: IRect,
        x: f64,
        y: f64,
    ) -> Result<SharedImageSurface, cairo::Status> {
        let output_surface = ImageSurface::create(cairo::Format::ARgb32, width, height)?;

        {
            let cr = cairo::Context::new(&output_surface);
            cr.rectangle(
                bounds.x0 as f64,
                bounds.y0 as f64,
                (bounds.x1 - bounds.x0) as f64,
                (bounds.y1 - bounds.y0) as f64,
            );
            cr.clip();

            cr.scale(x, y);
            self.set_as_source_surface(&cr, 0.0, 0.0);
            cr.paint();
        }

        SharedImageSurface::new(output_surface)
    }

    /// Returns a scaled version of a surface and bounds.
    #[inline]
    pub fn scale(
        &self,
        bounds: IRect,
        x: f64,
        y: f64,
    ) -> Result<(SharedImageSurface, IRect), cairo::Status> {
        let new_width = (f64::from(self.width) * x).ceil() as i32;
        let new_height = (f64::from(self.height) * y).ceil() as i32;
        let new_bounds = bounds.scale(x, y);

        Ok((
            self.scale_to(new_width, new_height, new_bounds, x, y)?,
            new_bounds,
        ))
    }

    /// Returns a surface with black background and alpha channel matching this surface.
    pub fn extract_alpha(&self, bounds: IRect) -> Result<SharedImageSurface, cairo::Status> {
        let mut output_surface =
            ImageSurface::create(cairo::Format::ARgb32, self.width, self.height)?;

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

            for (x, y, Pixel { a, .. }) in Pixels::new(self, bounds) {
                let output_pixel = Pixel {
                    r: 0,
                    g: 0,
                    b: 0,
                    a,
                };
                output_data.set_pixel(output_stride, output_pixel, x, y);
            }
        }

        SharedImageSurface::new_alpha_only(output_surface)
    }

    /// Returns a surface with pre-multiplication of color values undone.
    ///
    /// HACK: this is storing unpremultiplied pixels in an ARGB32 image surface (which is supposed
    /// to be premultiplied pixels).
    pub fn unpremultiply(&self, bounds: IRect) -> Result<SharedImageSurface, cairo::Status> {
        let mut output_surface =
            ImageSurface::create(cairo::Format::ARgb32, self.width, self.height)?;

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

            for (x, y, pixel) in Pixels::new(self, bounds) {
                data.set_pixel(stride, pixel.unpremultiply(), x, y);
            }
        }

        SharedImageSurface::new(output_surface)
    }

    /// Performs a convolution.
    ///
    /// Note that `kernel` is rotated 180 degrees.
    ///
    /// The `target` parameter determines the position of the kernel relative to each pixel of the
    /// image. The value of `(0, 0)` indicates that the top left pixel of the (180-degrees-rotated)
    /// kernel corresponds to the current pixel, and the rest of the kernel is to the right and
    /// bottom of the pixel. The value of `(cols / 2, rows / 2)` centers a kernel with an odd
    /// number of rows and columns.
    ///
    /// # Panics
    /// Panics if `kernel` has zero rows or columns.
    pub fn convolve(
        &self,
        bounds: IRect,
        target: (i32, i32),
        kernel: &Matrix<f64>,
        edge_mode: EdgeMode,
    ) -> Result<SharedImageSurface, cairo::Status> {
        assert!(kernel.rows() >= 1);
        assert!(kernel.cols() >= 1);

        let mut output_surface =
            ImageSurface::create(cairo::Format::ARgb32, self.width, self.height)?;

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

            for (x, y, _pixel) in Pixels::new(self, bounds) {
                let kernel_bounds = IRect {
                    x0: x as i32 - target.0,
                    y0: y as i32 - target.1,
                    x1: x as i32 - target.0 + kernel.cols() as i32,
                    y1: y as i32 - target.1 + kernel.rows() as i32,
                };

                let mut r = 0.0;
                let mut g = 0.0;
                let mut b = 0.0;
                let mut a = 0.0;

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

                    r += f64::from(pixel.r) * factor;
                    g += f64::from(pixel.g) * factor;
                    b += f64::from(pixel.b) * factor;
                    a += f64::from(pixel.a) * factor;
                }

                let convert = |x: f64| clamp(x, 0.0, 255.0).round() as u8;

                let output_pixel = Pixel {
                    r: convert(r),
                    g: convert(g),
                    b: convert(b),
                    a: convert(a),
                };

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

        SharedImageSurface::new(output_surface)
    }

    /// Returns a raw pointer to the underlying surface.
    ///
    /// # Safety
    /// The returned pointer must not be used to modify the surface.
    #[inline]
    pub unsafe fn to_glib_none(&self) -> Stash<*mut cairo_sys::cairo_surface_t, ImageSurface> {
        self.surface.to_glib_none()
    }
}
<|endoftext|>


<commit_before>use primal_bit::{BitVec};
use std::{cmp};
use hamming;

use wheel;

mod presieve;

/// A segmented sieve that yields only a small run of primes at a
/// time.
///
/// This is heavily inspired by this [segmented
/// sieve](http://primesieve.org/segmented_sieve.html) code.
#[derive(Debug)]
pub struct StreamingSieve {
    small: Option<::Sieve>,
    // stores which numbers *aren't* prime, i.e. true == composite.
    sieve: BitVec,
    primes: Vec<wheel::WheelInfo<wheel::Wheel210>>,
    small_primes: Vec<wheel::WheelInfo<wheel::Wheel30>>,
    presieve: presieve::Presieve,

    low: usize,
    current: usize,
    limit: usize,
}

const CACHE: usize = (32 << 10);
const SEG_ELEMS: usize = 8 * CACHE;
const SEG_LEN: usize = SEG_ELEMS * wheel::BYTE_MODULO / wheel::BYTE_SIZE;

fn bits_for(x: usize) -> usize {
    (x * wheel::BYTE_SIZE + wheel::BYTE_MODULO - 1) / wheel::BYTE_MODULO
}

impl StreamingSieve {
    /// Create a new instance of the streaming sieve that will
    /// correctly progressively filter primes up to `limit`.
    pub fn new(limit: usize) -> StreamingSieve {
        let low = 0;

        let elems = cmp::min(bits_for(limit), SEG_ELEMS);
        let presieve = presieve::Presieve::new(elems);
        let current = presieve.smallest_unincluded_prime();

        let small = if limit < current * current {
            None
        } else {
            Some(::Sieve::new((limit as f64).sqrt() as usize + 1))
        };

        StreamingSieve {
            small: small,
            sieve: BitVec::from_elem(elems, false),
            primes: vec![],
            small_primes: vec![],
            presieve: presieve,

            low: low,
            current: current,
            limit: limit
        }
    }
    fn split_index(&self, idx: usize) -> (usize, usize) {
        let len = SEG_ELEMS;
        (idx / len,idx % len)
    }
    fn index_for(&self, n: usize) -> (bool, usize, usize) {
        let (b, idx) = wheel::bit_index(n);
        let (base, tweak) = self.split_index(idx);
        (b, base, tweak)
    }

    pub fn count_upto(n: usize) -> usize {
        match n {
            0...1 => 0,
            2 => 1,
            3...4 => 2,
            5...6 => 3,
            7...10 => 4,
            _ => {
                let mut sieve = StreamingSieve::new(n);
                let (includes, base, tweak) = sieve.index_for(n);
                let mut count = match wheel::BYTE_MODULO {
                    30 => 3,
                    _ => unimplemented!()
                };

                for _ in 0..base {
                    let (_, bitv) = sieve.next().unwrap();
                    let bytes = bitv.as_bytes();
                    count += 8 * bytes.len() - hamming::weight(bytes) as usize;
                }
                let (tweak_byte, tweak_bit) = (tweak / 8, tweak % 8);
                let (_, last) = sieve.next().unwrap();
                let bytes = last.as_bytes();
                count += 8 * tweak_byte - hamming::weight(&bytes[..tweak_byte]) as usize;
                if tweak_bit > 0 || includes {
                    let byte = bytes[tweak_byte];
                    for i in 0..tweak_bit + includes as usize {
                        count += (byte & (1 << i) == 0) as usize
                    }
                }
                count
            }
        }
    }

    fn small_primes_sieve<W: wheel::Wheel>(sieve: &mut BitVec,
                                           small_primes: &mut [wheel::WheelInfo<W>]) {
        let bytes = sieve.as_bytes_mut();
        for wi in small_primes {
            wi.sieve_hardcoded(bytes);
        }
    }

    fn direct_sieve(&mut self) {
        let bytes = self.sieve.as_bytes_mut();

        let mut iter = self.primes.iter_mut();

        while iter.size_hint().0 >= 3 {
            match (iter.next(), iter.next(), iter.next()) {
                (Some(wi1), Some(wi2), Some(wi3)) => {
                    wi1.sieve_triple(wi2, wi3, bytes);
                }
                _ => unreachable!()
            }
        }
        for wi in iter {
            wi.sieve(bytes)
        }
    }

    /// Extract the next chunk of filtered primes, the return value is
    /// `Some((low, v))` or `None` if the sieve has reached the limit.
    ///
    /// The vector stores bits for each odd number starting at `low`.
    /// Bit `n` of `v` is set if and only if `low + 2 * n + 1` is
    /// prime.
    ///
    /// NB. the prime 2 is not included in any of these sieves and so
    /// needs special handling.
    pub fn next(&mut self) -> Option<(usize, &BitVec)> {
        if self.low >= self.limit {
            return None
        }

        let low = self.low;
        self.low += SEG_LEN;
        let high = cmp::min(low + SEG_LEN - 1, self.limit);
        self.sieve.clear();

        let mut s = self.current;

        if let Some(ref small) = self.small {
            while s * s <= high {
                if small.is_prime(s) {
                    if s <= SEG_LEN / 100 {
                        self.small_primes.push(wheel::compute_wheel_elem(wheel::Wheel30, s, low));
                    } else {
                        self.primes.push(wheel::compute_wheel_elem(wheel::Wheel210, s, low));
                    }
                }
                s += 1
            }
        }

        self.current = s;

        self.presieve.apply(&mut self.sieve, low);
        StreamingSieve::small_primes_sieve(&mut self.sieve, &mut self.small_primes);
        self.direct_sieve();

        if low == 0 {
            // 1 is not prime.
            self.sieve.set(0, true);
            self.presieve.mark_small_primes(&mut self.sieve);
        }

        Some((low, &self.sieve))
    }
}

#[cfg(test)]
mod tests {
    use wheel;
    use super::StreamingSieve;
    fn gcd(x: usize, y: usize) -> usize {
        if y == 0 { x }
        else { gcd(y, x % y) }
    }
    fn coprime_to(x: usize) -> Vec<usize> {
        (1..x).filter(|&n| gcd(n, x) == 1).collect()
    }
    #[test]
    fn test() {
        let coprime = coprime_to(wheel::BYTE_MODULO);
        const LIMIT: usize = 2_000_000;
        let mut sieve = StreamingSieve::new(LIMIT);
        let primes = ::primal_smallsieve::Primes::sieve(LIMIT);

        let mut base = 0;
        let mut index = 0;

        while let Some((_low, next)) = sieve.next() {
            for val in next {
                let i = wheel::BYTE_MODULO * base + coprime[index];
                if i >= LIMIT { break }
                assert!(primes.is_prime(i) == !val,
                        "failed for {} (is prime = {})", i, primes.is_prime(i));

                index += 1;
                if index == wheel::BYTE_SIZE {
                    index = 0;
                    base += 1
                }
            }
        }
    }
}

#[cfg(all(test, feature = "unstable"))]
mod benches {
    use test::Bencher;
    use super::StreamingSieve;

    fn run(b: &mut Bencher, n: usize) {
        b.iter(|| {
            let mut sieve = StreamingSieve::new(n);
            while sieve.next().is_some() {}
        })
    }

    #[bench]
    fn sieve_small(b: &mut Bencher) {
        run(b, 100)
    }
    #[bench]
    fn sieve_medium(b: &mut Bencher) {
        run(b, 10_000)
    }
    #[bench]
    fn sieve_large(b: &mut Bencher) {
        run(b, 100_000)
    }
    #[bench]
    fn sieve_larger(b: &mut Bencher) {
        run(b, 1_000_000)
    }
    #[bench]
    fn sieve_huge(b: &mut Bencher) {
        run(b, 10_000_000)
    }
}
<commit_msg>sieve: store "large" primes separately.<commit_after>use primal_bit::{BitVec};
use std::{cmp};
use hamming;

use wheel;

mod presieve;

/// A segmented sieve that yields only a small run of primes at a
/// time.
///
/// This is heavily inspired by this [segmented
/// sieve](http://primesieve.org/segmented_sieve.html) code.
#[derive(Debug)]
pub struct StreamingSieve {
    small: Option<::Sieve>,
    // stores which numbers *aren't* prime, i.e. true == composite.
    sieve: BitVec,
    primes: Vec<wheel::WheelInfo<wheel::Wheel210>>,
    small_primes: Vec<wheel::WheelInfo<wheel::Wheel30>>,
    large_primes: Vec<wheel::WheelInfo<wheel::Wheel210>>,
    presieve: presieve::Presieve,

    low: usize,
    current: usize,
    limit: usize,
}

const CACHE: usize = (32 << 10);
const SEG_ELEMS: usize = 8 * CACHE;
const SEG_LEN: usize = SEG_ELEMS * wheel::BYTE_MODULO / wheel::BYTE_SIZE;

fn bits_for(x: usize) -> usize {
    (x * wheel::BYTE_SIZE + wheel::BYTE_MODULO - 1) / wheel::BYTE_MODULO
}

impl StreamingSieve {
    /// Create a new instance of the streaming sieve that will
    /// correctly progressively filter primes up to `limit`.
    pub fn new(limit: usize) -> StreamingSieve {
        let low = 0;

        let elems = cmp::min(bits_for(limit), SEG_ELEMS);
        let presieve = presieve::Presieve::new(elems);
        let current = presieve.smallest_unincluded_prime();

        let small = if limit < current * current {
            None
        } else {
            Some(::Sieve::new((limit as f64).sqrt() as usize + 1))
        };

        StreamingSieve {
            small: small,
            sieve: BitVec::from_elem(elems, false),
            primes: vec![],
            small_primes: vec![],
            large_primes: vec![],
            presieve: presieve,

            low: low,
            current: current,
            limit: limit
        }
    }
    fn split_index(&self, idx: usize) -> (usize, usize) {
        let len = SEG_ELEMS;
        (idx / len,idx % len)
    }
    fn index_for(&self, n: usize) -> (bool, usize, usize) {
        let (b, idx) = wheel::bit_index(n);
        let (base, tweak) = self.split_index(idx);
        (b, base, tweak)
    }

    pub fn count_upto(n: usize) -> usize {
        match n {
            0...1 => 0,
            2 => 1,
            3...4 => 2,
            5...6 => 3,
            7...10 => 4,
            _ => {
                let mut sieve = StreamingSieve::new(n);
                let (includes, base, tweak) = sieve.index_for(n);
                let mut count = match wheel::BYTE_MODULO {
                    30 => 3,
                    _ => unimplemented!()
                };

                for _ in 0..base {
                    let (_, bitv) = sieve.next().unwrap();
                    let bytes = bitv.as_bytes();
                    count += 8 * bytes.len() - hamming::weight(bytes) as usize;
                }
                let (tweak_byte, tweak_bit) = (tweak / 8, tweak % 8);
                let (_, last) = sieve.next().unwrap();
                let bytes = last.as_bytes();
                count += 8 * tweak_byte - hamming::weight(&bytes[..tweak_byte]) as usize;
                if tweak_bit > 0 || includes {
                    let byte = bytes[tweak_byte];
                    for i in 0..tweak_bit + includes as usize {
                        count += (byte & (1 << i) == 0) as usize
                    }
                }
                count
            }
        }
    }

    fn small_primes_sieve<W: wheel::Wheel>(sieve: &mut BitVec,
                                           small_primes: &mut [wheel::WheelInfo<W>]) {
        let bytes = sieve.as_bytes_mut();
        for wi in small_primes {
            wi.sieve_hardcoded(bytes);
        }
    }

    fn direct_sieve(&mut self) {
        let bytes = self.sieve.as_bytes_mut();

        let mut iter = self.primes.iter_mut();

        while iter.size_hint().0 >= 3 {
            match (iter.next(), iter.next(), iter.next()) {
                (Some(wi1), Some(wi2), Some(wi3)) => {
                    wi1.sieve_triple(wi2, wi3, bytes);
                }
                _ => unreachable!()
            }
        }
        for wi in iter {
            wi.sieve(bytes)
        }
    }

    fn large_primes_sieve(&mut self) {
        let bytes = self.sieve.as_bytes_mut();

        let mut iter = self.large_primes.iter_mut();

        while iter.size_hint().0 >= 2 {
            match (iter.next(), iter.next()) {
                (Some(wi1), Some(wi2)) => {
                    wi1.sieve_pair(wi2, bytes);
                }
                _ => unreachable!()
            }
        }
        for wi in iter {
            wi.sieve(bytes)
        }
    }

    /// Extract the next chunk of filtered primes, the return value is
    /// `Some((low, v))` or `None` if the sieve has reached the limit.
    ///
    /// The vector stores bits for each odd number starting at `low`.
    /// Bit `n` of `v` is set if and only if `low + 2 * n + 1` is
    /// prime.
    ///
    /// NB. the prime 2 is not included in any of these sieves and so
    /// needs special handling.
    pub fn next(&mut self) -> Option<(usize, &BitVec)> {
        if self.low >= self.limit {
            return None
        }

        let low = self.low;
        self.low += SEG_LEN;
        let high = cmp::min(low + SEG_LEN - 1, self.limit);
        self.sieve.clear();

        let mut s = self.current;

        if let Some(ref small) = self.small {
            while s * s <= high {
                if small.is_prime(s) {
                    if s <= SEG_LEN / 100 {
                        self.small_primes.push(wheel::compute_wheel_elem(wheel::Wheel30, s, low));
                    } else {
                        let elem = wheel::compute_wheel_elem(wheel::Wheel210, s, low);
                        if s < SEG_LEN / 2 {
                            self.primes.push(elem)
                        } else {
                            self.large_primes.push(elem)
                        }
                    }
                }
                s += 1
            }
        }

        self.current = s;

        self.presieve.apply(&mut self.sieve, low);
        StreamingSieve::small_primes_sieve(&mut self.sieve, &mut self.small_primes);
        self.direct_sieve();
        self.large_primes_sieve();

        if low == 0 {
            // 1 is not prime.
            self.sieve.set(0, true);
            self.presieve.mark_small_primes(&mut self.sieve);
        }

        Some((low, &self.sieve))
    }
}

#[cfg(test)]
mod tests {
    use wheel;
    use super::StreamingSieve;
    fn gcd(x: usize, y: usize) -> usize {
        if y == 0 { x }
        else { gcd(y, x % y) }
    }
    fn coprime_to(x: usize) -> Vec<usize> {
        (1..x).filter(|&n| gcd(n, x) == 1).collect()
    }
    #[test]
    fn test() {
        let coprime = coprime_to(wheel::BYTE_MODULO);
        const LIMIT: usize = 2_000_000;
        let mut sieve = StreamingSieve::new(LIMIT);
        let primes = ::primal_smallsieve::Primes::sieve(LIMIT);

        let mut base = 0;
        let mut index = 0;

        while let Some((_low, next)) = sieve.next() {
            for val in next {
                let i = wheel::BYTE_MODULO * base + coprime[index];
                if i >= LIMIT { break }
                assert!(primes.is_prime(i) == !val,
                        "failed for {} (is prime = {})", i, primes.is_prime(i));

                index += 1;
                if index == wheel::BYTE_SIZE {
                    index = 0;
                    base += 1
                }
            }
        }
    }
}

#[cfg(all(test, feature = "unstable"))]
mod benches {
    use test::Bencher;
    use super::StreamingSieve;

    fn run(b: &mut Bencher, n: usize) {
        b.iter(|| {
            let mut sieve = StreamingSieve::new(n);
            while sieve.next().is_some() {}
        })
    }

    #[bench]
    fn sieve_small(b: &mut Bencher) {
        run(b, 100)
    }
    #[bench]
    fn sieve_medium(b: &mut Bencher) {
        run(b, 10_000)
    }
    #[bench]
    fn sieve_large(b: &mut Bencher) {
        run(b, 100_000)
    }
    #[bench]
    fn sieve_larger(b: &mut Bencher) {
        run(b, 1_000_000)
    }
    #[bench]
    fn sieve_huge(b: &mut Bencher) {
        run(b, 10_000_000)
    }
}
<|endoftext|>