<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 font_template::{FontTemplate, FontTemplateDescriptor};
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
use ipc_channel::router::ROUTER;
use mime::{TopLevel, SubLevel};
use net_traits::{AsyncResponseTarget, LoadContext, PendingAsyncLoad, ResourceTask, ResponseAction};
use platform::font_context::FontContextHandle;
use platform::font_list::for_each_available_family;
use platform::font_list::for_each_variation;
use platform::font_list::last_resort_font_families;
use platform::font_list::system_default_family;
use platform::font_template::FontTemplateData;
use std::borrow::ToOwned;
use std::collections::HashMap;
use std::mem;
use std::sync::mpsc::channel;
use std::sync::{Arc, Mutex};
use string_cache::Atom;
use style::font_face::Source;
use style::properties::longhands::font_family::computed_value::FontFamily;
use url::Url;
use util::prefs;
use util::str::LowercaseString;
use util::task::spawn_named;

/// A list of font templates that make up a given font family.
struct FontTemplates {
    templates: Vec<FontTemplate>,
}

impl FontTemplates {
    fn new() -> FontTemplates {
        FontTemplates {
            templates: vec!(),
        }
    }

    /// Find a font in this family that matches a given descriptor.
    fn find_font_for_style(&mut self, desc: &FontTemplateDescriptor, fctx: &FontContextHandle)
                               -> Option<Arc<FontTemplateData>> {
        // TODO(Issue #189): optimize lookup for
        // regular/bold/italic/bolditalic with fixed offsets and a
        // static decision table for fallback between these values.

        // TODO(Issue #190): if not in the fast path above, do
        // expensive matching of weights, etc.
        for template in &mut self.templates {
            let maybe_template = template.data_for_descriptor(fctx, desc);
            if maybe_template.is_some() {
                return maybe_template;
            }
        }

        // If a request is made for a font family that exists,
        // pick the first valid font in the family if we failed
        // to find an exact match for the descriptor.
        for template in &mut self.templates {
            let maybe_template = template.get();
            if maybe_template.is_some() {
                return maybe_template;
            }
        }

        None
    }

    fn add_template(&mut self, identifier: Atom, maybe_data: Option<Vec<u8>>) {
        for template in &self.templates {
            if *template.identifier() == identifier {
                return;
            }
        }

        let template = FontTemplate::new(identifier, maybe_data);
        self.templates.push(template);
    }
}

/// Commands that the FontContext sends to the font cache task.
#[derive(Deserialize, Serialize, Debug)]
pub enum Command {
    GetFontTemplate(FontFamily, FontTemplateDescriptor, IpcSender<Reply>),
    GetLastResortFontTemplate(FontTemplateDescriptor, IpcSender<Reply>),
    AddWebFont(FontFamily, Source, IpcSender<()>),
    AddDownloadedWebFont(FontFamily, Url, Vec<u8>, IpcSender<()>),
    Exit(IpcSender<()>),
}

/// Reply messages sent from the font cache task to the FontContext caller.
#[derive(Deserialize, Serialize, Debug)]
pub enum Reply {
    GetFontTemplateReply(Option<Arc<FontTemplateData>>),
}

/// The font cache task itself. It maintains a list of reference counted
/// font templates that are currently in use.
struct FontCache {
    port: IpcReceiver<Command>,
    channel_to_self: IpcSender<Command>,
    generic_fonts: HashMap<FontFamily, LowercaseString>,
    local_families: HashMap<LowercaseString, FontTemplates>,
    web_families: HashMap<LowercaseString, FontTemplates>,
    font_context: FontContextHandle,
    resource_task: ResourceTask,
}

fn populate_generic_fonts() -> HashMap<FontFamily, LowercaseString> {
    let mut generic_fonts = HashMap::with_capacity(5);

    append_map(&mut generic_fonts, FontFamily::Serif, "Times New Roman");
    append_map(&mut generic_fonts, FontFamily::SansSerif, "Arial");
    append_map(&mut generic_fonts, FontFamily::Cursive, "Apple Chancery");
    append_map(&mut generic_fonts, FontFamily::Fantasy, "Papyrus");
    append_map(&mut generic_fonts, FontFamily::Monospace, "Menlo");

    fn append_map(generic_fonts: &mut HashMap<FontFamily, LowercaseString>,
                  font_family: FontFamily,
                  mapped_name: &str) {
        let family_name = {
            let opt_system_default = system_default_family(font_family.name());
            match opt_system_default {
                Some(system_default) => LowercaseString::new(&system_default),
                None => LowercaseString::new(mapped_name)
            }
        };

        generic_fonts.insert(font_family, family_name);
    }

    generic_fonts
}

impl FontCache {
    fn run(&mut self) {
        loop {
            let msg = self.port.recv().unwrap();

            match msg {
                Command::GetFontTemplate(family, descriptor, result) => {
                    let maybe_font_template = self.find_font_template(&family, &descriptor);
                    result.send(Reply::GetFontTemplateReply(maybe_font_template)).unwrap();
                }
                Command::GetLastResortFontTemplate(descriptor, result) => {
                    let font_template = self.last_resort_font_template(&descriptor);
                    result.send(Reply::GetFontTemplateReply(Some(font_template))).unwrap();
                }
                Command::AddWebFont(family, src, result) => {
                    let family_name = LowercaseString::new(family.name());
                    if !self.web_families.contains_key(&family_name) {
                        let templates = FontTemplates::new();
                        self.web_families.insert(family_name, templates);
                    }

                    match src {
                        Source::Url(ref url_source) => {
                            let url = &url_source.url;
                            let load = PendingAsyncLoad::new(LoadContext::Font,
                                                             self.resource_task.clone(),
                                                             url.clone(),
                                                             None);
                            let (data_sender, data_receiver) = ipc::channel().unwrap();
                            let data_target = AsyncResponseTarget {
                                sender: data_sender,
                            };
                            load.load_async(data_target);
                            let channel_to_self = self.channel_to_self.clone();
                            let url = (*url).clone();
                            let bytes = Mutex::new(Vec::new());
                            let response_valid = Mutex::new(false);
                            ROUTER.add_route(data_receiver.to_opaque(), box move |message| {
                                let response: ResponseAction = message.to().unwrap();
                                match response {
                                    ResponseAction::HeadersAvailable(metadata) => {
                                        let is_response_valid =
                                            metadata.content_type.as_ref().map_or(false, |content_type| {
                                                let mime = &content_type.0;
                                                is_supported_font_type(&mime.0, &mime.1)
                                            });
                                        info!("{} font with MIME type {:?}",
                                              if is_response_valid { "Loading" } else { "Ignoring" },
                                              metadata.content_type);
                                        *response_valid.lock().unwrap() = is_response_valid;
                                    }
                                    ResponseAction::ResponseComplete(Err(_)) => {}
                                    ResponseAction::DataAvailable(new_bytes) => {
                                        if *response_valid.lock().unwrap() {
                                            bytes.lock().unwrap().extend(new_bytes.into_iter())
                                        }
                                    }
                                    ResponseAction::ResponseComplete(Ok(_)) => {
                                        if !*response_valid.lock().unwrap() {
                                            drop(result.send(()));
                                            return;
                                        }
                                        let mut bytes = bytes.lock().unwrap();
                                        let bytes = mem::replace(&mut *bytes, Vec::new());
                                        let command =
                                            Command::AddDownloadedWebFont(family.clone(),
                                                                          url.clone(),
                                                                          bytes,
                                                                          result.clone());
                                        channel_to_self.send(command).unwrap();
                                    }
                                }
                            });
                        }
                        Source::Local(ref family) => {
                            let family_name = LowercaseString::new(family.name());
                            let templates = &mut self.web_families.get_mut(&family_name).unwrap();
                            for_each_variation(&family_name, |path| {
                                templates.add_template(Atom::from(&*path), None);
                            });
                            result.send(()).unwrap();
                        }
                    }
                }
                Command::AddDownloadedWebFont(family, url, bytes, result) => {
                    let family_name = LowercaseString::new(family.name());

                    let templates = &mut self.web_families.get_mut(&family_name).unwrap();
                    templates.add_template(Atom::from(&*url.to_string()), Some(bytes));
                    drop(result.send(()));
                }
                Command::Exit(result) => {
                    result.send(()).unwrap();
                    break;
                }
            }
        }
    }

    fn refresh_local_families(&mut self) {
        self.local_families.clear();
        for_each_available_family(|family_name| {
            let family_name = LowercaseString::new(&family_name);
            if !self.local_families.contains_key(&family_name) {
                let templates = FontTemplates::new();
                self.local_families.insert(family_name, templates);
            }
        });
    }

    fn transform_family(&self, family: &FontFamily) -> LowercaseString {
        match self.generic_fonts.get(family) {
            None => LowercaseString::new(family.name()),
            Some(mapped_family) => (*mapped_family).clone()
        }
    }

    fn find_font_in_local_family(&mut self, family_name: &LowercaseString, desc: &FontTemplateDescriptor)
                                -> Option<Arc<FontTemplateData>> {
        // TODO(Issue #188): look up localized font family names if canonical name not found
        // look up canonical name
        if self.local_families.contains_key(family_name) {
            debug!("FontList: Found font family with name={}", &**family_name);
            let s = self.local_families.get_mut(family_name).unwrap();

            if s.templates.is_empty() {
                for_each_variation(family_name, |path| {
                    s.add_template(Atom::from(&*path), None);
                });
            }

            // TODO(Issue #192: handle generic font families, like 'serif' and 'sans-serif'.
            // if such family exists, try to match style to a font

            s.find_font_for_style(desc, &self.font_context)
        } else {
            debug!("FontList: Couldn't find font family with name={}", &**family_name);
            None
        }
    }

    fn find_font_in_web_family(&mut self, family: &FontFamily, desc: &FontTemplateDescriptor)
                                -> Option<Arc<FontTemplateData>> {
        let family_name = LowercaseString::new(family.name());

        if self.web_families.contains_key(&family_name) {
            let templates = self.web_families.get_mut(&family_name).unwrap();
            templates.find_font_for_style(desc, &self.font_context)
        } else {
            None
        }
    }

    fn find_font_template(&mut self, family: &FontFamily, desc: &FontTemplateDescriptor)
                            -> Option<Arc<FontTemplateData>> {
        self.find_font_in_web_family(family, desc)
            .or_else(|| {
                let transformed_family = self.transform_family(family);
                self.find_font_in_local_family(&transformed_family, desc)
            })
    }

    fn last_resort_font_template(&mut self, desc: &FontTemplateDescriptor)
                                        -> Arc<FontTemplateData> {
        let last_resort = last_resort_font_families();

        for family in &last_resort {
            let family = LowercaseString::new(family);
            let maybe_font_in_family = self.find_font_in_local_family(&family, desc);
            if let Some(family) = maybe_font_in_family {
                return family;
            }
        }

        panic!("Unable to find any fonts that match (do you have fallback fonts installed?)");
    }
}

