<commit_before>//! Implementations of the default callbacks exposed by wlc.
//! These functions are the main entry points into Way Cooler from user action.
//! This is the default mode that Way Cooler is in at initilization
use rustwlc::*;
use rustwlc::input::{pointer, keyboard};
use rustwlc::render::{read_pixels, wlc_pixel_format};
use uuid::Uuid;

use super::{EVENT_BLOCKED, EVENT_PASS_THROUGH, LEFT_CLICK, RIGHT_CLICK};
use ::keys::{self, KeyPress, KeyEvent};
use ::layout::{lock_tree, try_lock_tree, try_lock_action, Action, ContainerType,
                    MovementError, TreeError, FocusError};
use ::layout::commands::set_performing_action;
use ::layout::MIN_SIZE;
use ::lua::{self, LuaQuery};

use ::render::screen_scrape::{read_screen_scrape_lock, scraped_pixels_lock,
                              sync_scrape};
use ::awesome;

use registry::{self};
use super::Mode;

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Default;

#[allow(unused)]
impl Mode for Default {
    fn output_created(&mut self, output: WlcOutput) -> bool {
        if let Ok(mut tree) = try_lock_tree() {
            let result = tree.add_output(output).and_then(|_|{
                tree.switch_to_workspace(&"1")
                    .map(|_| tree.layout_active_of(ContainerType::Output))
            });
            match result {
                // If the output exists, we just couldn't add it to the tree because
                // it's already there. That's OK
                Ok(_) | Err(TreeError::OutputExists(_)) => true,
                _ => false
            }
        } else {
            false
        }
    }

    fn output_destroyed(&mut self, output: WlcOutput) {
         // TODO Redistribute workspaces of that output.
    }

    fn output_focused(&mut self, output: WlcOutput, focused: bool) {
         // TODO Ensure focused on right workspace
    }

    fn output_resolution(&mut self, output: WlcOutput,
                                    old_size_ptr: Size, new_size_ptr: Size) {
        // Update the resolution of the output and its children
        let scale = 1;
        output.set_resolution(new_size_ptr, scale);
        if let Ok(mut tree) = try_lock_tree() {
            tree.layout_active_of(ContainerType::Output)
                .expect("Could not layout active output");
        }
    }

    fn output_render_post(&mut self, output: WlcOutput) {
        let need_to_fetch = read_screen_scrape_lock();
        if *need_to_fetch {
            if WlcOutput::focused() != output {
                return
            }
            if let Ok(mut scraped_pixels) = scraped_pixels_lock() {
                let resolution = output.get_resolution()
                    .expect("Output had no resolution");
                let geo = Geometry {
                    origin: Point { x: 0, y: 0 },
                    size: resolution
                };
                let result = read_pixels(wlc_pixel_format::WLC_RGBA8888, geo).1;
                *scraped_pixels = result;
                sync_scrape();
            }
        }
    }

    fn view_created(&mut self, view: WlcView) -> bool {
        let lock = registry::clients_read();
        let client = lock.client(Uuid::nil()).unwrap();
        let handle = registry::ReadHandle::new(&client);
        let bar = handle.read("programs".into())
            .expect("programs category didn't exist")
            .get("x11_bar".into())
            .and_then(|data| data.as_string().map(str::to_string));
        // TODO Move this hack, probably could live somewhere else
        if let Some(bar_name) = bar {
            if view.get_title().as_str() == bar_name {
                view.set_mask(1);
                view.bring_to_front();
                if let Ok(mut tree) = try_lock_tree() {
                    let output = WlcOutput::focused();
                    tree.add_bar(view, output).unwrap_or_else(|_| {
                        warn!("Could not add bar {:#?} to output {:#?}", view, output);
                    });
                    return true;
                }
            }
        }
        // TODO Remove this hack
        if view.get_class().as_str() == "Background" {
            trace!("Setting background: {}", view.get_title());
            view.send_to_back();
            view.set_mask(1);
            let output = view.get_output();
            let resolution = output.get_resolution()
                .expect("Couldn't get output resolution");
            let fullscreen = Geometry {
                origin: Point { x: 0, y: 0 },
                size: resolution
            };
            view.set_geometry(ResizeEdge::empty(), fullscreen);
            if let Ok(mut tree) = lock_tree() {
                let output = WlcOutput::focused();
                return tree.add_background(view, output).map(|_| true)
                    .unwrap_or_else(|err| {
                        warn!("Could not add background due to {:?}", err);
                        true
                    })
            } else {
                warn!("Could not lock tree to place background");
            }
            return false
        }
        if let Ok(mut tree) = lock_tree() {
            let result = tree.add_view(view).and_then(|_| {
                view.set_state(VIEW_MAXIMIZED, true);
                match tree.set_active_view(view) {
                    // If blocked by fullscreen, we don't focus on purpose
                    Err(TreeError::Focus(FocusError::BlockedByFullscreen(_, _))) => Ok(()),
                    result => result
                }
            });
            if result.is_err() {
                warn!("Could not add {:?}. Reason: {:?}", view, result);
            }
            result.is_ok()
        } else {
            false
        }
    }

    fn view_destroyed(&mut self, view: WlcView) {
        match try_lock_tree() {
            Ok(mut tree) => {
                tree.remove_view(view).unwrap_or_else(|err| {
                    match err {
                        TreeError::ViewNotFound(_) => {},
                        _ => {
                            warn!("Error in view_destroyed: {:?}", err);
                        }
                    }});
            },
            Err(err) => warn!("Could not delete view {:?}, {:?}", view, err)
        }
    }

    fn view_focused(&mut self, current: WlcView, focused: bool) {
        current.set_state(VIEW_ACTIVATED, focused);
        if let Ok(mut tree) = try_lock_tree() {
            match tree.set_active_view(current) {
                Ok(_) => {},
                Err(err) => {
                    warn!("Could not set {:?} to be active view: {:?}", current, err);
                }
            }
        }
    }

    fn view_props_changed(&mut self, view: WlcView, prop: ViewPropertyType) {
        if prop.contains(PROPERTY_TITLE) {
            if let Ok(mut tree) = try_lock_tree() {
                match tree.update_title(view) {
                    Ok(_) => {},
                    Err(err) => {
                        warn!("Could not update title for view {:?} because {:#?}",
                            view, err);
                    }
                }
            }
        }
    }

    fn view_moved_to_output(&mut self, view: WlcView, o1: WlcOutput, o2: WlcOutput) {
        // TODO Ensure in correct workspace
    }

    fn view_request_state(&mut self, view: WlcView, state: ViewState, toggle: bool) {
        if state == VIEW_FULLSCREEN {
            if let Ok(mut tree) = try_lock_tree() {
                if let Ok(id) = tree.lookup_handle(view.into()) {
                    tree.set_fullscreen(id, toggle)
                        .expect("The ID was related to a non-view, somehow!");
                    match tree.container_in_active_workspace(id) {
                        Ok(true) => {
                            tree.layout_active_of(ContainerType::Workspace)
                                .unwrap_or_else(|err| {
                                    warn!("Could not layout active workspace \
                                           for view {:?}: {:?}",
                                            view, err)
                                });
                        },
                        Ok(false) => {},
                        Err(err) => warn!("Could not set {:?} fullscreen: {:?}",
                                           view, err)
                    }
                } else {
                    warn!("Could not find view {:?} in tree", view);
                }
            }
        }
    }

    fn view_request_move(&mut self, view: WlcView, _dest: Point) {
        if let Ok(mut tree) = try_lock_tree() {
            if let Err(err) = tree.set_active_view(view) {
                warn!("view_request_move error: {:?}", err);
            }
        }
    }

    fn view_request_resize(&mut self, view: WlcView, edge: ResizeEdge, point: Point) {
        if let Ok(mut tree) = try_lock_tree() {
            let in_action = try_lock_action()
                .map(|action| action.is_some())
                .unwrap_or(false);
            if in_action {
                if let Ok(id) = tree.lookup_handle(view.into()) {
                    if let Err(err) = tree.resize_container(id, edge, point) {
                        warn!("resize_container returned error: {:#?}",
                                err);
                    }
                }
            }
        }
    }

    fn on_keyboard_key(&mut self, _view: WlcView, _time: u32, mods: KeyboardModifiers,
                            key: u32, state: KeyState) -> bool {
        let empty_mods: KeyboardModifiers = KeyboardModifiers {
                mods: MOD_NONE,
                leds: KeyboardLed::empty()
        };
        let sym = keyboard::get_keysym_for_key(key, empty_mods);
        let press = KeyPress::new(mods.mods, sym);
        awesome::keygrabber_handle(mods, sym, state).unwrap_or_else(|err| {
            warn!("handling keygrabber returned error: {:#?}", err);
        });
        if state == KeyState::Pressed {
            if let Some(key) = keys::get(&press) {
                info!("[key] Found an action for {}, blocking event", press);
                let action = key.event;
                let passthrough = key.passthrough;
                match action {
                    KeyEvent::Command(func) => {
                        func();
                    },
                    KeyEvent::Lua => {
                        match lua::send(LuaQuery::HandleKey(press)) {
                            Ok(_) => {},
                            Err(err) => {
                                // We may want to wait for Lua's reply from
                                // keypresses; for example if the table is tampered
                                // with or Lua is restarted or Lua has an error.
                                // ATM Lua asynchronously logs this but in the future
                                // an error popup/etc is a good idea.
                                warn!("Error sending keypress: {:?}", err);
                            }
                        }
                    }
                }
                return !passthrough
            }
        }

        return EVENT_PASS_THROUGH
    }