/// The public interface to the font cache task, used exclusively by
/// the per-thread/task FontContext structures.
#[derive(Clone, Deserialize, Serialize, Debug)]
pub struct FontCacheTask {
    chan: IpcSender<Command>,
}

impl FontCacheTask {
    pub fn new(resource_task: ResourceTask) -> FontCacheTask {
        let (chan, port) = ipc::channel().unwrap();

        let channel_to_self = chan.clone();
        spawn_named("FontCacheTask".to_owned(), move || {
            // TODO: Allow users to specify these.
            let generic_fonts = populate_generic_fonts();

            let mut cache = FontCache {
                port: port,
                channel_to_self: channel_to_self,
                generic_fonts: generic_fonts,
                local_families: HashMap::new(),
                web_families: HashMap::new(),
                font_context: FontContextHandle::new(),
                resource_task: resource_task,
            };

            cache.refresh_local_families();
            cache.run();
        });

        FontCacheTask {
            chan: chan,
        }
    }

    pub fn find_font_template(&self, family: FontFamily, desc: FontTemplateDescriptor)
                                                -> Option<Arc<FontTemplateData>> {

        let (response_chan, response_port) = ipc::channel().unwrap();
        self.chan.send(Command::GetFontTemplate(family, desc, response_chan)).unwrap();

        let reply = response_port.recv().unwrap();

        match reply {
            Reply::GetFontTemplateReply(data) => {
                data
            }
        }
    }

    pub fn last_resort_font_template(&self, desc: FontTemplateDescriptor)
                                                -> Arc<FontTemplateData> {

        let (response_chan, response_port) = ipc::channel().unwrap();
        self.chan.send(Command::GetLastResortFontTemplate(desc, response_chan)).unwrap();

        let reply = response_port.recv().unwrap();

        match reply {
            Reply::GetFontTemplateReply(data) => {
                data.unwrap()
            }
        }
    }

    pub fn add_web_font(&self, family: FontFamily, src: Source, sender: IpcSender<()>) {
        self.chan.send(Command::AddWebFont(family, src, sender)).unwrap();
    }

    pub fn exit(&self) {
        let (response_chan, response_port) = ipc::channel().unwrap();
        self.chan.send(Command::Exit(response_chan)).unwrap();
        response_port.recv().unwrap();
    }
}

// derived from http://stackoverflow.com/a/10864297/3830
fn is_supported_font_type(toplevel: &TopLevel, sublevel: &SubLevel) -> bool {
    if !prefs::get_pref("net.mime.sniff").as_boolean().unwrap_or(false) {
        return true;
    }

    match (toplevel, sublevel) {
        (&TopLevel::Application, &SubLevel::Ext(ref ext)) => {
            match &ext[..] {
                //FIXME: once sniffing is enabled by default, we shouldn't need nonstandard
                //       MIME types here.
                "font-sfnt" | "x-font-ttf" | "x-font-truetype" | "x-font-opentype" => true,
                _ => false,
            }
        }
        _ => false,
    }
}
<commit_msg>Auto merge of #9159 - saneyuki:9158, r=jdm<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 font_template::{FontTemplate, FontTemplateDescriptor};
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
use ipc_channel::router::ROUTER;
use mime::{TopLevel, SubLevel};
use net_traits::{AsyncResponseTarget, LoadContext, PendingAsyncLoad, ResourceTask, ResponseAction};
use platform::font_context::FontContextHandle;
use platform::font_list::for_each_available_family;
use platform::font_list::for_each_variation;
use platform::font_list::last_resort_font_families;
use platform::font_list::system_default_family;
use platform::font_template::FontTemplateData;
use std::borrow::ToOwned;
use std::collections::HashMap;
use std::mem;
use std::sync::mpsc::channel;
use std::sync::{Arc, Mutex};
use string_cache::Atom;
use style::font_face::Source;
use style::properties::longhands::font_family::computed_value::FontFamily;
use url::Url;
use util::prefs;
use util::str::LowercaseString;
use util::task::spawn_named;

/// A list of font templates that make up a given font family.
struct FontTemplates {
    templates: Vec<FontTemplate>,
}

impl FontTemplates {
    fn new() -> FontTemplates {
        FontTemplates {
            templates: vec!(),
        }
    }

    /// Find a font in this family that matches a given descriptor.
    fn find_font_for_style(&mut self, desc: &FontTemplateDescriptor, fctx: &FontContextHandle)
                               -> Option<Arc<FontTemplateData>> {
        // TODO(Issue #189): optimize lookup for
        // regular/bold/italic/bolditalic with fixed offsets and a
        // static decision table for fallback between these values.

        // TODO(Issue #190): if not in the fast path above, do
        // expensive matching of weights, etc.
        for template in &mut self.templates {
            let maybe_template = template.data_for_descriptor(fctx, desc);
            if maybe_template.is_some() {
                return maybe_template;
            }
        }

        // If a request is made for a font family that exists,
        // pick the first valid font in the family if we failed
        // to find an exact match for the descriptor.
        for template in &mut self.templates {
            let maybe_template = template.get();
            if maybe_template.is_some() {
                return maybe_template;
            }
        }

        None
    }

    fn add_template(&mut self, identifier: Atom, maybe_data: Option<Vec<u8>>) {
        for template in &self.templates {
            if *template.identifier() == identifier {
                return;
            }
        }

        let template = FontTemplate::new(identifier, maybe_data);
        self.templates.push(template);
    }
}

/// Commands that the FontContext sends to the font cache task.
#[derive(Deserialize, Serialize, Debug)]
pub enum Command {
    GetFontTemplate(FontFamily, FontTemplateDescriptor, IpcSender<Reply>),
    GetLastResortFontTemplate(FontTemplateDescriptor, IpcSender<Reply>),
    AddWebFont(FontFamily, Source, IpcSender<()>),
    AddDownloadedWebFont(FontFamily, Url, Vec<u8>, IpcSender<()>),
    Exit(IpcSender<()>),
}

/// Reply messages sent from the font cache task to the FontContext caller.
#[derive(Deserialize, Serialize, Debug)]
pub enum Reply {
    GetFontTemplateReply(Option<Arc<FontTemplateData>>),
}

/// The font cache task itself. It maintains a list of reference counted
/// font templates that are currently in use.
struct FontCache {
    port: IpcReceiver<Command>,
    channel_to_self: IpcSender<Command>,
    generic_fonts: HashMap<FontFamily, LowercaseString>,
    local_families: HashMap<LowercaseString, FontTemplates>,
    web_families: HashMap<LowercaseString, FontTemplates>,
    font_context: FontContextHandle,
    resource_task: ResourceTask,
}

fn populate_generic_fonts() -> HashMap<FontFamily, LowercaseString> {
    let mut generic_fonts = HashMap::with_capacity(5);

    append_map(&mut generic_fonts, FontFamily::Serif, "Times New Roman");
    append_map(&mut generic_fonts, FontFamily::SansSerif, "Arial");
    append_map(&mut generic_fonts, FontFamily::Cursive, "Apple Chancery");
    append_map(&mut generic_fonts, FontFamily::Fantasy, "Papyrus");
    append_map(&mut generic_fonts, FontFamily::Monospace, "Menlo");

    fn append_map(generic_fonts: &mut HashMap<FontFamily, LowercaseString>,
                  font_family: FontFamily,
                  mapped_name: &str) {
        let family_name = {
            let opt_system_default = system_default_family(font_family.name());
            match opt_system_default {
                Some(system_default) => LowercaseString::new(&system_default),
                None => LowercaseString::new(mapped_name)
            }
        };

        generic_fonts.insert(font_family, family_name);
    }

    generic_fonts
}

impl FontCache {
    fn run(&mut self) {
        loop {
            let msg = self.port.recv().unwrap();

            match msg {
                Command::GetFontTemplate(family, descriptor, result) => {
                    let maybe_font_template = self.find_font_template(&family, &descriptor);
                    result.send(Reply::GetFontTemplateReply(maybe_font_template)).unwrap();
                }
                Command::GetLastResortFontTemplate(descriptor, result) => {
                    let font_template = self.last_resort_font_template(&descriptor);
                    result.send(Reply::GetFontTemplateReply(Some(font_template))).unwrap();
                }
                Command::AddWebFont(family, src, result) => {
                    let family_name = LowercaseString::new(family.name());
                    if !self.web_families.contains_key(&family_name) {
                        let templates = FontTemplates::new();
                        self.web_families.insert(family_name, templates);
                    }

                    match src {
                        Source::Url(ref url_source) => {
                            let url = &url_source.url;
                            let load = PendingAsyncLoad::new(LoadContext::Font,
                                                             self.resource_task.clone(),
                                                             url.clone(),
                                                             None);
                            let (data_sender, data_receiver) = ipc::channel().unwrap();
                            let data_target = AsyncResponseTarget {
                                sender: data_sender,
                            };
                            load.load_async(data_target);
                            let channel_to_self = self.channel_to_self.clone();
                            let url = (*url).clone();
                            let bytes = Mutex::new(Vec::new());
                            let response_valid = Mutex::new(false);
                            ROUTER.add_route(data_receiver.to_opaque(), box move |message| {
                                let response: ResponseAction = message.to().unwrap();
                                match response {
                                    ResponseAction::HeadersAvailable(metadata) => {
                                        let is_response_valid =
                                            metadata.content_type.as_ref().map_or(false, |content_type| {
                                                let mime = &content_type.0;
                                                is_supported_font_type(&mime.0, &mime.1)
                                            });
                                        info!("{} font with MIME type {:?}",
                                              if is_response_valid { "Loading" } else { "Ignoring" },
                                              metadata.content_type);
                                        *response_valid.lock().unwrap() = is_response_valid;
                                    }
                                    ResponseAction::DataAvailable(new_bytes) => {
                                        if *response_valid.lock().unwrap() {
                                            bytes.lock().unwrap().extend(new_bytes.into_iter())
                                        }
                                    }
                                    ResponseAction::ResponseComplete(response) => {
                                        if response.is_err() || !*response_valid.lock().unwrap() {
                                            drop(result.send(()));
                                            return;
                                        }
                                        let mut bytes = bytes.lock().unwrap();
                                        let bytes = mem::replace(&mut *bytes, Vec::new());
                                        let command =
                                            Command::AddDownloadedWebFont(family.clone(),
                                                                          url.clone(),
                                                                          bytes,
                                                                          result.clone());
                                        channel_to_self.send(command).unwrap();
                                    }
                                }
                            });
                        }
                        Source::Local(ref family) => {
                            let family_name = LowercaseString::new(family.name());
                            let templates = &mut self.web_families.get_mut(&family_name).unwrap();
                            for_each_variation(&family_name, |path| {
                                templates.add_template(Atom::from(&*path), None);
                            });
                            result.send(()).unwrap();
                        }
                    }
                }
                Command::AddDownloadedWebFont(family, url, bytes, result) => {
                    let family_name = LowercaseString::new(family.name());

                    let templates = &mut self.web_families.get_mut(&family_name).unwrap();
                    templates.add_template(Atom::from(&*url.to_string()), Some(bytes));
                    drop(result.send(()));
                }
                Command::Exit(result) => {
                    result.send(()).unwrap();
                    break;
                }
            }
        }
    }

    fn refresh_local_families(&mut self) {
        self.local_families.clear();
        for_each_available_family(|family_name| {
            let family_name = LowercaseString::new(&family_name);
            if !self.local_families.contains_key(&family_name) {
                let templates = FontTemplates::new();
                self.local_families.insert(family_name, templates);
            }
        });
    }

    fn transform_family(&self, family: &FontFamily) -> LowercaseString {
        match self.generic_fonts.get(family) {
            None => LowercaseString::new(family.name()),
            Some(mapped_family) => (*mapped_family).clone()
        }
    }

    fn find_font_in_local_family(&mut self, family_name: &LowercaseString, desc: &FontTemplateDescriptor)
                                -> Option<Arc<FontTemplateData>> {
        // TODO(Issue #188): look up localized font family names if canonical name not found
        // look up canonical name
        if self.local_families.contains_key(family_name) {
            debug!("FontList: Found font family with name={}", &**family_name);
            let s = self.local_families.get_mut(family_name).unwrap();

            if s.templates.is_empty() {
                for_each_variation(family_name, |path| {
                    s.add_template(Atom::from(&*path), None);
                });
            }

            // TODO(Issue #192: handle generic font families, like 'serif' and 'sans-serif'.
            // if such family exists, try to match style to a font

            s.find_font_for_style(desc, &self.font_context)
        } else {
            debug!("FontList: Couldn't find font family with name={}", &**family_name);
            None
        }
    }

    fn find_font_in_web_family(&mut self, family: &FontFamily, desc: &FontTemplateDescriptor)
                                -> Option<Arc<FontTemplateData>> {
        let family_name = LowercaseString::new(family.name());

        if self.web_families.contains_key(&family_name) {
            let templates = self.web_families.get_mut(&family_name).unwrap();
            templates.find_font_for_style(desc, &self.font_context)
        } else {
            None
        }
    }

    fn find_font_template(&mut self, family: &FontFamily, desc: &FontTemplateDescriptor)
                            -> Option<Arc<FontTemplateData>> {
        self.find_font_in_web_family(family, desc)
            .or_else(|| {
                let transformed_family = self.transform_family(family);
                self.find_font_in_local_family(&transformed_family, desc)
            })
    }

    fn last_resort_font_template(&mut self, desc: &FontTemplateDescriptor)
                                        -> Arc<FontTemplateData> {
        let last_resort = last_resort_font_families();

        for family in &last_resort {
            let family = LowercaseString::new(family);
            let maybe_font_in_family = self.find_font_in_local_family(&family, desc);
            if let Some(family) = maybe_font_in_family {
                return family;
            }
        }

        panic!("Unable to find any fonts that match (do you have fallback fonts installed?)");
    }
}

/// The public interface to the font cache task, used exclusively by
/// the per-thread/task FontContext structures.
#[derive(Clone, Deserialize, Serialize, Debug)]
pub struct FontCacheTask {
    chan: IpcSender<Command>,
}

impl FontCacheTask {
    pub fn new(resource_task: ResourceTask) -> FontCacheTask {
        let (chan, port) = ipc::channel().unwrap();

        let channel_to_self = chan.clone();
        spawn_named("FontCacheTask".to_owned(), move || {
            // TODO: Allow users to specify these.
            let generic_fonts = populate_generic_fonts();

            let mut cache = FontCache {
                port: port,
                channel_to_self: channel_to_self,
                generic_fonts: generic_fonts,
                local_families: HashMap::new(),
                web_families: HashMap::new(),
                font_context: FontContextHandle::new(),
                resource_task: resource_task,
            };

            cache.refresh_local_families();
            cache.run();
        });

        FontCacheTask {
            chan: chan,
        }
    }

    pub fn find_font_template(&self, family: FontFamily, desc: FontTemplateDescriptor)
                                                -> Option<Arc<FontTemplateData>> {

        let (response_chan, response_port) = ipc::channel().unwrap();
        self.chan.send(Command::GetFontTemplate(family, desc, response_chan)).unwrap();

        let reply = response_port.recv().unwrap();

        match reply {
            Reply::GetFontTemplateReply(data) => {
                data
            }
        }
    }

    pub fn last_resort_font_template(&self, desc: FontTemplateDescriptor)
                                                -> Arc<FontTemplateData> {

        let (response_chan, response_port) = ipc::channel().unwrap();
        self.chan.send(Command::GetLastResortFontTemplate(desc, response_chan)).unwrap();

        let reply = response_port.recv().unwrap();

        match reply {
            Reply::GetFontTemplateReply(data) => {
                data.unwrap()
            }
        }
    }

    pub fn add_web_font(&self, family: FontFamily, src: Source, sender: IpcSender<()>) {
        self.chan.send(Command::AddWebFont(family, src, sender)).unwrap();
    }

    pub fn exit(&self) {
        let (response_chan, response_port) = ipc::channel().unwrap();
        self.chan.send(Command::Exit(response_chan)).unwrap();
        response_port.recv().unwrap();
    }
}

// derived from http://stackoverflow.com/a/10864297/3830
fn is_supported_font_type(toplevel: &TopLevel, sublevel: &SubLevel) -> bool {
    if !prefs::get_pref("net.mime.sniff").as_boolean().unwrap_or(false) {
        return true;
    }

    match (toplevel, sublevel) {
        (&TopLevel::Application, &SubLevel::Ext(ref ext)) => {
            match &ext[..] {
                //FIXME: once sniffing is enabled by default, we shouldn't need nonstandard
                //       MIME types here.
                "font-sfnt" | "x-font-ttf" | "x-font-truetype" | "x-font-opentype" => true,
                _ => false,
            }
        }
        _ => false,
    }
}
<|endoftext|>


<commit_before>//!
//! [`Device`](Device) and [`Surface`](Surface)
//! implementations using gbm buffers for efficient rendering.
//!
//! Usually this implementation will be wrapped into a [`EglDevice`](::backend::drm::egl::EglDevice).
//! Take a look at `anvil`s source code for an example of this.
//!
//! To use these types standalone, you will need to consider the special requirements
//! of [`GbmSurface::page_flip`](::backend::drm::gbm::GbmSurface::page_flip).
//!

use super::{Device, DeviceHandler, RawDevice, ResourceHandles, Surface};
use crate::backend::graphics::SwapBuffersError;

use drm::control::{connector, crtc, encoder, framebuffer, plane, Device as ControlDevice, Mode};
use drm::SystemError as DrmError;
use gbm::{self, BufferObjectFlags, Format as GbmFormat};
use nix::libc::dev_t;

use std::cell::{Cell, RefCell};
use std::collections::HashMap;
use std::io;
use std::os::unix::io::{AsRawFd, RawFd};
use std::rc::{Rc, Weak};
use std::sync::Once;