    fn view_request_geometry(&mut self, view: WlcView, geometry: Geometry) {
        let unmanaged = view.get_type().intersects(VIEW_BIT_UNMANAGED);
        if geometry.size.w < MIN_SIZE.w && geometry.size.h < MIN_SIZE.h && !unmanaged {
            warn!("Ignoring requested geometry {:#?}, which is below min {:#?}",
                  geometry, MIN_SIZE);
            return;
        }
        if let Ok(mut tree) = try_lock_tree() {
            match tree.update_floating_geometry(view, geometry) {
                Ok(()) | Err(TreeError::ViewNotFound(_)) => {},
                err => warn!("Could not find view {:#?} \
                              in order to update geometry w/ {:#?} \
                              because of {:#?}",
                             view, geometry, err)
            }
        }
    }

    fn on_pointer_button(&mut self, view: WlcView, _time: u32,
                            mods: KeyboardModifiers, button: u32,
                                state: ButtonState, point: Point) -> bool {
        if state == ButtonState::Pressed {
            let mouse_mod = keys::mouse_modifier();
            if button == LEFT_CLICK && !view.is_root() {
                if let Ok(mut tree) = try_lock_tree() {
                    tree.set_active_view(view).unwrap_or_else(|_| {
                        // still focus on view, even if not in tree.
                        view.focus();
                    });
                    if mods.mods.contains(mouse_mod) {
                        let action = Action {
                            view: view,
                            grab: point,
                            edges: ResizeEdge::empty()
                        };
                        set_performing_action(Some(action));
                    }
                }
            } else if button == RIGHT_CLICK && !view.is_root() {
                info!("User right clicked w/ mods \"{:?}\" on {:?}", mods, view);
                if let Ok(mut tree) = try_lock_tree() {
                    tree.set_active_view(view).ok();
                }
                if mods.mods.contains(mouse_mod) {
                    let action = Action {
                        view: view,
                        grab: point,
                        edges: ResizeEdge::empty()
                    };
                    set_performing_action(Some(action));
                    let geometry = view.get_geometry()
                        .expect("Could not get geometry of the view");
                    let halfw = geometry.origin.x + geometry.size.w as i32 / 2;
                    let halfh = geometry.origin.y + geometry.size.h as i32 / 2;

                    {
                        let mut action: Action = try_lock_action().ok().and_then(|guard| *guard)
                            .unwrap_or(Action {
                                view: view,
                                grab: point,
                                edges: ResizeEdge::empty()
                            });
                        let flag_x = if point.x < halfw {
                            RESIZE_LEFT
                        } else if point.x > halfw {
                            RESIZE_RIGHT
                        } else {
                            ResizeEdge::empty()
                        };

                        let flag_y = if point.y < halfh {
                            RESIZE_TOP
                        } else if point.y > halfh {
                            RESIZE_BOTTOM
                        } else {
                            ResizeEdge::empty()
                        };

                        action.edges = flag_x | flag_y;
                        set_performing_action(Some(action));
                    }
                    view.set_state(VIEW_RESIZING, true);
                    return EVENT_BLOCKED
                }
            }
        } else {
            if let Ok(lock) = try_lock_action() {
                match *lock {
                    Some(action) => {
                        let view = action.view;
                        if view.get_state().contains(VIEW_RESIZING) {
                            view.set_state(VIEW_RESIZING, false);
                        }
                    },
                    _ => {}
                }
            }
            set_performing_action(None);
        }
        EVENT_PASS_THROUGH
    }

    fn on_pointer_scroll(&mut self, _view: WlcView, _time: u32,
                            _mods_ptr: KeyboardModifiers, _axis: ScrollAxis,
                            _heights: [f64; 2]) -> bool {
        EVENT_PASS_THROUGH
    }

    fn on_pointer_motion(&mut self, view: WlcView, _time: u32, point: Point) -> bool {
        let mut result = EVENT_PASS_THROUGH;
        let mut maybe_action = None;
        {
            if let Ok(action_lock) = try_lock_action() {
                maybe_action = action_lock.clone();
            }
        }
        match maybe_action {
            None => result = EVENT_PASS_THROUGH,
            Some(action) => {
                if action.edges.bits() != 0 {
                    if let Ok(mut tree) = try_lock_tree() {
                        if let Ok(active_id) = tree.lookup_handle(view.into()) {
                            match tree.resize_container(active_id, action.edges, point) {
                                // Return early here to not set the pointer
                                Ok(_) => return EVENT_BLOCKED,
                                Err(err) => warn!("Could not resize: {:#?}", err)
                            }
                        }
                    }
                } else {
                    if let Ok(mut tree) = try_lock_tree() {
                        match tree.try_drag_active(point) {
                            Ok(_) => result = EVENT_BLOCKED,
                            Err(TreeError::PerformingAction(_)) |
                            Err(TreeError::Movement(MovementError::NotFloating(_))) =>
                                result = EVENT_PASS_THROUGH,
                            Err(err) => {
                                warn!("Unexpected drarg error: {:#?}", err);
                                result = EVENT_PASS_THROUGH
                            }
                        }
                    }
                }
            }
        }
        pointer::set_position(point);
        result
    }

    fn view_pre_render(&mut self, view: WlcView) {
        if let Ok(mut tree) = lock_tree() {
            tree.render_borders(view).unwrap_or_else(|err| {
                match err {
                    // TODO Only filter if background or bar
                    TreeError::ViewNotFound(_) => {},
                    err => warn!("Error while rendering borders: {:?}", err)
                }
            })
        }
    }
}
<commit_msg>Fixed tests failing due to move<commit_after>//! Implementations of the default callbacks exposed by wlc.
//! These functions are the main entry points into Way Cooler from user action.
//! This is the default mode that Way Cooler is in at initilization
use rustwlc::*;
use rustwlc::input::{pointer, keyboard};
use rustwlc::render::{read_pixels, wlc_pixel_format};
use uuid::Uuid;

use super::{EVENT_BLOCKED, EVENT_PASS_THROUGH, LEFT_CLICK, RIGHT_CLICK};
use ::keys::{self, KeyPress, KeyEvent};
use ::layout::{lock_tree, try_lock_tree, try_lock_action, Action, ContainerType,
                    MovementError, TreeError, FocusError};
use ::layout::commands::set_performing_action;
use ::layout::MIN_SIZE;
use ::lua::{self, LuaQuery};

use ::render::screen_scrape::{read_screen_scrape_lock, scraped_pixels_lock,
                              sync_scrape};
use ::awesome;

use registry::{self};
use super::Mode;

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Default;

#[allow(unused)]
impl Mode for Default {
    fn output_created(&mut self, output: WlcOutput) -> bool {
        if let Ok(mut tree) = try_lock_tree() {
            let result = tree.add_output(output).and_then(|_|{
                tree.switch_to_workspace(&"1")
                    .map(|_| tree.layout_active_of(ContainerType::Output))
            });
            match result {
                // If the output exists, we just couldn't add it to the tree because
                // it's already there. That's OK
                Ok(_) | Err(TreeError::OutputExists(_)) => true,
                _ => false
            }
        } else {
            false
        }
    }

    fn output_destroyed(&mut self, output: WlcOutput) {
         // TODO Redistribute workspaces of that output.
    }

    fn output_focused(&mut self, output: WlcOutput, focused: bool) {
         // TODO Ensure focused on right workspace
    }

    fn output_resolution(&mut self, output: WlcOutput,
                                    old_size_ptr: Size, new_size_ptr: Size) {
        // Update the resolution of the output and its children
        let scale = 1;
        output.set_resolution(new_size_ptr, scale);
        if let Ok(mut tree) = try_lock_tree() {
            tree.layout_active_of(ContainerType::Output)
                .expect("Could not layout active output");
        }
    }

    fn output_render_post(&mut self, output: WlcOutput) {
        let need_to_fetch = read_screen_scrape_lock();
        if *need_to_fetch {
            if WlcOutput::focused() != output {
                return
            }
            if let Ok(mut scraped_pixels) = scraped_pixels_lock() {
                let resolution = output.get_resolution()
                    .expect("Output had no resolution");
                let geo = Geometry {
                    origin: Point { x: 0, y: 0 },
                    size: resolution
                };
                let result = read_pixels(wlc_pixel_format::WLC_RGBA8888, geo).1;
                *scraped_pixels = result;
                sync_scrape();
            }
        }
    }