/// Errors thrown by the [`GbmDevice`](::backend::drm::gbm::GbmDevice)
/// and [`GbmSurface`](::backend::drm::gbm::GbmSurface).
#[derive(thiserror::Error, Debug)]
pub enum Error<U: std::error::Error + 'static> {
    /// Creation of GBM device failed
    #[error("Creation of GBM device failed")]
    InitFailed(#[source] io::Error),
    /// Creation of GBM surface failed
    #[error("Creation of GBM surface failed")]
    SurfaceCreationFailed(#[source] io::Error),
    /// Creation of GBM buffer object failed
    #[error("Creation of GBM buffer object failed")]
    BufferCreationFailed(#[source] io::Error),
    /// Writing to GBM buffer failed
    #[error("Writing to GBM buffer failed")]
    BufferWriteFailed(#[source] io::Error),
    /// Creation of drm framebuffer failed
    #[error("Creation of drm framebuffer failed")]
    FramebufferCreationFailed(#[source] failure::Compat<drm::SystemError>),
    /// Lock of GBM surface front buffer failed
    #[error("Lock of GBM surface font buffer failed")]
    FrontBufferLockFailed,
    /// No additional buffers are available
    #[error("No additional buffers are available. Did you swap twice?")]
    FrontBuffersExhausted,
    /// Internal state was modified
    #[error("Internal state was modified. Did you change gbm userdata?")]
    InvalidInternalState,
    /// The GBM device was destroyed
    #[error("The GBM device was destroyed")]
    DeviceDestroyed,
    /// Underlying backend error
    #[error("Underlying error: {0}")]
    Underlying(#[source] U),
}

mod surface;
pub use self::surface::GbmSurface;
use self::surface::GbmSurfaceInternal;

#[cfg(feature = "backend_egl")]
pub mod egl;

#[cfg(feature = "backend_session")]
pub mod session;

static LOAD: Once = Once::new();

/// Representation of an open gbm device to create rendering surfaces
pub struct GbmDevice<D: RawDevice + ControlDevice + 'static> {
    pub(self) dev: Rc<RefCell<gbm::Device<D>>>,
    backends: Rc<RefCell<HashMap<crtc::Handle, Weak<GbmSurfaceInternal<D>>>>>,
    logger: ::slog::Logger,
}

impl<D: RawDevice + ControlDevice + 'static> GbmDevice<D> {
    /// Create a new [`GbmDevice`] from an open drm node
    ///
    /// Returns an error if the file is no valid drm node or context creation was not
    /// successful.
    pub fn new<L>(mut dev: D, logger: L) -> Result<Self, Error<<<D as Device>::Surface as Surface>::Error>>
    where
        L: Into<Option<::slog::Logger>>,
    {
        /* GBM will load a dri driver, but even though they need symbols from
         * libglapi, in some version of Mesa they are not linked to it. Since
         * only the gl-renderer module links to it, these symbols won't be
         * globally available, and loading the DRI driver fails.
         * Workaround this by dlopen()'ing libglapi with RTLD_GLOBAL.
         */
        LOAD.call_once(|| unsafe {
            nix::libc::dlopen(
                "libglapi.so.0".as_ptr() as *const _,
                nix::libc::RTLD_LAZY | nix::libc::RTLD_GLOBAL,
            );
        });

        let log = crate::slog_or_stdlog(logger).new(o!("smithay_module" => "backend_gbm"));

        dev.clear_handler();

        debug!(log, "Creating gbm device");
        Ok(GbmDevice {
            // Open the gbm device from the drm device
            dev: Rc::new(RefCell::new(gbm::Device::new(dev).map_err(Error::InitFailed)?)),
            backends: Rc::new(RefCell::new(HashMap::new())),
            logger: log,
        })
    }
}

struct InternalDeviceHandler<D: RawDevice + ControlDevice + 'static> {
    handler: Box<dyn DeviceHandler<Device = GbmDevice<D>> + 'static>,
    backends: Weak<RefCell<HashMap<crtc::Handle, Weak<GbmSurfaceInternal<D>>>>>,
    logger: ::slog::Logger,
}

impl<D: RawDevice + ControlDevice + 'static> DeviceHandler for InternalDeviceHandler<D> {
    type Device = D;

    fn vblank(&mut self, crtc: crtc::Handle) {
        if let Some(backends) = self.backends.upgrade() {
            if let Some(surface) = backends.borrow().get(&crtc) {
                if let Some(surface) = surface.upgrade() {
                    surface.unlock_buffer();
                    self.handler.vblank(crtc);
                }
            } else {
                warn!(
                    self.logger,
                    "Surface ({:?}) not managed by gbm, event not handled.", crtc
                );
            }
        }
    }
    fn error(&mut self, error: <<D as Device>::Surface as Surface>::Error) {
        self.handler.error(Error::Underlying(error))
    }
}

impl<D: RawDevice + ControlDevice + 'static> Device for GbmDevice<D> {
    type Surface = GbmSurface<D>;

    fn device_id(&self) -> dev_t {
        self.dev.borrow().device_id()
    }

    fn set_handler(&mut self, handler: impl DeviceHandler<Device = Self> + 'static) {
        self.dev.borrow_mut().set_handler(InternalDeviceHandler {
            handler: Box::new(handler),
            backends: Rc::downgrade(&self.backends),
            logger: self.logger.clone(),
        });
    }

    fn clear_handler(&mut self) {
        self.dev.borrow_mut().clear_handler();
    }

    fn create_surface(
        &mut self,
        crtc: crtc::Handle,
        mode: Mode,
        connectors: &[connector::Handle],
    ) -> Result<GbmSurface<D>, Error<<<D as Device>::Surface as Surface>::Error>> {
        info!(self.logger, "Initializing GbmSurface");

        let drm_surface = Device::create_surface(&mut **self.dev.borrow_mut(), crtc, mode, connectors)
            .map_err(Error::Underlying)?;

        // initialize the surface
        let (w, h) = drm_surface.pending_mode().size();
        let surface = self
            .dev
            .borrow()
            .create_surface(
                w as u32,
                h as u32,
                GbmFormat::XRGB8888,
                BufferObjectFlags::SCANOUT | BufferObjectFlags::RENDERING,
            )
            .map_err(Error::SurfaceCreationFailed)?;

        // initialize a buffer for the cursor image
        let cursor = Cell::new((
            self.dev
                .borrow()
                .create_buffer_object(
                    1,
                    1,
                    GbmFormat::ARGB8888,
                    BufferObjectFlags::CURSOR | BufferObjectFlags::WRITE,
                )
                .map_err(Error::BufferCreationFailed)?,
            (0, 0),
        ));

        let backend = Rc::new(GbmSurfaceInternal {
            dev: self.dev.clone(),
            surface: RefCell::new(surface),
            crtc: drm_surface,
            cursor,
            current_frame_buffer: Cell::new(None),
            front_buffer: Cell::new(None),
            next_buffer: Cell::new(None),
            recreated: Cell::new(true),
            logger: self.logger.new(o!("crtc" => format!("{:?}", crtc))),
        });
        self.backends.borrow_mut().insert(crtc, Rc::downgrade(&backend));
        Ok(GbmSurface(backend))
    }

    fn process_events(&mut self) {
        self.dev.borrow_mut().process_events()
    }

    fn resource_handles(&self) -> Result<ResourceHandles, Error<<<D as Device>::Surface as Surface>::Error>> {
        Device::resource_handles(&**self.dev.borrow()).map_err(Error::Underlying)
    }

    fn get_connector_info(&self, conn: connector::Handle) -> std::result::Result<connector::Info, DrmError> {
        self.dev.borrow().get_connector_info(conn)
    }
    fn get_crtc_info(&self, crtc: crtc::Handle) -> std::result::Result<crtc::Info, DrmError> {
        self.dev.borrow().get_crtc_info(crtc)
    }
    fn get_encoder_info(&self, enc: encoder::Handle) -> std::result::Result<encoder::Info, DrmError> {
        self.dev.borrow().get_encoder_info(enc)
    }
    fn get_framebuffer_info(
        &self,
        fb: framebuffer::Handle,
    ) -> std::result::Result<framebuffer::Info, DrmError> {
        self.dev.borrow().get_framebuffer_info(fb)
    }
    fn get_plane_info(&self, plane: plane::Handle) -> std::result::Result<plane::Info, DrmError> {
        self.dev.borrow().get_plane_info(plane)
    }
}

impl<D: RawDevice + ControlDevice + 'static> AsRawFd for GbmDevice<D> {
    fn as_raw_fd(&self) -> RawFd {
        self.dev.borrow().as_raw_fd()
    }
}

impl<D: RawDevice + ControlDevice + 'static> Drop for GbmDevice<D> {
    fn drop(&mut self) {
        self.clear_handler();
    }
}

impl<E> Into<SwapBuffersError> for Error<E>
where
    E: std::error::Error + Into<SwapBuffersError> + 'static,
{
    fn into(self) -> SwapBuffersError {
        match self {
            Error::FrontBuffersExhausted => SwapBuffersError::AlreadySwapped,
            Error::FramebufferCreationFailed(x)
                if match x.get_ref() {
                    drm::SystemError::Unknown {
                        errno: nix::errno::Errno::EBUSY,
                    } => true,
                    drm::SystemError::Unknown {
                        errno: nix::errno::Errno::EINTR,
                    } => true,
                    _ => false,
                } =>
            {
                SwapBuffersError::TemporaryFailure(Box::new(x))
            }
            Error::Underlying(x) => x.into(),
            x => SwapBuffersError::ContextLost(Box::new(x)),
        }
    }
}
<commit_msg>gbm: Do not unpack drm-rs errors on conversion<commit_after>//!
//! [`Device`](Device) and [`Surface`](Surface)
//! implementations using gbm buffers for efficient rendering.
//!
//! Usually this implementation will be wrapped into a [`EglDevice`](::backend::drm::egl::EglDevice).
//! Take a look at `anvil`s source code for an example of this.
//!
//! To use these types standalone, you will need to consider the special requirements
//! of [`GbmSurface::page_flip`](::backend::drm::gbm::GbmSurface::page_flip).
//!

use super::{Device, DeviceHandler, RawDevice, ResourceHandles, Surface};
use crate::backend::graphics::SwapBuffersError;

use drm::control::{connector, crtc, encoder, framebuffer, plane, Device as ControlDevice, Mode};
use drm::SystemError as DrmError;
use gbm::{self, BufferObjectFlags, Format as GbmFormat};
use nix::libc::dev_t;

use std::cell::{Cell, RefCell};
use std::collections::HashMap;
use std::io;
use std::os::unix::io::{AsRawFd, RawFd};
use std::rc::{Rc, Weak};
use std::sync::Once;