    fn view_created(&mut self, view: WlcView) -> bool {
        let lock = registry::clients_read();
        let client = lock.client(Uuid::nil()).unwrap();
        let handle = registry::ReadHandle::new(&client);
        let bar = handle.read("programs".into())
            .expect("programs category didn't exist")
            .get("x11_bar".into())
            .and_then(|data| data.as_string().map(str::to_string));
        // TODO Move this hack, probably could live somewhere else
        if let Some(bar_name) = bar {
            if view.get_title().as_str() == bar_name {
                view.set_mask(1);
                view.bring_to_front();
                if let Ok(mut tree) = try_lock_tree() {
                    let output = WlcOutput::focused();
                    tree.add_bar(view, output).unwrap_or_else(|_| {
                        warn!("Could not add bar {:#?} to output {:#?}", view, output);
                    });
                    return true;
                }
            }
        }
        // TODO Remove this hack
        if view.get_class().as_str() == "Background" {
            trace!("Setting background: {}", view.get_title());
            view.send_to_back();
            view.set_mask(1);
            let output = view.get_output();
            let resolution = output.get_resolution()
                .expect("Couldn't get output resolution");
            let fullscreen = Geometry {
                origin: Point { x: 0, y: 0 },
                size: resolution
            };
            view.set_geometry(ResizeEdge::empty(), fullscreen);
            if let Ok(mut tree) = lock_tree() {
                let output = WlcOutput::focused();
                return tree.add_background(view, output).map(|_| true)
                    .unwrap_or_else(|err| {
                        warn!("Could not add background due to {:?}", err);
                        true
                    })
            } else {
                warn!("Could not lock tree to place background");
            }
            return false
        }
        if let Ok(mut tree) = lock_tree() {
            let result = tree.add_view(view).and_then(|_| {
                view.set_state(VIEW_MAXIMIZED, true);
                match tree.set_active_view(view) {
                    // If blocked by fullscreen, we don't focus on purpose
                    Err(TreeError::Focus(FocusError::BlockedByFullscreen(_, _))) => Ok(()),
                    result => result
                }
            });
            if result.is_err() {
                warn!("Could not add {:?}. Reason: {:?}", view, result);
            }
            result.is_ok()
        } else {
            false
        }
    }

    fn view_destroyed(&mut self, view: WlcView) {
        match try_lock_tree() {
            Ok(mut tree) => {
                tree.remove_view(view).unwrap_or_else(|err| {
                    match err {
                        TreeError::ViewNotFound(_) => {},
                        _ => {
                            warn!("Error in view_destroyed: {:?}", err);
                        }
                    }});
            },
            Err(err) => warn!("Could not delete view {:?}, {:?}", view, err)
        }
    }

    fn view_focused(&mut self, current: WlcView, focused: bool) {
        current.set_state(VIEW_ACTIVATED, focused);
        if let Ok(mut tree) = try_lock_tree() {
            match tree.set_active_view(current) {
                Ok(_) => {},
                Err(err) => {
                    warn!("Could not set {:?} to be active view: {:?}", current, err);
                }
            }
        }
    }

    fn view_props_changed(&mut self, view: WlcView, prop: ViewPropertyType) {
        if prop.contains(PROPERTY_TITLE) {
            if let Ok(mut tree) = try_lock_tree() {
                match tree.update_title(view) {
                    Ok(_) => {},
                    Err(err) => {
                        warn!("Could not update title for view {:?} because {:#?}",
                            view, err);
                    }
                }
            }
        }
    }

    fn view_moved_to_output(&mut self, view: WlcView, o1: WlcOutput, o2: WlcOutput) {
        // TODO Ensure in correct workspace
    }

    fn view_request_state(&mut self, view: WlcView, state: ViewState, toggle: bool) {
        if state == VIEW_FULLSCREEN {
            if let Ok(mut tree) = try_lock_tree() {
                if let Ok(id) = tree.lookup_handle(view.into()) {
                    tree.set_fullscreen(id, toggle)
                        .expect("The ID was related to a non-view, somehow!");
                    match tree.container_in_active_workspace(id) {
                        Ok(true) => {
                            tree.layout_active_of(ContainerType::Workspace)
                                .unwrap_or_else(|err| {
                                    warn!("Could not layout active workspace \
                                           for view {:?}: {:?}",
                                            view, err)
                                });
                        },
                        Ok(false) => {},
                        Err(err) => warn!("Could not set {:?} fullscreen: {:?}",
                                           view, err)
                    }
                } else {
                    warn!("Could not find view {:?} in tree", view);
                }
            }
        }
    }

    fn view_request_move(&mut self, view: WlcView, _dest: Point) {
        if let Ok(mut tree) = try_lock_tree() {
            if let Err(err) = tree.set_active_view(view) {
                warn!("view_request_move error: {:?}", err);
            }
        }
    }

    fn view_request_resize(&mut self, view: WlcView, edge: ResizeEdge, point: Point) {
        if let Ok(mut tree) = try_lock_tree() {
            let in_action = try_lock_action()
                .map(|action| action.is_some())
                .unwrap_or(false);
            if in_action {
                if let Ok(id) = tree.lookup_handle(view.into()) {
                    if let Err(err) = tree.resize_container(id, edge, point) {
                        warn!("resize_container returned error: {:#?}",
                                err);
                    }
                }
            }
        }
    }

    fn on_keyboard_key(&mut self, _view: WlcView, _time: u32, mods: KeyboardModifiers,
                            key: u32, state: KeyState) -> bool {
        let empty_mods: KeyboardModifiers = KeyboardModifiers {
                mods: MOD_NONE,
                leds: KeyboardLed::empty()
        };
        let sym = keyboard::get_keysym_for_key(key, empty_mods);
        let press = KeyPress::new(mods.mods, sym.clone());
        awesome::keygrabber_handle(mods, sym, state).unwrap_or_else(|err| {
            warn!("handling keygrabber returned error: {:#?}", err);
        });
        if state == KeyState::Pressed {
            if let Some(key) = keys::get(&press) {
                info!("[key] Found an action for {}, blocking event", press);
                let action = key.event;
                let passthrough = key.passthrough;
                match action {
                    KeyEvent::Command(func) => {
                        func();
                    },
                    KeyEvent::Lua => {
                        match lua::send(LuaQuery::HandleKey(press)) {
                            Ok(_) => {},
                            Err(err) => {
                                // We may want to wait for Lua's reply from
                                // keypresses; for example if the table is tampered
                                // with or Lua is restarted or Lua has an error.
                                // ATM Lua asynchronously logs this but in the future
                                // an error popup/etc is a good idea.
                                warn!("Error sending keypress: {:?}", err);
                            }
                        }
                    }
                }
                return !passthrough
            }
        }

        return EVENT_PASS_THROUGH
    }

    fn view_request_geometry(&mut self, view: WlcView, geometry: Geometry) {
        let unmanaged = view.get_type().intersects(VIEW_BIT_UNMANAGED);
        if geometry.size.w < MIN_SIZE.w && geometry.size.h < MIN_SIZE.h && !unmanaged {
            warn!("Ignoring requested geometry {:#?}, which is below min {:#?}",
                  geometry, MIN_SIZE);
            return;
        }
        if let Ok(mut tree) = try_lock_tree() {
            match tree.update_floating_geometry(view, geometry) {
                Ok(()) | Err(TreeError::ViewNotFound(_)) => {},
                err => warn!("Could not find view {:#?} \
                              in order to update geometry w/ {:#?} \
                              because of {:#?}",
                             view, geometry, err)
            }
        }
    }

    fn on_pointer_button(&mut self, view: WlcView, _time: u32,
                            mods: KeyboardModifiers, button: u32,
                                state: ButtonState, point: Point) -> bool {
        if state == ButtonState::Pressed {
            let mouse_mod = keys::mouse_modifier();
            if button == LEFT_CLICK && !view.is_root() {
                if let Ok(mut tree) = try_lock_tree() {
                    tree.set_active_view(view).unwrap_or_else(|_| {
                        // still focus on view, even if not in tree.
                        view.focus();
                    });
                    if mods.mods.contains(mouse_mod) {
                        let action = Action {
                            view: view,
                            grab: point,
                            edges: ResizeEdge::empty()
                        };
                        set_performing_action(Some(action));
                    }
                }
            } else if button == RIGHT_CLICK && !view.is_root() {
                info!("User right clicked w/ mods \"{:?}\" on {:?}", mods, view);
                if let Ok(mut tree) = try_lock_tree() {
                    tree.set_active_view(view).ok();
                }
                if mods.mods.contains(mouse_mod) {
                    let action = Action {
                        view: view,
                        grab: point,
                        edges: ResizeEdge::empty()
                    };
                    set_performing_action(Some(action));
                    let geometry = view.get_geometry()
                        .expect("Could not get geometry of the view");
                    let halfw = geometry.origin.x + geometry.size.w as i32 / 2;
                    let halfh = geometry.origin.y + geometry.size.h as i32 / 2;

                    {
                        let mut action: Action = try_lock_action().ok().and_then(|guard| *guard)
                            .unwrap_or(Action {
                                view: view,
                                grab: point,
                                edges: ResizeEdge::empty()
                            });
                        let flag_x = if point.x < halfw {
                            RESIZE_LEFT
                        } else if point.x > halfw {
                            RESIZE_RIGHT
                        } else {
                            ResizeEdge::empty()
                        };

                        let flag_y = if point.y < halfh {
                            RESIZE_TOP
                        } else if point.y > halfh {
                            RESIZE_BOTTOM
                        } else {
                            ResizeEdge::empty()
                        };

                        action.edges = flag_x | flag_y;
                        set_performing_action(Some(action));
                    }
                    view.set_state(VIEW_RESIZING, true);
                    return EVENT_BLOCKED
                }
            }
        } else {
            if let Ok(lock) = try_lock_action() {
                match *lock {
                    Some(action) => {
                        let view = action.view;
                        if view.get_state().contains(VIEW_RESIZING) {
                            view.set_state(VIEW_RESIZING, false);
                        }
                    },
                    _ => {}
                }
            }
            set_performing_action(None);
        }
        EVENT_PASS_THROUGH
    }

    fn on_pointer_scroll(&mut self, _view: WlcView, _time: u32,
                            _mods_ptr: KeyboardModifiers, _axis: ScrollAxis,
                            _heights: [f64; 2]) -> bool {
        EVENT_PASS_THROUGH
    }

    fn on_pointer_motion(&mut self, view: WlcView, _time: u32, point: Point) -> bool {
        let mut result = EVENT_PASS_THROUGH;
        let mut maybe_action = None;
        {
            if let Ok(action_lock) = try_lock_action() {
                maybe_action = action_lock.clone();
            }
        }
        match maybe_action {
            None => result = EVENT_PASS_THROUGH,
            Some(action) => {
                if action.edges.bits() != 0 {
                    if let Ok(mut tree) = try_lock_tree() {
                        if let Ok(active_id) = tree.lookup_handle(view.into()) {
                            match tree.resize_container(active_id, action.edges, point) {
                                // Return early here to not set the pointer
                                Ok(_) => return EVENT_BLOCKED,
                                Err(err) => warn!("Could not resize: {:#?}", err)
                            }
                        }
                    }
                } else {
                    if let Ok(mut tree) = try_lock_tree() {
                        match tree.try_drag_active(point) {
                            Ok(_) => result = EVENT_BLOCKED,
                            Err(TreeError::PerformingAction(_)) |
                            Err(TreeError::Movement(MovementError::NotFloating(_))) =>
                                result = EVENT_PASS_THROUGH,
                            Err(err) => {
                                warn!("Unexpected drarg error: {:#?}", err);
                                result = EVENT_PASS_THROUGH
                            }
                        }
                    }
                }
            }
        }
        pointer::set_position(point);
        result
    }

    fn view_pre_render(&mut self, view: WlcView) {
        if let Ok(mut tree) = lock_tree() {
            tree.render_borders(view).unwrap_or_else(|err| {
                match err {
                    // TODO Only filter if background or bar
                    TreeError::ViewNotFound(_) => {},
                    err => warn!("Error while rendering borders: {:?}", err)
                }
            })
        }
    }
}
<|endoftext|>


<commit_before>use pulldown_cmark::{html, CodeBlockKind, Event, Options, Parser, Tag};
use syntect::html::{ClassStyle, ClassedHTMLGenerator};
use syntect::parsing::SyntaxSet;

use super::Preprocessed;

enum ParseState<'a> {
    NotInCodeBlock,
    RequiresFirstLineParse,
    UnknownSyntax,
    KnownSyntax(ClassedHTMLGenerator<'a>),
}

/// The result of rendering the content.
pub struct Processed(pub(super) String);