/// Errors thrown by the [`GbmDevice`](::backend::drm::gbm::GbmDevice)
/// and [`GbmSurface`](::backend::drm::gbm::GbmSurface).
#[derive(thiserror::Error, Debug)]
pub enum Error<U: std::error::Error + 'static> {
    /// Creation of GBM device failed
    #[error("Creation of GBM device failed")]
    InitFailed(#[source] io::Error),
    /// Creation of GBM surface failed
    #[error("Creation of GBM surface failed")]
    SurfaceCreationFailed(#[source] io::Error),
    /// Creation of GBM buffer object failed
    #[error("Creation of GBM buffer object failed")]
    BufferCreationFailed(#[source] io::Error),
    /// Writing to GBM buffer failed
    #[error("Writing to GBM buffer failed")]
    BufferWriteFailed(#[source] io::Error),
    /// Creation of drm framebuffer failed
    #[error("Creation of drm framebuffer failed")]
    FramebufferCreationFailed(#[source] failure::Compat<drm::SystemError>),
    /// Lock of GBM surface front buffer failed
    #[error("Lock of GBM surface font buffer failed")]
    FrontBufferLockFailed,
    /// No additional buffers are available
    #[error("No additional buffers are available. Did you swap twice?")]
    FrontBuffersExhausted,
    /// Internal state was modified
    #[error("Internal state was modified. Did you change gbm userdata?")]
    InvalidInternalState,
    /// The GBM device was destroyed
    #[error("The GBM device was destroyed")]
    DeviceDestroyed,
    /// Underlying backend error
    #[error("Underlying error: {0}")]
    Underlying(#[source] U),
}

mod surface;
pub use self::surface::GbmSurface;
use self::surface::GbmSurfaceInternal;

#[cfg(feature = "backend_egl")]
pub mod egl;

#[cfg(feature = "backend_session")]
pub mod session;

static LOAD: Once = Once::new();

/// Representation of an open gbm device to create rendering surfaces
pub struct GbmDevice<D: RawDevice + ControlDevice + 'static> {
    pub(self) dev: Rc<RefCell<gbm::Device<D>>>,
    backends: Rc<RefCell<HashMap<crtc::Handle, Weak<GbmSurfaceInternal<D>>>>>,
    logger: ::slog::Logger,
}

impl<D: RawDevice + ControlDevice + 'static> GbmDevice<D> {
    /// Create a new [`GbmDevice`] from an open drm node
    ///
    /// Returns an error if the file is no valid drm node or context creation was not
    /// successful.
    pub fn new<L>(mut dev: D, logger: L) -> Result<Self, Error<<<D as Device>::Surface as Surface>::Error>>
    where
        L: Into<Option<::slog::Logger>>,
    {
        /* GBM will load a dri driver, but even though they need symbols from
         * libglapi, in some version of Mesa they are not linked to it. Since
         * only the gl-renderer module links to it, these symbols won't be
         * globally available, and loading the DRI driver fails.
         * Workaround this by dlopen()'ing libglapi with RTLD_GLOBAL.
         */
        LOAD.call_once(|| unsafe {
            nix::libc::dlopen(
                "libglapi.so.0".as_ptr() as *const _,
                nix::libc::RTLD_LAZY | nix::libc::RTLD_GLOBAL,
            );
        });

        let log = crate::slog_or_stdlog(logger).new(o!("smithay_module" => "backend_gbm"));

        dev.clear_handler();

        debug!(log, "Creating gbm device");
        Ok(GbmDevice {
            // Open the gbm device from the drm device
            dev: Rc::new(RefCell::new(gbm::Device::new(dev).map_err(Error::InitFailed)?)),
            backends: Rc::new(RefCell::new(HashMap::new())),
            logger: log,
        })
    }
}

struct InternalDeviceHandler<D: RawDevice + ControlDevice + 'static> {
    handler: Box<dyn DeviceHandler<Device = GbmDevice<D>> + 'static>,
    backends: Weak<RefCell<HashMap<crtc::Handle, Weak<GbmSurfaceInternal<D>>>>>,
    logger: ::slog::Logger,
}

impl<D: RawDevice + ControlDevice + 'static> DeviceHandler for InternalDeviceHandler<D> {
    type Device = D;

    fn vblank(&mut self, crtc: crtc::Handle) {
        if let Some(backends) = self.backends.upgrade() {
            if let Some(surface) = backends.borrow().get(&crtc) {
                if let Some(surface) = surface.upgrade() {
                    surface.unlock_buffer();
                    self.handler.vblank(crtc);
                }
            } else {
                warn!(
                    self.logger,
                    "Surface ({:?}) not managed by gbm, event not handled.", crtc
                );
            }
        }
    }
    fn error(&mut self, error: <<D as Device>::Surface as Surface>::Error) {
        self.handler.error(Error::Underlying(error))
    }
}

impl<D: RawDevice + ControlDevice + 'static> Device for GbmDevice<D> {
    type Surface = GbmSurface<D>;

    fn device_id(&self) -> dev_t {
        self.dev.borrow().device_id()
    }

    fn set_handler(&mut self, handler: impl DeviceHandler<Device = Self> + 'static) {
        self.dev.borrow_mut().set_handler(InternalDeviceHandler {
            handler: Box::new(handler),
            backends: Rc::downgrade(&self.backends),
            logger: self.logger.clone(),
        });
    }

    fn clear_handler(&mut self) {
        self.dev.borrow_mut().clear_handler();
    }

    fn create_surface(
        &mut self,
        crtc: crtc::Handle,
        mode: Mode,
        connectors: &[connector::Handle],
    ) -> Result<GbmSurface<D>, Error<<<D as Device>::Surface as Surface>::Error>> {
        info!(self.logger, "Initializing GbmSurface");

        let drm_surface = Device::create_surface(&mut **self.dev.borrow_mut(), crtc, mode, connectors)
            .map_err(Error::Underlying)?;

        // initialize the surface
        let (w, h) = drm_surface.pending_mode().size();
        let surface = self
            .dev
            .borrow()
            .create_surface(
                w as u32,
                h as u32,
                GbmFormat::XRGB8888,
                BufferObjectFlags::SCANOUT | BufferObjectFlags::RENDERING,
            )
            .map_err(Error::SurfaceCreationFailed)?;

        // initialize a buffer for the cursor image
        let cursor = Cell::new((
            self.dev
                .borrow()
                .create_buffer_object(
                    1,
                    1,
                    GbmFormat::ARGB8888,
                    BufferObjectFlags::CURSOR | BufferObjectFlags::WRITE,
                )
                .map_err(Error::BufferCreationFailed)?,
            (0, 0),
        ));

        let backend = Rc::new(GbmSurfaceInternal {
            dev: self.dev.clone(),
            surface: RefCell::new(surface),
            crtc: drm_surface,
            cursor,
            current_frame_buffer: Cell::new(None),
            front_buffer: Cell::new(None),
            next_buffer: Cell::new(None),
            recreated: Cell::new(true),
            logger: self.logger.new(o!("crtc" => format!("{:?}", crtc))),
        });
        self.backends.borrow_mut().insert(crtc, Rc::downgrade(&backend));
        Ok(GbmSurface(backend))
    }

    fn process_events(&mut self) {
        self.dev.borrow_mut().process_events()
    }

    fn resource_handles(&self) -> Result<ResourceHandles, Error<<<D as Device>::Surface as Surface>::Error>> {
        Device::resource_handles(&**self.dev.borrow()).map_err(Error::Underlying)
    }

    fn get_connector_info(&self, conn: connector::Handle) -> std::result::Result<connector::Info, DrmError> {
        self.dev.borrow().get_connector_info(conn)
    }
    fn get_crtc_info(&self, crtc: crtc::Handle) -> std::result::Result<crtc::Info, DrmError> {
        self.dev.borrow().get_crtc_info(crtc)
    }
    fn get_encoder_info(&self, enc: encoder::Handle) -> std::result::Result<encoder::Info, DrmError> {
        self.dev.borrow().get_encoder_info(enc)
    }
    fn get_framebuffer_info(
        &self,
        fb: framebuffer::Handle,
    ) -> std::result::Result<framebuffer::Info, DrmError> {
        self.dev.borrow().get_framebuffer_info(fb)
    }
    fn get_plane_info(&self, plane: plane::Handle) -> std::result::Result<plane::Info, DrmError> {
        self.dev.borrow().get_plane_info(plane)
    }
}

impl<D: RawDevice + ControlDevice + 'static> AsRawFd for GbmDevice<D> {
    fn as_raw_fd(&self) -> RawFd {
        self.dev.borrow().as_raw_fd()
    }
}

impl<D: RawDevice + ControlDevice + 'static> Drop for GbmDevice<D> {
    fn drop(&mut self) {
        self.clear_handler();
    }
}

impl<E> Into<SwapBuffersError> for Error<E>
where
    E: std::error::Error + Into<SwapBuffersError> + 'static,
{
    fn into(self) -> SwapBuffersError {
        match self {
            Error::FrontBuffersExhausted => SwapBuffersError::AlreadySwapped,
            Error::FramebufferCreationFailed(x)
                if match x.get_ref() {
                    drm::SystemError::Unknown {
                        errno: nix::errno::Errno::EBUSY,
                    } => true,
                    drm::SystemError::Unknown {
                        errno: nix::errno::Errno::EINTR,
                    } => true,
                    _ => false,
                } =>
            {
                SwapBuffersError::TemporaryFailure(Box::new(Error::<E>::FramebufferCreationFailed(x)))
            }
            Error::Underlying(x) => x.into(),
            x => SwapBuffersError::ContextLost(Box::new(x)),
        }
    }
}
<|endoftext|>


<commit_before>use sqlite::{Connection, Statement, State};
use std::mem;
use std::path::Path;

use output::Output;
use streamer::platform::{Platform, Profile};
use {Data, Event, Result, System};

pub struct Database {
    #[allow(dead_code)]
    connection: Connection,
    statement: Statement<'static>,
}

impl Database {
    pub fn new<T: AsRef<Path>>(system: &System, path: T) -> Result<Database> {
        use sql::prelude::*;

        let connection = ok!(Connection::open(path));

        ok!(connection.execute({
            ok!(create_table("dynamic").if_not_exists().columns(&[
                "time".float().not_null(), "component_id".integer().not_null(),
                "power".float().not_null(), "temperature".float().not_null(),
            ]).compile())
        }));

        ok!(connection.execute(ok!(delete_from("dynamic").compile())));

        ok!(connection.execute("
            PRAGMA journal_mode = MEMORY;
            PRAGMA synchronous = OFF;
        "));

        let statement = {
            let units = system.platform().elements().len();
            let statement = ok!(connection.prepare({
                ok!(insert_into("dynamic").columns(&[
                    "time", "component_id", "power", "temperature",
                ]).batch(units).compile())
            }));
            unsafe { mem::transmute(statement) }
        };

        Ok(Database { connection: connection, statement: statement })
    }
}

impl Output for Database {
    fn next(&mut self, _: &Event, &(ref power, ref temperature): &Data) -> Result<()> {
        let &Profile { units, steps, time, time_step, data: ref power } = power;
        let &Profile { data: ref temperature, .. } = temperature;
        ok!(self.connection.execute("BEGIN TRANSACTION"));
        let statement = &mut self.statement;
        for i in 0..steps {
            let time = time + (i as f64) * time_step;
            ok!(statement.reset());
            let mut k = 0;
            for j in 0..units {
                ok!(statement.bind(k + 1, time));
                ok!(statement.bind(k + 2, j as i64));
                ok!(statement.bind(k + 3, power[i * units + j]));
                ok!(statement.bind(k + 4, temperature[i * units + j]));
                k += 4;
            }
            if State::Done != ok!(statement.next()) {
                raise!("failed to write into the database");
            }
        }
        ok!(self.connection.execute("END TRANSACTION"));
        Ok(())
    }
}
<commit_msg>bin/streamer: dump arrival times<commit_after>use sqlite::{Connection, Statement, State};
use std::mem;
use std::path::Path;

use output::Output;
use streamer::platform::{Platform, Profile};
use streamer::system::{EventKind, Job};
use {Data, Event, Result, System};

pub struct Database {
    #[allow(dead_code)]
    connection: Connection,
    arrivals: Statement<'static>,
    profiles: Statement<'static>,
}

impl Database {
    pub fn new<T: AsRef<Path>>(system: &System, path: T) -> Result<Database> {
        use sql::prelude::*;

        let connection = ok!(Connection::open(path));

        ok!(connection.execute("
            PRAGMA journal_mode = MEMORY;
            PRAGMA synchronous = OFF;
        "));

        ok!(connection.execute({
            ok!(create_table("arrivals").if_not_exists().columns(&[
                "time".float().not_null(),
            ]).compile())
        }));
        ok!(connection.execute({
            ok!(create_table("profiles").if_not_exists().columns(&[
                "time".float().not_null(), "component_id".integer().not_null(),
                "power".float().not_null(), "temperature".float().not_null(),
            ]).compile())
        }));

        ok!(connection.execute(ok!(delete_from("arrivals").compile())));
        ok!(connection.execute(ok!(delete_from("profiles").compile())));

        let arrivals = {
            let statement = ok!(connection.prepare({
                ok!(insert_into("arrivals").columns(&[
                    "time",
                ]).compile())
            }));
            unsafe { mem::transmute(statement) }
        };
        let profiles = {
            let units = system.platform().elements().len();
            let statement = ok!(connection.prepare({
                ok!(insert_into("profiles").columns(&[
                    "time", "component_id", "power", "temperature",
                ]).batch(units).compile())
            }));
            unsafe { mem::transmute(statement) }
        };

        Ok(Database {
            connection: connection,
            arrivals: arrivals,
            profiles: profiles,
        })
    }

    fn write_arrival(&mut self, job: &Job) -> Result<()> {
        let statement = &mut self.arrivals;
        ok!(statement.bind(1, job.arrival));
        if State::Done != ok!(statement.next()) {
            raise!("failed to write into the database");
        }
        Ok(())
    }

    fn write_profile(&mut self, power: &Profile, temperature: &Profile) -> Result<()> {
        let &Profile { units, steps, time, time_step, data: ref power } = power;
        let &Profile { data: ref temperature, .. } = temperature;
        let statement = &mut self.profiles;
        for i in 0..steps {
            let time = time + (i as f64) * time_step;
            ok!(statement.reset());
            let mut k = 0;
            for j in 0..units {
                ok!(statement.bind(k + 1, time));
                ok!(statement.bind(k + 2, j as i64));
                ok!(statement.bind(k + 3, power[i * units + j]));
                ok!(statement.bind(k + 4, temperature[i * units + j]));
                k += 4;
            }
            if State::Done != ok!(statement.next()) {
                raise!("failed to write into the database");
            }
        }
        Ok(())
    }
}

impl Output for Database {
    fn next(&mut self, event: &Event, &(ref power, ref temperature): &Data) -> Result<()> {
        ok!(self.connection.execute("BEGIN TRANSACTION"));
        if let &EventKind::Arrived(ref job) = &event.kind {
            ok!(self.write_arrival(job));
        }
        ok!(self.write_profile(power, temperature));
        ok!(self.connection.execute("END TRANSACTION"));
        Ok(())
    }
}
<|endoftext|>


<commit_before>extern crate rustc_serialize;
use rustc_serialize::base64::FromBase64;

use std::io::prelude::*;
use std::io::BufReader;
use std::fs::File;

fn main() {
	let data = match load_from_file() {
		Err(why) => panic!("Failed to read data/set1_challenge4.txt: {}", why),
		Ok(data) => data,
	};

	let mut smallest_keysize_distance = std::usize::MAX;
	let mut smallest_keysize = 0;

	for key_size in 2..41 {
		let str1 = &data[0..key_size]; // slice?
		let str2 = &data[key_size..key_size*2];
		let str3 = &data[key_size*2..key_size*3];
		let str4 = &data[key_size*3..key_size*4];

		let mut distances = Vec::new();

		distances.push(hamming_distance(str1, str2) / key_size);
		distances.push(hamming_distance(str1, str3) / key_size);
		distances.push(hamming_distance(str1, str4) / key_size);
		distances.push(hamming_distance(str2, str3) / key_size);
		distances.push(hamming_distance(str2, str4) / key_size);
		distances.push(hamming_distance(str3, str4) / key_size);

		let average_distance = distances.iter().fold(0, |total, &value| total + value);

		if average_distance < smallest_keysize_distance {
			smallest_keysize_distance = average_distance;
			smallest_keysize = key_size;
		}
	}
	println!("smallest_keysize_distance: {}, key_size: {}", smallest_keysize_distance, smallest_keysize);
}

fn load_from_file() -> std::io::Result<Vec<u8>> {
	let file = try!(File::open("data/set1_challenge6.txt"));
	let reader = BufReader::new(file);

	let mut data = String::new();

	for line in reader.lines() {
		data.push_str(&(line.unwrap()));
	}

	let decoded_data = data.from_base64().unwrap();
	return Ok(decoded_data);
}

/*
binary hamming distance
this is a test
wokka wokka!!!
-> 37
 */
fn hamming_distance(str1: &[u8], str2: &[u8]) -> usize {
    let mut distance = 0;

    for i in 0..str1.len() {
		let diff = str1[i] ^ str2[i];
        if (diff & 0b00000001) > 0 { distance += 1; }
        if (diff & 0b00000010) > 0 { distance += 1; }
        if (diff & 0b00000100) > 0 { distance += 1; }
        if (diff & 0b00001000) > 0 { distance += 1; }
        if (diff & 0b00010000) > 0 { distance += 1; }
        if (diff & 0b00100000) > 0 { distance += 1; }
        if (diff & 0b01000000) > 0 { distance += 1; }
        if (diff & 0b10000000) > 0 { distance += 1; }
    }
    return distance;
}
<commit_msg>set1 challenge6: refactored key size guessing in its own function<commit_after>extern crate rustc_serialize;
use rustc_serialize::base64::FromBase64;

use std::io::prelude::*;
use std::io::BufReader;
use std::fs::File;

fn main() {
	let data = match load_from_file() {
		Err(why) => panic!("Failed to read data/set1_challenge4.txt: {}", why),
		Ok(data) => data,
	};

	let key_size = guess_key_size(&data);
	println!("guesses key size: {}", key_size);
}

fn load_from_file() -> std::io::Result<Vec<u8>> {
	let file = try!(File::open("data/set1_challenge6.txt"));
	let reader = BufReader::new(file);

	let mut data = String::new();

	for line in reader.lines() {
		data.push_str(&(line.unwrap()));
	}

	let decoded_data = data.from_base64().unwrap();
	return Ok(decoded_data);
}

fn guess_key_size(data: &[u8]) -> usize {
	let mut smallest_key_size_distance = std::usize::MAX;
	let mut guessed_key_size = 0;

	for key_size in 2..41 {
		let str1 = &data[0..key_size]; // slice?
		let str2 = &data[key_size..key_size*2];
		let str3 = &data[key_size*2..key_size*3];
		let str4 = &data[key_size*3..key_size*4];

		let mut distances = Vec::new();

		distances.push(hamming_distance(str1, str2) / key_size)                                                                          ;
		distances.push(hamming_distance(str1, str3) / key_size);
		distances.push(hamming_distance(str1, str4) / key_size);
		distances.push(hamming_distance(str2, str3) / key_size);
		distances.push(hamming_distance(str2, str4) / key_size);
		distances.push(hamming_distance(str3, str4) / key_size)                                                                          ;

		let average_distance = distances.iter().fold(0, |total, &value| total + value);

		if average_distance < smallest_key_size_distance {
			smallest_key_size_distance = average_distance;
			guessed_key_size = key_size;
		}
	}
	return guessed_key_size;
}

/*
binary hamming distance
this is a test
wokka wokka!!!
-> 37
 */
fn hamming_distance(str1: &[u8], str2: &[u8]) -> usize {
    let mut distance = 0;

    for i in 0..str1.len() {
		let diff = str1[i] ^ str2[i];
        if (diff & 0b00000001) > 0 { distance += 1; }
        if (diff & 0b00000010) > 0 { distance += 1; }
        if (diff & 0b00000100) > 0 { distance += 1; }
        if (diff & 0b00001000) > 0 { distance += 1; }
        if (diff & 0b00010000) > 0 { distance += 1; }
        if (diff & 0b00100000) > 0 { distance += 1; }
        if (diff & 0b01000000) > 0 { distance += 1; }
        if (diff & 0b10000000) > 0 { distance += 1; }
    }
    return distance;
}

<|endoftext|>


<commit_before>use core::ptr;
use core::slice;
use header::Tag;

#[derive(Debug, PartialEq)]
pub struct FramebufferTag<'a> {
    pub address: u64,
    pub pitch: u32,
    pub width: u32,
    pub height: u32,
    pub bpp: u8,
    pub buffer_type: FramebufferType<'a>
}

#[derive(Debug, PartialEq)]
pub enum FramebufferType<'a> {
    Indexed {
        palette: &'a [FramebufferColor]
    },
    RGB {
        red: FramebufferField,
        green: FramebufferField,
        blue: FramebufferField
    },
    Text
}

#[derive(Debug, PartialEq)]
pub struct FramebufferField {
    position: u8,
    size: u8
}

#[derive(Debug, PartialEq)]
#[repr(C, packed)]
pub struct FramebufferColor {
    red: u8,
    green: u8,
    blue: u8
}

struct Reader {
    ptr: *const u8,
    off: usize
}

impl Reader {
    fn new<T>(ptr: *const T) -> Reader {
        Reader {
            ptr: ptr as *const u8,
            off: 0
        }
    }

    fn read_u8(&mut self) -> u8 {
        self.off += 1;
        unsafe {
            ptr::read(self.ptr.offset((self.off - 1) as isize))
        }
    }

    fn read_u16(&mut self) -> u16 {
        self.read_u8() as u16 | (self.read_u8() as u16) << 8
    }

    fn read_u32(&mut self) -> u32 {
        self.read_u16() as u32 | (self.read_u16() as u32) << 16
    }

    fn read_u64(&mut self) -> u64 {
        self.read_u32() as u64 | (self.read_u32() as u64) << 32
    }

    fn skip(&mut self, n: usize) {
        self.off += n;
    }
}

pub fn framebuffer_tag<'a>(tag: &'a Tag) -> FramebufferTag<'a> {
    let mut reader = Reader::new(tag as *const Tag);
    reader.skip(8);
    let address = reader.read_u64();
    let pitch = reader.read_u32();
    let width = reader.read_u32();
    let height = reader.read_u32();
    let bpp = reader.read_u8();
    let type_no = reader.read_u8();
    reader.skip(2); // In the multiboot spec, it has this listed as a u8 _NOT_ a u16.
                    // Reading the GRUB2 source code reveals it is in fact a u16.
    let buffer_type = match type_no {
        0 =>  {
            let num_colors = reader.read_u32();
            let palette = unsafe {
                slice::from_raw_parts(reader.ptr.offset(reader.off as isize) as *const FramebufferColor, num_colors as usize)
            } as &'static [FramebufferColor];
            FramebufferType::Indexed { palette }
        },
        1 => {
            let red_pos = reader.read_u8();     //These refer to the bit positions of the MSB of each field
            let red_mask = reader.read_u8();    //And then the length of the field from MSB to LSB
            let green_pos = reader.read_u8();
            let green_mask = reader.read_u8();
            let blue_pos = reader.read_u8();
            let blue_mask = reader.read_u8();
            FramebufferType::RGB {
                red: FramebufferField { position: red_pos, size: red_mask },
                green: FramebufferField { position: green_pos, size: green_mask },
                blue: FramebufferField { position: blue_pos, size: blue_mask }
            }
        },
        2 => FramebufferType::Text,
        _ => panic!("Unknown framebuffer type: {}", type_no)
    };

    FramebufferTag {
        address,
        pitch,
        width,
        height,
        bpp,
        buffer_type
    }
}
<commit_msg>Fix public modifiers.<commit_after>use core::ptr;
use core::slice;
use header::Tag;

#[derive(Debug, PartialEq)]
pub struct FramebufferTag<'a> {
    pub address: u64,
    pub pitch: u32,
    pub width: u32,
    pub height: u32,
    pub bpp: u8,
    pub buffer_type: FramebufferType<'a>
}

#[derive(Debug, PartialEq)]
pub enum FramebufferType<'a> {
    Indexed {
        palette: &'a [FramebufferColor]
    },
    RGB {
        red: FramebufferField,
        green: FramebufferField,
        blue: FramebufferField
    },
    Text
}

#[derive(Debug, PartialEq)]
pub struct FramebufferField {
    pub position: u8,
    pub size: u8
}

#[derive(Debug, PartialEq)]
#[repr(C, packed)]
pub struct FramebufferColor {
    pub red: u8,
    pub green: u8,
    pub blue: u8
}

struct Reader {
    ptr: *const u8,
    off: usize
}

impl Reader {
    fn new<T>(ptr: *const T) -> Reader {
        Reader {
            ptr: ptr as *const u8,
            off: 0
        }
    }

    fn read_u8(&mut self) -> u8 {
        self.off += 1;
        unsafe {
            ptr::read(self.ptr.offset((self.off - 1) as isize))
        }
    }

    fn read_u16(&mut self) -> u16 {
        self.read_u8() as u16 | (self.read_u8() as u16) << 8
    }

    fn read_u32(&mut self) -> u32 {
        self.read_u16() as u32 | (self.read_u16() as u32) << 16
    }

    fn read_u64(&mut self) -> u64 {
        self.read_u32() as u64 | (self.read_u32() as u64) << 32
    }

    fn skip(&mut self, n: usize) {
        self.off += n;
    }
}