pub(super) fn render_markdown(
    src: Preprocessed,
    syntax_set: &SyntaxSet,
) -> Result<Processed, String> {
    let src = src.as_str();
    let parser = Parser::new_ext(src, Options::all());
    let mut state = ParseState::NotInCodeBlock;

    let mut events = Vec::<Event>::with_capacity(src.len() * 2);
    for event in parser {
        match event {
            Event::Text(text) => match &mut state {
                // This is a little quirky: it hands off the text to the highlighter
                // and relies on correctly calling `highlighter.finalize()` when we
                // reach the end of the code block.
                ParseState::KnownSyntax(ref mut generator) => {
                    generator.parse_html_for_line_which_includes_newline(text.as_ref());
                    events.push(Event::Text("".into()));
                }
                // This has the same constraint as `KnownSyntax`, but requires that
                // we also try to get a
                ParseState::RequiresFirstLineParse => {
                    match syntax_set.find_syntax_by_first_line(&text) {
                        Some(definition) => {
                            let mut generator = ClassedHTMLGenerator::new_with_class_style(
                                definition,
                                &syntax_set,
                                ClassStyle::Spaced,
                            );
                            events.push(Event::Html(
                                format!("
", definition.name).into(),
                            ));
                            generator.parse_html_for_line_which_includes_newline(&text);
                            state = ParseState::KnownSyntax(generator);
                            events.push(Event::Text("".into()));
                        }
                        None => {
                            state = ParseState::UnknownSyntax;
                            events.push(Event::Text(text));
                        }
                    }
                }
                ParseState::UnknownSyntax | ParseState::NotInCodeBlock => {
                    events.push(Event::Text(text))
                }
            },
            Event::Start(Tag::CodeBlock(CodeBlockKind::Fenced(name))) => {
                if let Some(looked_up) = syntax_set.find_syntax_by_token(name.as_ref()) {
                    state = ParseState::KnownSyntax(ClassedHTMLGenerator::new_with_class_style(
                        looked_up,
                        &syntax_set,
                        ClassStyle::Spaced,
                    ));
                    let html = format!("
", looked_up.name);
                    events.push(Event::Html(html.into()));
                } else {
                    state = ParseState::UnknownSyntax;
                    events.push(Event::Html("
".into()));
                }
            }
            Event::Start(Tag::CodeBlock(CodeBlockKind::Indented)) => match state {
                ParseState::NotInCodeBlock => {
                    state = ParseState::RequiresFirstLineParse;
                }
                _ => {
                    unreachable!("should never be entering a codeblock when already in a codeblock")
                }
            },
            Event::End(Tag::CodeBlock(_)) => match state {
                ParseState::KnownSyntax(generator) => {
                    let highlighted = generator.finalize();
                    state = ParseState::NotInCodeBlock;
                    events.push(Event::Html((highlighted + "
").into()));
                }
                ParseState::UnknownSyntax | ParseState::RequiresFirstLineParse => {
                    state = ParseState::NotInCodeBlock;
                    events.push(Event::Html("
".into()));
                }
                ParseState::NotInCodeBlock => {
                    unreachable!("Cannot *not* be in a code block when ending a coceblock")
                }
            },
            _ => events.push(event),
        }
    }

    let mut html_output = String::with_capacity(src.len() * 2);

    html::push_html(&mut html_output, events.into_iter());

    Ok(Processed(html_output))
}
<commit_msg>Markdown: improve highlighting<commit_after>use pulldown_cmark::{html, CodeBlockKind, Event, Options, Parser, Tag};
use syntect::html::{ClassStyle, ClassedHTMLGenerator};
use syntect::parsing::SyntaxSet;

use super::Preprocessed;

enum ParseState<'a> {
    NotInCodeBlock,
    RequiresFirstLineParse,
    UnknownSyntax,
    KnownSyntax(ClassedHTMLGenerator<'a>),
}

/// The result of rendering the content.
pub struct Processed(pub(super) String);

pub(super) fn render_markdown(
    src: Preprocessed,
    syntax_set: &SyntaxSet,
) -> Result<Processed, String> {
    let src = src.as_str();
    let parser = Parser::new_ext(src, Options::all());
    let mut state = ParseState::NotInCodeBlock;

    let mut events = Vec::<Event>::with_capacity(src.len() * 2);
    for event in parser {
        match event {
            Event::Text(text) => match &mut state {
                // This is a little quirky: it hands off the text to the highlighter
                // and relies on correctly calling `highlighter.finalize()` when we
                // reach the end of the code block.
                ParseState::KnownSyntax(ref mut generator) => {
                    generator.parse_html_for_line_which_includes_newline(text.as_ref());
                    events.push(Event::Text("".into()));
                }
                // This has the same constraint as `KnownSyntax`, but requires that
                // we also try to get a
                ParseState::RequiresFirstLineParse => {
                    match syntax_set.find_syntax_by_first_line(&text) {
                        Some(definition) => {
                            let mut generator = ClassedHTMLGenerator::new_with_class_style(
                                definition,
                                &syntax_set,
                                ClassStyle::Spaced,
                            );
                            events.push(Event::Html(
                                format!(
                                    "
",
                                    name = definition.name
                                )
                                .into(),
                            ));
                            generator.parse_html_for_line_which_includes_newline(&text);
                            state = ParseState::KnownSyntax(generator);
                            events.push(Event::Text("".into()));
                        }
                        None => {
                            events.push(Event::Html("
".to_string().into()));
                            state = ParseState::UnknownSyntax;
                            events.push(Event::Text(text));
                        }
                    }
                }
                ParseState::UnknownSyntax | ParseState::NotInCodeBlock => {
                    events.push(Event::Text(text))
                }
            },
            Event::Start(Tag::CodeBlock(CodeBlockKind::Fenced(name))) => {
                if let Some(looked_up) = syntax_set.find_syntax_by_token(name.as_ref()) {
                    state = ParseState::KnownSyntax(ClassedHTMLGenerator::new_with_class_style(
                        looked_up,
                        &syntax_set,
                        ClassStyle::Spaced,
                    ));
                    let html = format!("
", looked_up.name);
                    events.push(Event::Html(html.into()));
                } else {
                    state = ParseState::UnknownSyntax;
                    events.push(Event::Html("
".into()));
                }
            }
            Event::Start(Tag::CodeBlock(CodeBlockKind::Indented)) => match state {
                ParseState::NotInCodeBlock => {
                    state = ParseState::RequiresFirstLineParse;
                }
                _ => {
                    unreachable!("should never be entering a codeblock when already in a codeblock")
                }
            },
            Event::End(Tag::CodeBlock(_)) => match state {
                ParseState::KnownSyntax(generator) => {
                    let highlighted = generator.finalize();
                    state = ParseState::NotInCodeBlock;
                    events.push(Event::Html((highlighted + "
").into()));
                }
                ParseState::UnknownSyntax | ParseState::RequiresFirstLineParse => {
                    state = ParseState::NotInCodeBlock;
                    events.push(Event::Html("
".into()));
                }
                ParseState::NotInCodeBlock => {
                    unreachable!("Cannot *not* be in a code block when ending a code block")
                }
            },
            _ => events.push(event),
        }
    }

    let mut html_output = String::with_capacity(src.len() * 2);

    html::push_html(&mut html_output, events.into_iter());

    Ok(Processed(html_output))
}
<|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/. */

use aabbtree::AABBTreeNode;
use app_units::Au;
use batch_builder;
use euclid::{Rect, Size2D};
use fnv::FnvHasher;
use internal_types::{BorderRadiusRasterOp, BoxShadowRasterOp, DrawListItemIndex};
use internal_types::{Glyph, GlyphKey, RasterItem, DevicePixel};
use resource_cache::ResourceCache;
use std::collections::{HashMap, HashSet};
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::hash::BuildHasherDefault;
use tessellator;
use webrender_traits::{AuxiliaryLists, BorderRadius, BorderStyle, BoxShadowClipMode};
use webrender_traits::{FontKey, ImageFormat, ImageKey, ImageRendering, PipelineId};
use webrender_traits::{SpecificDisplayItem};

type RequiredImageSet = HashSet<(ImageKey, ImageRendering), BuildHasherDefault<FnvHasher>>;
type RequiredGlyphMap = HashMap<FontKey, HashSet<Glyph>, BuildHasherDefault<FnvHasher>>;
type RequiredRasterSet = HashSet<RasterItem, BuildHasherDefault<FnvHasher>>;

pub struct ResourceList {
    required_images: RequiredImageSet,
    required_glyphs: RequiredGlyphMap,
    required_rasters: RequiredRasterSet,
    device_pixel_ratio: f32,
}

impl ResourceList {
    pub fn new(device_pixel_ratio: f32) -> ResourceList {
        ResourceList {
            required_glyphs: HashMap::with_hasher(Default::default()),
            required_images: HashSet::with_hasher(Default::default()),
            required_rasters: HashSet::with_hasher(Default::default()),
            device_pixel_ratio: device_pixel_ratio,
        }
    }

    pub fn add_image(&mut self,
                     key: ImageKey,
                     image_rendering: ImageRendering) {
        self.required_images.insert((key, image_rendering));
    }

    pub fn add_glyph(&mut self, font_key: FontKey, glyph: Glyph) {
        match self.required_glyphs.entry(font_key) {
            Occupied(entry) => {
                entry.into_mut().insert(glyph);
            }
            Vacant(entry) => {
                let mut hash_set = HashSet::new();
                hash_set.insert(glyph);
                entry.insert(hash_set);
            }
        }
    }

    pub fn add_radius_raster(&mut self,
                             outer_radius: &Size2D<f32>,
                             inner_radius: &Size2D<f32>,
                             inverted: bool,
                             index: Option<u32>,
                             image_format: ImageFormat) {
        let outer_radius_x = DevicePixel::new(outer_radius.width, self.device_pixel_ratio);
        let outer_radius_y = DevicePixel::new(outer_radius.height, self.device_pixel_ratio);
        let inner_radius_x = DevicePixel::new(inner_radius.width, self.device_pixel_ratio);
        let inner_radius_y = DevicePixel::new(inner_radius.height, self.device_pixel_ratio);
        if let Some(raster_item) = BorderRadiusRasterOp::create(outer_radius_x,
                                                                outer_radius_y,
                                                                inner_radius_x,
                                                                inner_radius_y,
                                                                inverted,
                                                                index,
                                                                image_format) {
            self.required_rasters.insert(RasterItem::BorderRadius(raster_item));
        }
    }

    /// NB: Only adds non-tessellated border radii.
    pub fn add_radius_raster_for_border_radii(&mut self, radii: &BorderRadius) {
        let zero_size = Size2D::new(0.0, 0.0);
        self.add_radius_raster(&radii.top_left, &zero_size, false, None, ImageFormat::A8);
        self.add_radius_raster(&radii.top_right, &zero_size, false, None, ImageFormat::A8);
        self.add_radius_raster(&radii.bottom_left, &zero_size, false, None, ImageFormat::A8);
        self.add_radius_raster(&radii.bottom_right, &zero_size, false, None, ImageFormat::A8);
    }

    pub fn add_box_shadow_corner(&mut self,
                                 blur_radius: f32,
                                 border_radius: f32,
                                 box_rect: &Rect<f32>,
                                 inverted: bool) {
        if let Some(raster_item) = BoxShadowRasterOp::create_corner(blur_radius,
                                                                    border_radius,
                                                                    box_rect,
                                                                    inverted,
                                                                    self.device_pixel_ratio) {
            self.required_rasters.insert(RasterItem::BoxShadow(raster_item));
        }
    }

    pub fn add_box_shadow_edge(&mut self,
                               blur_radius: f32,
                               border_radius: f32,
                               box_rect: &Rect<f32>,
                               inverted: bool) {
        if let Some(raster_item) = BoxShadowRasterOp::create_edge(blur_radius,
                                                                  border_radius,
                                                                  box_rect,
                                                                  inverted,
                                                                  self.device_pixel_ratio) {
            self.required_rasters.insert(RasterItem::BoxShadow(raster_item));
        }
    }

    pub fn for_each_image<F>(&self, mut f: F) where F: FnMut(ImageKey, ImageRendering) {
        for &(image_id, image_rendering) in &self.required_images {
            f(image_id, image_rendering);
        }
    }

    pub fn for_each_raster<F>(&self, mut f: F) where F: FnMut(&RasterItem) {
        for raster_item in &self.required_rasters {
            f(raster_item);
        }
    }

    pub fn for_each_glyph<F>(&self, mut f: F) where F: FnMut(&GlyphKey) {
        for (font_id, glyphs) in &self.required_glyphs {
            let mut glyph_key = GlyphKey::new(font_id.clone(), Au(0), Au(0), 0);

            for glyph in glyphs {
                glyph_key.size = glyph.size;
                glyph_key.index = glyph.index;
                glyph_key.blur_radius = glyph.blur_radius;

                f(&glyph_key);
            }
        }
    }
}

pub trait BuildRequiredResources {
    fn build_resource_list(&mut self,
                           resource_cache: &ResourceCache,
                           pipeline_auxiliary_lists: &HashMap<PipelineId,
                                                              AuxiliaryLists,
                                                              BuildHasherDefault<FnvHasher>>);
}

impl BuildRequiredResources for AABBTreeNode {
    fn build_resource_list(&mut self,
                           resource_cache: &ResourceCache,
                           pipeline_auxiliary_lists: &HashMap<PipelineId,
                                                              AuxiliaryLists,
                                                              BuildHasherDefault<FnvHasher>>) {
        //let _pf = util::ProfileScope::new("  build_resource_list");
        let mut resource_list = ResourceList::new(resource_cache.device_pixel_ratio());

        for group in &self.draw_list_group_segments {
            for draw_list_index_buffer in &group.index_buffers {
                let draw_list = resource_cache.get_draw_list(draw_list_index_buffer.draw_list_id);

                for index in &draw_list_index_buffer.indices {
                    let DrawListItemIndex(index) = *index;
                    let display_item = &draw_list.items[index as usize];
                    let auxiliary_lists =
                        pipeline_auxiliary_lists.get(&draw_list.pipeline_id)
                                                .expect("No auxiliary lists for pipeline?!");

                    // Handle border radius for complex clipping regions.
                    for complex_clip_region in
                            auxiliary_lists.complex_clip_regions(&display_item.clip.complex) {
                        resource_list.add_radius_raster_for_border_radii(
                            &complex_clip_region.radii);
                    }

                    match display_item.item {
                        SpecificDisplayItem::Image(ref info) => {
                            resource_list.add_image(info.image_key, info.image_rendering);
                        }
                        SpecificDisplayItem::Text(ref info) => {
                            let glyphs = auxiliary_lists.glyph_instances(&info.glyphs);
                            for glyph in glyphs {
                                let glyph = Glyph::new(info.size, info.blur_radius, glyph.index);
                                resource_list.add_glyph(info.font_key, glyph);
                            }
                        }
                        SpecificDisplayItem::WebGL(..) => {}
                        SpecificDisplayItem::Rectangle(..) => {}
                        SpecificDisplayItem::Gradient(..) => {}
                        SpecificDisplayItem::BoxShadow(ref info) => {
                            resource_list.add_radius_raster_for_border_radii(
                                &BorderRadius::uniform(info.border_radius));

                            let box_rect = batch_builder::compute_box_shadow_rect(&info.box_bounds,
                                                                                &info.offset,
                                                                                info.spread_radius,
                                                                                info.clip_mode);
                            resource_list.add_box_shadow_corner(info.blur_radius,
                                                                info.border_radius,
                                                                &box_rect,
                                                                false);
                            resource_list.add_box_shadow_edge(info.blur_radius,
                                                              info.border_radius,
                                                              &box_rect,
                                                              false);
                            if info.clip_mode == BoxShadowClipMode::Inset {
                                resource_list.add_box_shadow_corner(info.blur_radius,
                                                                    info.border_radius,
                                                                    &box_rect,
                                                                    true);
                                resource_list.add_box_shadow_edge(info.blur_radius,
                                                                  info.border_radius,
                                                                  &box_rect,
                                                                  true);
                            }
                        }
                        SpecificDisplayItem::Border(ref info) => {
                            let can_tessellate = tessellator::can_tessellate_border(info);
                            add_border_radius_raster(&info.radius.top_left,
                                                     &info.top_left_inner_radius(),
                                                     can_tessellate,
                                                     resource_cache,
                                                     &mut resource_list);
                            add_border_radius_raster(&info.radius.top_right,
                                                     &info.top_right_inner_radius(),
                                                     can_tessellate,
                                                     resource_cache,
                                                     &mut resource_list);
                            add_border_radius_raster(&info.radius.bottom_right,
                                                     &info.bottom_right_inner_radius(),
                                                     can_tessellate,
                                                     resource_cache,
                                                     &mut resource_list);
                            add_border_radius_raster(&info.radius.bottom_left,
                                                     &info.bottom_left_inner_radius(),
                                                     can_tessellate,
                                                     resource_cache,
                                                     &mut resource_list);

                            if info.top.style == BorderStyle::Dotted {
                                resource_list.add_radius_raster(&Size2D::new(info.top.width / 2.0,
                                                                             info.top.width / 2.0),
                                                                &Size2D::new(0.0, 0.0),
                                                                false,
                                                                None,
                                                                ImageFormat::RGBA8);
                            }
                            if info.right.style == BorderStyle::Dotted {
                                resource_list.add_radius_raster(&Size2D::new(info.right.width / 2.0,
                                                                             info.right.width / 2.0),
                                                                &Size2D::new(0.0, 0.0),
                                                                false,
                                                                None,
                                                                ImageFormat::RGBA8);
                            }
                            if info.bottom.style == BorderStyle::Dotted {
                                resource_list.add_radius_raster(&Size2D::new(info.bottom.width / 2.0,
                                                                             info.bottom.width / 2.0),
                                                                &Size2D::new(0.0, 0.0),
                                                                false,
                                                                None,
                                                                ImageFormat::RGBA8);
                            }
                            if info.left.style == BorderStyle::Dotted {
                                resource_list.add_radius_raster(&Size2D::new(info.left.width / 2.0,
                                                                             info.left.width / 2.0),
                                                                &Size2D::new(0.0, 0.0),
                                                                false,
                                                                None,
                                                                ImageFormat::RGBA8);
                            }

                            if info.top.style == BorderStyle::Double {
                                resource_list.add_radius_raster(&info.radius.top_left,
                                                                &Size2D::zero(),
                                                                false,
                                                                None,
                                                                ImageFormat::A8);

                                resource_list.add_radius_raster(&Size2D::zero(),
                                                                &info.top_left_inner_radius(),
                                                                false,
                                                                None,
                                                                ImageFormat::A8);
                            }
                            if info.right.style == BorderStyle::Double {
                                resource_list.add_radius_raster(&info.radius.top_right,
                                                                &Size2D::zero(),
                                                                false,
                                                                None,
                                                                ImageFormat::A8);

                                resource_list.add_radius_raster(&Size2D::zero(),
                                                                &info.top_right_inner_radius(),
                                                                false,
                                                                None,
                                                                ImageFormat::A8);
                            }
                            if info.bottom.style == BorderStyle::Double {
                                resource_list.add_radius_raster(&info.radius.bottom_left,
                                                                &Size2D::zero(),
                                                                false,
                                                                None,
                                                                ImageFormat::A8);

                                resource_list.add_radius_raster(&Size2D::zero(),
                                                                &info.bottom_left_inner_radius(),
                                                                false,
                                                                None,
                                                                ImageFormat::A8);
                            }
                            if info.left.style == BorderStyle::Double {
                                resource_list.add_radius_raster(&info.radius.bottom_right,
                                                                &Size2D::zero(),
                                                                false,
                                                                None,
                                                                ImageFormat::A8);

                                resource_list.add_radius_raster(&Size2D::zero(),
                                                                &info.bottom_right_inner_radius(),
                                                                false,
                                                                None,
                                                                ImageFormat::A8);
                            }

                        }
                    }
                }
            }
        }

        self.resource_list = Some(resource_list);
    }
}

fn add_border_radius_raster(outer_radius: &Size2D<f32>,
                            inner_radius: &Size2D<f32>,
                            can_tessellate: bool,
                            resource_cache: &ResourceCache,
                            resource_list: &mut ResourceList) {
    let quad_count = if can_tessellate {
        tessellator::quad_count_for_border_corner(outer_radius,
                                                  resource_cache.device_pixel_ratio())
    } else {
        1
    };
    for rect_index in 0..quad_count {
        let index = if can_tessellate {
            Some(rect_index)
        } else {
            None
        };
        resource_list.add_radius_raster(outer_radius,
                                        inner_radius,
                                        false,
                                        index,
                                        ImageFormat::A8);
    }
}

<commit_msg>bonus: Be more idiomatic on "add_glyph"<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/. */

use aabbtree::AABBTreeNode;
use app_units::Au;
use batch_builder;
use euclid::{Rect, Size2D};
use fnv::FnvHasher;
use internal_types::{BorderRadiusRasterOp, BoxShadowRasterOp, DrawListItemIndex};
use internal_types::{Glyph, GlyphKey, RasterItem, DevicePixel};
use resource_cache::ResourceCache;
use std::collections::{HashMap, HashSet};
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::hash::BuildHasherDefault;
use tessellator;
use webrender_traits::{AuxiliaryLists, BorderRadius, BorderStyle, BoxShadowClipMode};
use webrender_traits::{FontKey, ImageFormat, ImageKey, ImageRendering, PipelineId};
use webrender_traits::{SpecificDisplayItem};

type RequiredImageSet = HashSet<(ImageKey, ImageRendering), BuildHasherDefault<FnvHasher>>;
type RequiredGlyphMap = HashMap<FontKey, HashSet<Glyph>, BuildHasherDefault<FnvHasher>>;
type RequiredRasterSet = HashSet<RasterItem, BuildHasherDefault<FnvHasher>>;

pub struct ResourceList {
    required_images: RequiredImageSet,
    required_glyphs: RequiredGlyphMap,
    required_rasters: RequiredRasterSet,
    device_pixel_ratio: f32,
}

impl ResourceList {
    pub fn new(device_pixel_ratio: f32) -> ResourceList {
        ResourceList {
            required_glyphs: HashMap::with_hasher(Default::default()),
            required_images: HashSet::with_hasher(Default::default()),
            required_rasters: HashSet::with_hasher(Default::default()),
            device_pixel_ratio: device_pixel_ratio,
        }
    }

    pub fn add_image(&mut self,
                     key: ImageKey,
                     image_rendering: ImageRendering) {
        self.required_images.insert((key, image_rendering));
    }

    pub fn add_glyph(&mut self, font_key: FontKey, glyph: Glyph) {
        self.required_glyphs.entry(font_key)
                            .or_insert_with(HashSet::new)
                            .insert(glyph);
    }

    pub fn add_radius_raster(&mut self,
                             outer_radius: &Size2D<f32>,
                             inner_radius: &Size2D<f32>,
                             inverted: bool,
                             index: Option<u32>,
                             image_format: ImageFormat) {
        let outer_radius_x = DevicePixel::new(outer_radius.width, self.device_pixel_ratio);
        let outer_radius_y = DevicePixel::new(outer_radius.height, self.device_pixel_ratio);
        let inner_radius_x = DevicePixel::new(inner_radius.width, self.device_pixel_ratio);
        let inner_radius_y = DevicePixel::new(inner_radius.height, self.device_pixel_ratio);
        if let Some(raster_item) = BorderRadiusRasterOp::create(outer_radius_x,
                                                                outer_radius_y,
                                                                inner_radius_x,
                                                                inner_radius_y,
                                                                inverted,
                                                                index,
                                                                image_format) {
            self.required_rasters.insert(RasterItem::BorderRadius(raster_item));
        }
    }

    /// NB: Only adds non-tessellated border radii.
    pub fn add_radius_raster_for_border_radii(&mut self, radii: &BorderRadius) {
        let zero_size = Size2D::new(0.0, 0.0);
        self.add_radius_raster(&radii.top_left, &zero_size, false, None, ImageFormat::A8);
        self.add_radius_raster(&radii.top_right, &zero_size, false, None, ImageFormat::A8);
        self.add_radius_raster(&radii.bottom_left, &zero_size, false, None, ImageFormat::A8);
        self.add_radius_raster(&radii.bottom_right, &zero_size, false, None, ImageFormat::A8);
    }

    pub fn add_box_shadow_corner(&mut self,
                                 blur_radius: f32,
                                 border_radius: f32,
                                 box_rect: &Rect<f32>,
                                 inverted: bool) {
        if let Some(raster_item) = BoxShadowRasterOp::create_corner(blur_radius,
                                                                    border_radius,
                                                                    box_rect,
                                                                    inverted,
                                                                    self.device_pixel_ratio) {
            self.required_rasters.insert(RasterItem::BoxShadow(raster_item));
        }
    }

    pub fn add_box_shadow_edge(&mut self,
                               blur_radius: f32,
                               border_radius: f32,
                               box_rect: &Rect<f32>,
                               inverted: bool) {
        if let Some(raster_item) = BoxShadowRasterOp::create_edge(blur_radius,
                                                                  border_radius,
                                                                  box_rect,
                                                                  inverted,
                                                                  self.device_pixel_ratio) {
            self.required_rasters.insert(RasterItem::BoxShadow(raster_item));
        }
    }

    pub fn for_each_image<F>(&self, mut f: F) where F: FnMut(ImageKey, ImageRendering) {
        for &(image_id, image_rendering) in &self.required_images {
            f(image_id, image_rendering);
        }
    }

    pub fn for_each_raster<F>(&self, mut f: F) where F: FnMut(&RasterItem) {
        for raster_item in &self.required_rasters {
            f(raster_item);
        }
    }

    pub fn for_each_glyph<F>(&self, mut f: F) where F: FnMut(&GlyphKey) {
        for (font_id, glyphs) in &self.required_glyphs {
            let mut glyph_key = GlyphKey::new(font_id.clone(), Au(0), Au(0), 0);

            for glyph in glyphs {
                glyph_key.size = glyph.size;
                glyph_key.index = glyph.index;
                glyph_key.blur_radius = glyph.blur_radius;

                f(&glyph_key);
            }
        }
    }
}

pub trait BuildRequiredResources {
    fn build_resource_list(&mut self,
                           resource_cache: &ResourceCache,
                           pipeline_auxiliary_lists: &HashMap<PipelineId,
                                                              AuxiliaryLists,
                                                              BuildHasherDefault<FnvHasher>>);
}

impl BuildRequiredResources for AABBTreeNode {
    fn build_resource_list(&mut self,
                           resource_cache: &ResourceCache,
                           pipeline_auxiliary_lists: &HashMap<PipelineId,
                                                              AuxiliaryLists,
                                                              BuildHasherDefault<FnvHasher>>) {
        //let _pf = util::ProfileScope::new("  build_resource_list");
        let mut resource_list = ResourceList::new(resource_cache.device_pixel_ratio());

        for group in &self.draw_list_group_segments {
            for draw_list_index_buffer in &group.index_buffers {
                let draw_list = resource_cache.get_draw_list(draw_list_index_buffer.draw_list_id);

                for index in &draw_list_index_buffer.indices {
                    let DrawListItemIndex(index) = *index;
                    let display_item = &draw_list.items[index as usize];
                    let auxiliary_lists =
                        pipeline_auxiliary_lists.get(&draw_list.pipeline_id)
                                                .expect("No auxiliary lists for pipeline?!");

                    // Handle border radius for complex clipping regions.
                    for complex_clip_region in
                            auxiliary_lists.complex_clip_regions(&display_item.clip.complex) {
                        resource_list.add_radius_raster_for_border_radii(
                            &complex_clip_region.radii);
                    }

                    match display_item.item {
                        SpecificDisplayItem::Image(ref info) => {
                            resource_list.add_image(info.image_key, info.image_rendering);
                        }
                        SpecificDisplayItem::Text(ref info) => {
                            let glyphs = auxiliary_lists.glyph_instances(&info.glyphs);
                            for glyph in glyphs {
                                let glyph = Glyph::new(info.size, info.blur_radius, glyph.index);
                                resource_list.add_glyph(info.font_key, glyph);
                            }
                        }
                        SpecificDisplayItem::WebGL(..) => {}
                        SpecificDisplayItem::Rectangle(..) => {}
                        SpecificDisplayItem::Gradient(..) => {}
                        SpecificDisplayItem::BoxShadow(ref info) => {
                            resource_list.add_radius_raster_for_border_radii(
                                &BorderRadius::uniform(info.border_radius));

                            let box_rect = batch_builder::compute_box_shadow_rect(&info.box_bounds,
                                                                                &info.offset,
                                                                                info.spread_radius,
                                                                                info.clip_mode);
                            resource_list.add_box_shadow_corner(info.blur_radius,
                                                                info.border_radius,
                                                                &box_rect,
                                                                false);
                            resource_list.add_box_shadow_edge(info.blur_radius,
                                                              info.border_radius,
                                                              &box_rect,
                                                              false);
                            if info.clip_mode == BoxShadowClipMode::Inset {
                                resource_list.add_box_shadow_corner(info.blur_radius,
                                                                    info.border_radius,
                                                                    &box_rect,
                                                                    true);
                                resource_list.add_box_shadow_edge(info.blur_radius,
                                                                  info.border_radius,
                                                                  &box_rect,
                                                                  true);
                            }
                        }
                        SpecificDisplayItem::Border(ref info) => {
                            let can_tessellate = tessellator::can_tessellate_border(info);
                            add_border_radius_raster(&info.radius.top_left,
                                                     &info.top_left_inner_radius(),
                                                     can_tessellate,
                                                     resource_cache,
                                                     &mut resource_list);
                            add_border_radius_raster(&info.radius.top_right,
                                                     &info.top_right_inner_radius(),
                                                     can_tessellate,
                                                     resource_cache,
                                                     &mut resource_list);
                            add_border_radius_raster(&info.radius.bottom_right,
                                                     &info.bottom_right_inner_radius(),
                                                     can_tessellate,
                                                     resource_cache,
                                                     &mut resource_list);
                            add_border_radius_raster(&info.radius.bottom_left,
                                                     &info.bottom_left_inner_radius(),
                                                     can_tessellate,
                                                     resource_cache,
                                                     &mut resource_list);

                            if info.top.style == BorderStyle::Dotted {
                                resource_list.add_radius_raster(&Size2D::new(info.top.width / 2.0,
                                                                             info.top.width / 2.0),
                                                                &Size2D::new(0.0, 0.0),
                                                                false,
                                                                None,
                                                                ImageFormat::RGBA8);
                            }
                            if info.right.style == BorderStyle::Dotted {
                                resource_list.add_radius_raster(&Size2D::new(info.right.width / 2.0,
                                                                             info.right.width / 2.0),
                                                                &Size2D::new(0.0, 0.0),
                                                                false,
                                                                None,
                                                                ImageFormat::RGBA8);
                            }
                            if info.bottom.style == BorderStyle::Dotted {
                                resource_list.add_radius_raster(&Size2D::new(info.bottom.width / 2.0,
                                                                             info.bottom.width / 2.0),
                                                                &Size2D::new(0.0, 0.0),
                                                                false,
                                                                None,
                                                                ImageFormat::RGBA8);
                            }
                            if info.left.style == BorderStyle::Dotted {
                                resource_list.add_radius_raster(&Size2D::new(info.left.width / 2.0,
                                                                             info.left.width / 2.0),
                                                                &Size2D::new(0.0, 0.0),
                                                                false,
                                                                None,
                                                                ImageFormat::RGBA8);
                            }

                            if info.top.style == BorderStyle::Double {
                                resource_list.add_radius_raster(&info.radius.top_left,
                                                                &Size2D::zero(),
                                                                false,
                                                                None,
                                                                ImageFormat::A8);

                                resource_list.add_radius_raster(&Size2D::zero(),
                                                                &info.top_left_inner_radius(),
                                                                false,
                                                                None,
                                                                ImageFormat::A8);
                            }
                            if info.right.style == BorderStyle::Double {
                                resource_list.add_radius_raster(&info.radius.top_right,
                                                                &Size2D::zero(),
                                                                false,
                                                                None,
                                                                ImageFormat::A8);

                                resource_list.add_radius_raster(&Size2D::zero(),
                                                                &info.top_right_inner_radius(),
                                                                false,
                                                                None,
                                                                ImageFormat::A8);
                            }
                            if info.bottom.style == BorderStyle::Double {
                                resource_list.add_radius_raster(&info.radius.bottom_left,
                                                                &Size2D::zero(),
                                                                false,
                                                                None,
                                                                ImageFormat::A8);

                                resource_list.add_radius_raster(&Size2D::zero(),
                                                                &info.bottom_left_inner_radius(),
                                                                false,
                                                                None,
                                                                ImageFormat::A8);
                            }
                            if info.left.style == BorderStyle::Double {
                                resource_list.add_radius_raster(&info.radius.bottom_right,
                                                                &Size2D::zero(),
                                                                false,
                                                                None,
                                                                ImageFormat::A8);

                                resource_list.add_radius_raster(&Size2D::zero(),
                                                                &info.bottom_right_inner_radius(),
                                                                false,
                                                                None,
                                                                ImageFormat::A8);
                            }

                        }
                    }
                }
            }
        }

        self.resource_list = Some(resource_list);
    }
}

fn add_border_radius_raster(outer_radius: &Size2D<f32>,
                            inner_radius: &Size2D<f32>,
                            can_tessellate: bool,
                            resource_cache: &ResourceCache,
                            resource_list: &mut ResourceList) {
    let quad_count = if can_tessellate {
        tessellator::quad_count_for_border_corner(outer_radius,
                                                  resource_cache.device_pixel_ratio())
    } else {
        1
    };
    for rect_index in 0..quad_count {
        let index = if can_tessellate {
            Some(rect_index)
        } else {
            None
        };
        resource_list.add_radius_raster(outer_radius,
                                        inner_radius,
                                        false,
                                        index,
                                        ImageFormat::A8);
    }
}

<|endoftext|>


<commit_before>extern crate clap;
extern crate rusqlite;

#[macro_use] extern crate log;

extern crate env_logger;
extern crate rustc_serialize;
extern crate uuid;

mod loader;
mod db;
mod dbFsDirType;
mod dbFsDir;
mod dbFsFile;
mod dbProvider;
mod dbJob;
mod dbJobProvide;
mod dbJobDepend;
mod dbVariableName;
mod dbJobRequireVariable;
mod dbVariablePair;
mod dbJobRequireVariablePair;
mod json_loader_elephant;
mod cli_clap;
mod jobs_load;
mod elephant;
mod dbSession;
mod dbEnviroment;
mod autoconf;
mod clap_actions;

use uuid::Uuid;

fn main() {
    env_logger::init().unwrap();
    let some_value = 10;
    let clap_matches = cli_clap::cli_clap(&some_value);
    let actions = clap_actions::actions_get(&clap_matches);
    let session_uuid = Uuid::new_v4();
    let session_uuid_string = session_uuid.simple().to_string();
    let conn = db::connect_deligate(&clap_matches);
    db::create_tables(&conn);
    loader::deligate(&conn, &clap_matches);
    let pk_session = elephant::elephant_session(&conn, &session_uuid_string);
    loader::enviroment(&conn, pk_session, &clap_matches);
    jobs_load::load(&conn);
}
<commit_msg>maintenance loader::deligate<commit_after>extern crate clap;
extern crate rusqlite;

#[macro_use] extern crate log;

extern crate env_logger;
extern crate rustc_serialize;
extern crate uuid;

mod loader;
mod db;
mod dbFsDirType;
mod dbFsDir;
mod dbFsFile;
mod dbProvider;
mod dbJob;
mod dbJobProvide;
mod dbJobDepend;
mod dbVariableName;
mod dbJobRequireVariable;
mod dbVariablePair;
mod dbJobRequireVariablePair;
mod json_loader_elephant;
mod cli_clap;
mod jobs_load;
mod elephant;
mod dbSession;
mod dbEnviroment;
mod autoconf;
mod clap_actions;

use uuid::Uuid;

fn main() {
    env_logger::init().unwrap();
    let some_value = 10;
    let clap_matches = cli_clap::cli_clap(&some_value);
    let actions = clap_actions::actions_get(&clap_matches);
    let session_uuid = Uuid::new_v4();
    let session_uuid_string = session_uuid.simple().to_string();
    let conn = db::connect_deligate(&clap_matches);
    db::create_tables(&conn);
    loader::deligate(&conn, &actions, &clap_matches);
    let pk_session = elephant::elephant_session(&conn, &session_uuid_string);
    loader::enviroment(&conn, pk_session, &clap_matches);
    jobs_load::load(&conn);
}
<|endoftext|>


<commit_before>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

//!
//! # Tagged stream
//!
//! A tagged stream recursively applies tags to regions of an input stream. A stream consisting of a single tag forms a tree,
//! so this stream type is useful for representing the parsed represention of an input.
//!
//! The simplest form of tagged stream is one that's just a set of untagged symbols. This can be created using the `TaggedStream::from_reader`
//! method.
//!
//! ```
//! # use concordance::*;
//! #[derive(Ord, PartialOrd, Eq, PartialEq, Clone)]
//! enum SomeTag {
//!     Identifier
//! };
//!
//! let simple_tagged : TaggedStream<char, SomeTag> = TaggedStream::from_reader(&mut "Hello, world".read_symbols());
//! ```
//!

use std::slice::Iter;
use std::ops::Index;

use super::symbol_reader::*;

///
/// Represents a symbol in a tagged stream.
///
/// A symbol can either be a sequence of untagged base symbols, or it can be a tag (which itself can contain any number of tagged symbol)
///
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum TagSymbol<Base: Clone, Tag: Clone> {
    Untagged(Base),
    Tagged(Tag, Vec<TaggedStream<Base, Tag>>)
}

///
/// Represents a stream of tagged symbols
///
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct TaggedStream<Base: Clone, Tag: Clone> {
    /// The data in this stream
    data: Vec<TagSymbol<Base, Tag>>
}

impl<Base: Clone, Tag: Clone> TaggedStream<Base, Tag> {
    ///
    /// Creates a basic tagged stream from a source of the base symbol
    ///
    pub fn from_reader(reader: &mut SymbolReader<Base>) -> TaggedStream<Base, Tag> {
        // Read from the reader into an array
        let mut symbols = vec![];

        while let Some(next_symbol) = reader.next_symbol() {
            symbols.push(TagSymbol::Untagged(next_symbol));
        }

        // Generate a simple tagged stream from the result
        TaggedStream { data: symbols }
    }

    ///
    /// The number of symbols in this stream
    ///
    pub fn len(&self) -> usize {
        self.data.len()
    }
}

impl<Base: Clone, Tag: Clone> Index<usize> for TaggedStream<Base, Tag> {
    type Output = TagSymbol<Base, Tag>;

    fn index(&self, index: usize) -> &TagSymbol<Base, Tag> {
        &self.data[index]
    }
}

impl<'a, Base: Clone, Tag: Clone> SymbolSource<'a, TagSymbol<Base, Tag>> for &'a TaggedStream<Base, Tag> {
    type SymbolReader = Iter<'a, TagSymbol<Base, Tag>>;

    /// Returns a new object that can read the symbols from this one
    fn read_symbols(self) -> Self::SymbolReader {
        self.data.read_symbols()
    }
}
<commit_msg>Oops, this is just a single tagged stream, not a vector<commit_after>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

//!
//! # Tagged stream
//!
//! A tagged stream recursively applies tags to regions of an input stream. A stream consisting of a single tag forms a tree,
//! so this stream type is useful for representing the parsed represention of an input.
//!
//! The simplest form of tagged stream is one that's just a set of untagged symbols. This can be created using the `TaggedStream::from_reader`
//! method.
//!
//! ```
//! # use concordance::*;
//! #[derive(Ord, PartialOrd, Eq, PartialEq, Clone)]
//! enum SomeTag {
//!     Identifier
//! };
//!
//! let simple_tagged : TaggedStream<char, SomeTag> = TaggedStream::from_reader(&mut "Hello, world".read_symbols());
//! ```
//!

use std::slice::Iter;
use std::ops::Index;

use super::symbol_reader::*;

///
/// Represents a symbol in a tagged stream.
///
/// A symbol can either be a sequence of untagged base symbols, or it can be a tag (which itself can contain any number of tagged symbol)
///
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum TagSymbol<Base: Clone, Tag: Clone> {
    Untagged(Base),
    Tagged(Tag, TaggedStream<Base, Tag>)
}

///
/// Represents a stream of tagged symbols
///
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct TaggedStream<Base: Clone, Tag: Clone> {
    /// The data in this stream
    data: Vec<TagSymbol<Base, Tag>>
}

impl<Base: Clone, Tag: Clone> TaggedStream<Base, Tag> {
    ///
    /// Creates a basic tagged stream from a source of the base symbol
    ///
    pub fn from_reader(reader: &mut SymbolReader<Base>) -> TaggedStream<Base, Tag> {
        // Read from the reader into an array
        let mut symbols = vec![];

        while let Some(next_symbol) = reader.next_symbol() {
            symbols.push(TagSymbol::Untagged(next_symbol));
        }

        // Generate a simple tagged stream from the result
        TaggedStream { data: symbols }
    }

    ///
    /// The number of symbols in this stream
    ///
    pub fn len(&self) -> usize {
        self.data.len()
    }
}

impl<Base: Clone, Tag: Clone> Index<usize> for TaggedStream<Base, Tag> {
    type Output = TagSymbol<Base, Tag>;

    fn index(&self, index: usize) -> &TagSymbol<Base, Tag> {
        &self.data[index]
    }
}

impl<'a, Base: Clone, Tag: Clone> SymbolSource<'a, TagSymbol<Base, Tag>> for &'a TaggedStream<Base, Tag> {
    type SymbolReader = Iter<'a, TagSymbol<Base, Tag>>;

    /// Returns a new object that can read the symbols from this one
    fn read_symbols(self) -> Self::SymbolReader {
        self.data.read_symbols()
    }
}
<|endoftext|>