pub fn framebuffer_tag<'a>(tag: &'a Tag) -> FramebufferTag<'a> {
    let mut reader = Reader::new(tag as *const Tag);
    reader.skip(8);
    let address = reader.read_u64();
    let pitch = reader.read_u32();
    let width = reader.read_u32();
    let height = reader.read_u32();
    let bpp = reader.read_u8();
    let type_no = reader.read_u8();
    reader.skip(2); // In the multiboot spec, it has this listed as a u8 _NOT_ a u16.
                    // Reading the GRUB2 source code reveals it is in fact a u16.
    let buffer_type = match type_no {
        0 =>  {
            let num_colors = reader.read_u32();
            let palette = unsafe {
                slice::from_raw_parts(reader.ptr.offset(reader.off as isize) as *const FramebufferColor, num_colors as usize)
            } as &'static [FramebufferColor];
            FramebufferType::Indexed { palette }
        },
        1 => {
            let red_pos = reader.read_u8();     //These refer to the bit positions of the MSB of each field
            let red_mask = reader.read_u8();    //And then the length of the field from MSB to LSB
            let green_pos = reader.read_u8();
            let green_mask = reader.read_u8();
            let blue_pos = reader.read_u8();
            let blue_mask = reader.read_u8();
            FramebufferType::RGB {
                red: FramebufferField { position: red_pos, size: red_mask },
                green: FramebufferField { position: green_pos, size: green_mask },
                blue: FramebufferField { position: blue_pos, size: blue_mask }
            }
        },
        2 => FramebufferType::Text,
        _ => panic!("Unknown framebuffer type: {}", type_no)
    };

    FramebufferTag {
        address,
        pitch,
        width,
        height,
        bpp,
        buffer_type
    }
}
<|endoftext|>


<commit_before>use std::collections::{BTreeMap, HashMap};
use std::path::{Path, PathBuf};
use std::sync::Arc;

use double_checked_cell_async::DoubleCheckedCell;
use fs::{Permissions, RelativePath};
use hashing::Digest;
use parking_lot::Mutex;
use store::Store;
use tempfile::TempDir;

use crate::WorkdirSymlink;

/// Holds Digests materialized into a temporary directory, for symlinking into local sandboxes.
pub struct ImmutableInputs {
  store: Store,
  // The TempDir that digests are materialized in.
  workdir: TempDir,
  // A map from Digest to the location it has been materialized at. The DoubleCheckedCell allows
  // for cooperation between threads attempting to create Digests.
  contents: Mutex<HashMap<Digest, Arc<DoubleCheckedCell<PathBuf>>>>,
}

impl ImmutableInputs {
  pub fn new(store: Store, base: &Path) -> Result<Self, String> {
    let workdir = TempDir::new_in(base).map_err(|e| {
      format!(
        "Failed to create temporary directory for immutable inputs: {}",
        e
      )
    })?;
    Ok(Self {
      store,
      workdir,
      contents: Mutex::default(),
    })
  }

  /// Returns an absolute Path to immutably consume the given Digest from.
  async fn path(&self, digest: Digest) -> Result<PathBuf, String> {
    let cell = self.contents.lock().entry(digest).or_default().clone();
    let value: Result<_, String> = cell
      .get_or_try_init(async {
        let digest_str = digest.hash.to_hex();

        let path = self.workdir.path().join(digest_str);
        self
          .store
          .materialize_directory(path.clone(), digest, Permissions::ReadOnly)
          .await?;
        Ok(path)
      })
      .await;
    Ok(value?.clone())
  }

  ///
  /// Returns symlinks to create for the given set of immutable cache paths.
  ///
  pub(crate) async fn local_paths(
    &self,
    immutable_inputs: &BTreeMap<RelativePath, Digest>,
  ) -> Result<Vec<WorkdirSymlink>, String> {
    let dsts = futures::future::try_join_all(
      immutable_inputs
        .values()
        .map(|d| self.path(*d))
        .collect::<Vec<_>>(),
    )
    .await?;

    Ok(
      immutable_inputs
        .keys()
        .zip(dsts.into_iter())
        .map(|(src, dst)| WorkdirSymlink {
          src: src.clone(),
          dst,
        })
        .collect(),
    )
  }
}
<commit_msg>[internal] Add output to confirm immutable input race condition. (#14013)<commit_after>use std::collections::{BTreeMap, HashMap};
use std::path::{Path, PathBuf};
use std::sync::Arc;

use double_checked_cell_async::DoubleCheckedCell;
use fs::{Permissions, RelativePath};
use hashing::Digest;
use parking_lot::Mutex;
use store::Store;
use tempfile::TempDir;

use crate::WorkdirSymlink;

/// Holds Digests materialized into a temporary directory, for symlinking into local sandboxes.
pub struct ImmutableInputs {
  store: Store,
  // The TempDir that digests are materialized in.
  workdir: TempDir,
  // A map from Digest to the location it has been materialized at. The DoubleCheckedCell allows
  // for cooperation between threads attempting to create Digests.
  contents: Mutex<HashMap<Digest, Arc<DoubleCheckedCell<PathBuf>>>>,
}

impl ImmutableInputs {
  pub fn new(store: Store, base: &Path) -> Result<Self, String> {
    let workdir = TempDir::new_in(base).map_err(|e| {
      format!(
        "Failed to create temporary directory for immutable inputs: {}",
        e
      )
    })?;
    Ok(Self {
      store,
      workdir,
      contents: Mutex::default(),
    })
  }

  /// Returns an absolute Path to immutably consume the given Digest from.
  async fn path(&self, digest: Digest) -> Result<PathBuf, String> {
    let cell = self.contents.lock().entry(digest).or_default().clone();
    let value: Result<_, String> = cell
      .get_or_try_init(async {
        let digest_str = digest.hash.to_hex();

        let path = self.workdir.path().join(digest_str);
        if let Ok(meta) = tokio::fs::metadata(&path).await {
          // TODO: If this error triggers, it indicates that we have previously checked out this
          // directory, either due to a race condition, or due to a previous failure to
          // materialize. See https://github.com/pantsbuild/pants/issues/13899
          return Err(format!(
            "Destination for immutable digest already exists: {:?}",
            meta
          ));
        }
        self
          .store
          .materialize_directory(path.clone(), digest, Permissions::ReadOnly)
          .await?;
        Ok(path)
      })
      .await;
    Ok(value?.clone())
  }

  ///
  /// Returns symlinks to create for the given set of immutable cache paths.
  ///
  pub(crate) async fn local_paths(
    &self,
    immutable_inputs: &BTreeMap<RelativePath, Digest>,
  ) -> Result<Vec<WorkdirSymlink>, String> {
    let dsts = futures::future::try_join_all(
      immutable_inputs
        .values()
        .map(|d| self.path(*d))
        .collect::<Vec<_>>(),
    )
    .await?;

    Ok(
      immutable_inputs
        .keys()
        .zip(dsts.into_iter())
        .map(|(src, dst)| WorkdirSymlink {
          src: src.clone(),
          dst,
        })
        .collect(),
    )
  }
}
<|endoftext|>


<commit_before>use std::path::Path;
use std::collections::HashMap;
use graphics::character::{ CharacterCache, Character };
use graphics::types::{ FontSize, Scalar };
use glium::texture::srgb_texture2d::SrgbTexture2d;
use glium::backend::Facade;
use glium::texture::RawImage2d;
use image::{ Rgba, ImageBuffer };
use freetype::{ self, Face };
use Texture;

/// Caches characters for a font.
pub struct GlyphCache<F> {
    face: Face<'static>,
    data: HashMap<(FontSize, char), ([Scalar; 2], [Scalar; 2], Texture)>,
    facade: F,
}

impl<F> GlyphCache<F> where F: Facade {
     /// Constructor for a GlyphCache.
    pub fn new(font: &Path, facade: F) -> Result<Self, freetype::error::Error> {
        let freetype = try!(freetype::Library::init());
        let face = try!(freetype.new_face(font, 0));
        Ok(GlyphCache {
            face: face,
            data: HashMap::new(),
            facade: facade,
        })
    }

    /// Get a `Character` from cache, or load it if not there.
    fn get(&mut self, font_size: FontSize, character: char)
        -> &([Scalar; 2], [Scalar; 2], Texture)
    {
        // Create a `Character` from a given `FontSize` and `char`.
        fn create_character<F: Facade>(
            facade: &F,
            face: &freetype::Face,
            font_size: FontSize,
            character: char
        ) -> ([Scalar; 2], [Scalar; 2], Texture) {
            face.set_pixel_sizes(0, font_size).unwrap();
            face.load_char(character as usize, freetype::face::DEFAULT).unwrap();
            let glyph = face.glyph().get_glyph().unwrap();
            let bitmap_glyph = glyph.to_bitmap(freetype::render_mode::RenderMode::Normal, None).unwrap();
            let bitmap = bitmap_glyph.bitmap();
            let texture =
                if bitmap.width() != 0 {
                    let image = ImageBuffer::<Rgba<u8>, _>::from_raw(
                        bitmap.width() as u32, bitmap.rows() as u32,
                        bitmap.buffer().iter()
                            .flat_map(|&pix| vec![255, 255, 255, pix].into_iter())
                            .collect::<Vec<_>>()
                        ).expect("failed to create glyph texture");
                    let image_dimensions = image.dimensions();
                    SrgbTexture2d::new(
                        facade,
                        RawImage2d::from_raw_rgba_reversed(
                            image.into_raw(), image_dimensions
                        )
                    )
                } else { SrgbTexture2d::empty(facade, 1, 1) };
            let glyph_size_x = glyph.advance_x();
            let glyph_size_y = glyph.advance_y();
            (
                [bitmap_glyph.left() as f64, bitmap_glyph.top() as f64],
                [(glyph_size_x >> 16) as f64, (glyph_size_y >> 16) as f64],
                Texture::new(texture.unwrap())
            )
        }

        let face = &self.face; // necessary to borrow-check
        let facade = &self.facade;

        self.data.entry((font_size, character))
                 .or_insert_with(|| create_character(facade, face, font_size, character) )
    }
}

impl<F: Facade> CharacterCache for GlyphCache<F> {
    type Texture = Texture;

    fn character<'a>(&'a mut self, size: FontSize, ch: char) -> Character<'a, Texture> {
        let &(offset, size, ref texture) = self.get(size, ch);
        return Character {
            offset: offset,
            size: size,
            texture: texture
        }
    }
}
<commit_msg>Made `GlyphCache::new` take `P: AsRef<Path>`<commit_after>use std::path::Path;
use std::collections::HashMap;
use graphics::character::{ CharacterCache, Character };
use graphics::types::{ FontSize, Scalar };
use glium::texture::srgb_texture2d::SrgbTexture2d;
use glium::backend::Facade;
use glium::texture::RawImage2d;
use image::{ Rgba, ImageBuffer };
use freetype::{ self, Face };
use Texture;

/// Caches characters for a font.
pub struct GlyphCache<F> {
    face: Face<'static>,
    data: HashMap<(FontSize, char), ([Scalar; 2], [Scalar; 2], Texture)>,
    facade: F,
}

impl<F> GlyphCache<F> where F: Facade {
     /// Constructor for a GlyphCache.
    pub fn new<P>(font: P, facade: F) -> Result<Self, freetype::error::Error>
        where P: AsRef<Path>
    {
        let freetype = try!(freetype::Library::init());
        let face = try!(freetype.new_face(font.as_ref(), 0));
        Ok(GlyphCache {
            face: face,
            data: HashMap::new(),
            facade: facade,
        })
    }

    /// Get a `Character` from cache, or load it if not there.
    fn get(&mut self, font_size: FontSize, character: char)
        -> &([Scalar; 2], [Scalar; 2], Texture)
    {
        // Create a `Character` from a given `FontSize` and `char`.
        fn create_character<F: Facade>(
            facade: &F,
            face: &freetype::Face,
            font_size: FontSize,
            character: char
        ) -> ([Scalar; 2], [Scalar; 2], Texture) {
            face.set_pixel_sizes(0, font_size).unwrap();
            face.load_char(character as usize, freetype::face::DEFAULT).unwrap();
            let glyph = face.glyph().get_glyph().unwrap();
            let bitmap_glyph = glyph.to_bitmap(freetype::render_mode::RenderMode::Normal, None).unwrap();
            let bitmap = bitmap_glyph.bitmap();
            let texture =
                if bitmap.width() != 0 {
                    let image = ImageBuffer::<Rgba<u8>, _>::from_raw(
                        bitmap.width() as u32, bitmap.rows() as u32,
                        bitmap.buffer().iter()
                            .flat_map(|&pix| vec![255, 255, 255, pix].into_iter())
                            .collect::<Vec<_>>()
                        ).expect("failed to create glyph texture");
                    let image_dimensions = image.dimensions();
                    SrgbTexture2d::new(
                        facade,
                        RawImage2d::from_raw_rgba_reversed(
                            image.into_raw(), image_dimensions
                        )
                    )
                } else { SrgbTexture2d::empty(facade, 1, 1) };
            let glyph_size_x = glyph.advance_x();
            let glyph_size_y = glyph.advance_y();
            (
                [bitmap_glyph.left() as f64, bitmap_glyph.top() as f64],
                [(glyph_size_x >> 16) as f64, (glyph_size_y >> 16) as f64],
                Texture::new(texture.unwrap())
            )
        }

        let face = &self.face; // necessary to borrow-check
        let facade = &self.facade;

        self.data.entry((font_size, character))
                 .or_insert_with(|| create_character(facade, face, font_size, character) )
    }
}

impl<F: Facade> CharacterCache for GlyphCache<F> {
    type Texture = Texture;

    fn character<'a>(&'a mut self, size: FontSize, ch: char) -> Character<'a, Texture> {
        let &(offset, size, ref texture) = self.get(size, ch);
        return Character {
            offset: offset,
            size: size,
            texture: texture
        }
    }
}
<|endoftext|>


<commit_before>use std::io::{Result, Write};

use super::super::general::write_vec;

pub fn begin<W: Write>(w: &mut W) -> Result<()>{
    let v = vec![
"",
"#![allow(non_camel_case_types)]",
"",
"extern crate libc;",
"#[macro_use] extern crate bitflags;",
    ];

    write_vec(w, &v)
}

pub fn after_extern_crates<W: Write>(w: &mut W) -> Result<()>{
    let v = vec![
"",
"#[allow(unused_imports)]",
"use libc::{c_int, c_char, c_float, c_uint, c_double,",
"    c_short, c_ushort, c_long, c_ulong,",
"    c_void, size_t, ssize_t, time_t};",
    ];

    write_vec(w, &v)
}

pub fn use_glib_ffi<W: Write>(w: &mut W) -> Result<()>{
    let v = vec![
"",
"#[allow(unused_imports)]",
"use glib_ffi::{gboolean, gconstpointer, gpointer, GList, GSList};",
    ];

    write_vec(w, &v)
}

pub fn only_for_glib<W: Write>(w: &mut W) -> Result<()>{
    let v = vec![
"",
"pub type gboolean = c_int;",
"pub const GFALSE:  c_int = 0;",
"pub const GTRUE:   c_int = 1;",
"",
"pub type gconstpointer = *const c_void;",
"pub type gpointer = *mut c_void;",
    ];

    write_vec(w, &v)
}

pub fn only_for_gtk<W: Write>(w: &mut W) -> Result<()>{
    let v = vec![
"",
"pub const GTK_ENTRY_BUFFER_MAX_SIZE: u16 = ::std::u16::MAX;",
"",
"//pub type GtkTreeModelForeachFunc = fn(model: *mut GtkTreeModel, path: *mut GtkTreePath, iter: *mut GtkTreeIter, data: gpointer) -> gboolean;",
"",
"pub const GTK_STYLE_PROVIDER_PRIORITY_FALLBACK: u32 = 1;",
"pub const GTK_STYLE_PROVIDER_PRIORITY_THEME: u32 = 200;",
"pub const GTK_STYLE_PROVIDER_PRIORITY_SETTINGS: u32 = 400;",
"pub const GTK_STYLE_PROVIDER_PRIORITY_APPLICATION: u32 = 600;",
"pub const GTK_STYLE_PROVIDER_PRIORITY_USER: u32 = 800;",
    ];

    write_vec(w, &v)
}
<commit_msg>sys: import GHashTable and GType from glib<commit_after>use std::io::{Result, Write};

use super::super::general::write_vec;

pub fn begin<W: Write>(w: &mut W) -> Result<()>{
    let v = vec![
"",
"#![allow(non_camel_case_types)]",
"",
"extern crate libc;",
"#[macro_use] extern crate bitflags;",
    ];

    write_vec(w, &v)
}

pub fn after_extern_crates<W: Write>(w: &mut W) -> Result<()>{
    let v = vec![
"",
"#[allow(unused_imports)]",
"use libc::{c_int, c_char, c_float, c_uint, c_double,",
"    c_short, c_ushort, c_long, c_ulong,",
"    c_void, size_t, ssize_t, time_t};",
    ];

    write_vec(w, &v)
}

pub fn use_glib_ffi<W: Write>(w: &mut W) -> Result<()>{
    let v = vec![
"",
"#[allow(unused_imports)]",
"use glib_ffi::{gboolean, gconstpointer, gpointer, GHashTable, GList, GSList, GType};",
    ];

    write_vec(w, &v)
}

pub fn only_for_glib<W: Write>(w: &mut W) -> Result<()>{
    let v = vec![
"",
"pub type gboolean = c_int;",
"pub const GFALSE:  c_int = 0;",
"pub const GTRUE:   c_int = 1;",
"",
"pub type gconstpointer = *const c_void;",
"pub type gpointer = *mut c_void;",
    ];

    write_vec(w, &v)
}

pub fn only_for_gtk<W: Write>(w: &mut W) -> Result<()>{
    let v = vec![
"",
"pub const GTK_ENTRY_BUFFER_MAX_SIZE: u16 = ::std::u16::MAX;",
"",
"//pub type GtkTreeModelForeachFunc = fn(model: *mut GtkTreeModel, path: *mut GtkTreePath, iter: *mut GtkTreeIter, data: gpointer) -> gboolean;",
"",
"pub const GTK_STYLE_PROVIDER_PRIORITY_FALLBACK: u32 = 1;",
"pub const GTK_STYLE_PROVIDER_PRIORITY_THEME: u32 = 200;",
"pub const GTK_STYLE_PROVIDER_PRIORITY_SETTINGS: u32 = 400;",
"pub const GTK_STYLE_PROVIDER_PRIORITY_APPLICATION: u32 = 600;",
"pub const GTK_STYLE_PROVIDER_PRIORITY_USER: u32 = 800;",
    ];

    write_vec(w, &v)
}
<|endoftext|>


<commit_before>use grid::Grid;
use cell::Cell;

pub struct SquareGrid<C: Cell> {
	cells: Vec<C>
}

impl<C: Cell> Grid for SquareGrid<C> {

}<commit_msg>Neighbors are found.<commit_after>use std::rc::Rc;

use grid::Grid;
use cell::Cell;

const NEIGHBORS_COUNT: usize = 8;

type Neighbors<C> = [Option<Rc<C>>; NEIGHBORS_COUNT];

pub struct SquareGrid<C: Cell> {
    cells: Vec<Rc<C>>,
    neighbors: Vec<Neighbors<C>>,
    rows: usize,
    cols: usize
}

impl<C: Cell + Clone> SquareGrid<C> {

    pub fn new(rows: usize, cols: usize, initial: C) -> Self {

        let len = rows * cols;
        let cells = vec![Rc::new(initial); len];
        let neighbors = Vec::with_capacity(len);

        let mut grid = SquareGrid {
            cells: cells,
            neighbors: neighbors,
            rows: rows,
            cols: cols
        };
        grid.init_neighbors();

        grid
    }

    /// 0 | 1 | 2
    /// 3 | x | 4
    /// 5 | 6 | 7
    fn init_neighbors(&mut self) {

        let len = self.cells.len() as i32;
        let cols = self.cols as i32;

        for (offset, cell) in self.cells.iter().enumerate() {

            for serial in 0 .. NEIGHBORS_COUNT {

                let neighbor_index: i32;

                {
                    let offset = offset as i32;
                    let serial = serial as i32;

                    neighbor_index = match serial {
                        i @ 0 ... 2 => offset - cols - (i - 1),
                        3 => offset - 1,
                        4 => offset + 1,
                        i @ 5 ... 7 => offset + cols - (i - 1),
                        // such values will be ignored later
                        _ => len
                    };
                }

                if neighbor_index >= 0 && neighbor_index < len {
                    self.neighbors[offset][serial] = Some(cell.clone());
                }
                else {
                    self.neighbors[offset][serial] = None;
                }
            }
        }
    }
}

impl<C: Cell> Grid for SquareGrid<C> {
    fn step(&self) {}
}
<|endoftext|>


<commit_before>/*!
helper functions used by this crate
whose utility surpasses the confines of this crate.

generic things that are also useful in other crates.
*/

mod repeatedly;
pub use self::repeatedly::{Repeatedly, repeatedly};

mod normalize;
pub use self::normalize::Normalize;

mod partial_max;
pub use self::partial_max::PartialMaxIteratorExt;

mod random;
pub use self::random::random01;
<commit_msg>make normalize module public so impls are visible<commit_after>/*!
helper functions used by this crate
whose utility surpasses the confines of this crate.

generic things that are also useful in other crates.
*/

mod repeatedly;
pub use self::repeatedly::{Repeatedly, repeatedly};

// this needs to be public otherwise the impl is not exported
pub mod normalize;
pub use self::normalize::Normalize;

mod partial_max;
pub use self::partial_max::PartialMaxIteratorExt;

mod random;
pub use self::random::random01;
<|endoftext|>