<commit_before>use crate::core::{InternedString, PackageId, SourceId};
use crate::sources::git;
use crate::sources::registry::MaybeLock;
use crate::sources::registry::{RegistryConfig, RegistryData, CRATE_TEMPLATE, VERSION_TEMPLATE};
use crate::util::errors::{CargoResult, CargoResultExt};
use crate::util::paths;
use crate::util::{Config, Filesystem, Sha256};
use lazycell::LazyCell;
use log::{debug, trace};
use std::cell::{Cell, Ref, RefCell};
use std::fmt::Write as FmtWrite;
use std::fs::{File, OpenOptions};
use std::io::prelude::*;
use std::io::SeekFrom;
use std::mem;
use std::path::Path;
use std::str;

pub struct RemoteRegistry<'cfg> {
    index_path: Filesystem,
    cache_path: Filesystem,
    source_id: SourceId,
    config: &'cfg Config,
    tree: RefCell<Option<git2::Tree<'static>>>,
    repo: LazyCell<git2::Repository>,
    head: Cell<Option<git2::Oid>>,
    current_sha: Cell<Option<InternedString>>,
}

impl<'cfg> RemoteRegistry<'cfg> {
    pub fn new(source_id: SourceId, config: &'cfg Config, name: &str) -> RemoteRegistry<'cfg> {
        RemoteRegistry {
            index_path: config.registry_index_path().join(name),
            cache_path: config.registry_cache_path().join(name),
            source_id,
            config,
            tree: RefCell::new(None),
            repo: LazyCell::new(),
            head: Cell::new(None),
            current_sha: Cell::new(None),
        }
    }

    fn repo(&self) -> CargoResult<&git2::Repository> {
        self.repo.try_borrow_with(|| {
            let path = self.config.assert_package_cache_locked(&self.index_path);

            // Fast path without a lock
            if let Ok(repo) = git2::Repository::open(&path) {
                trace!("opened a repo without a lock");
                return Ok(repo);
            }

            // Ok, now we need to lock and try the whole thing over again.
            trace!("acquiring registry index lock");
            match git2::Repository::open(&path) {
                Ok(repo) => Ok(repo),
                Err(_) => {
                    drop(paths::remove_dir_all(&path));
                    paths::create_dir_all(&path)?;

                    // Note that we'd actually prefer to use a bare repository
                    // here as we're not actually going to check anything out.
                    // All versions of Cargo, though, share the same CARGO_HOME,
                    // so for compatibility with older Cargo which *does* do
                    // checkouts we make sure to initialize a new full
                    // repository (not a bare one).
                    //
                    // We should change this to `init_bare` whenever we feel
                    // like enough time has passed or if we change the directory
                    // that the folder is located in, such as by changing the
                    // hash at the end of the directory.
                    //
                    // Note that in the meantime we also skip `init.templatedir`
                    // as it can be misconfigured sometimes or otherwise add
                    // things that we don't want.
                    let mut opts = git2::RepositoryInitOptions::new();
                    opts.external_template(false);
                    Ok(git2::Repository::init_opts(&path, &opts)
                        .chain_err(|| "failed to initialized index git repository")?)
                }
            }
        })
    }

    fn head(&self) -> CargoResult<git2::Oid> {
        if self.head.get().is_none() {
            let oid = self.repo()?.refname_to_id("refs/remotes/origin/master")?;
            self.head.set(Some(oid));
        }
        Ok(self.head.get().unwrap())
    }

    fn tree(&self) -> CargoResult<Ref<'_, git2::Tree<'_>>> {
        {
            let tree = self.tree.borrow();
            if tree.is_some() {
                return Ok(Ref::map(tree, |s| s.as_ref().unwrap()));
            }
        }
        let repo = self.repo()?;
        let commit = repo.find_commit(self.head()?)?;
        let tree = commit.tree()?;

        // Unfortunately in libgit2 the tree objects look like they've got a
        // reference to the repository object which means that a tree cannot
        // outlive the repository that it came from. Here we want to cache this
        // tree, though, so to accomplish this we transmute it to a static
        // lifetime.
        //
        // Note that we don't actually hand out the static lifetime, instead we
        // only return a scoped one from this function. Additionally the repo
        // we loaded from (above) lives as long as this object
        // (`RemoteRegistry`) so we then just need to ensure that the tree is
        // destroyed first in the destructor, hence the destructor on
        // `RemoteRegistry` below.
        let tree = unsafe { mem::transmute::<git2::Tree<'_>, git2::Tree<'static>>(tree) };
        *self.tree.borrow_mut() = Some(tree);
        Ok(Ref::map(self.tree.borrow(), |s| s.as_ref().unwrap()))
    }

    fn filename(&self, pkg: PackageId) -> String {
        format!("{}-{}.crate", pkg.name(), pkg.version())
    }
}

const LAST_UPDATED_FILE: &str = ".last-updated";

impl<'cfg> RegistryData for RemoteRegistry<'cfg> {
    fn prepare(&self) -> CargoResult<()> {
        self.repo()?; // create intermediate dirs and initialize the repo
        Ok(())
    }

    fn index_path(&self) -> &Filesystem {
        &self.index_path
    }

    fn assert_index_locked<'a>(&self, path: &'a Filesystem) -> &'a Path {
        self.config.assert_package_cache_locked(path)
    }

    fn current_version(&self) -> Option<InternedString> {
        if let Some(sha) = self.current_sha.get() {
            return Some(sha);
        }
        let sha = InternedString::new(&self.head().ok()?.to_string());
        self.current_sha.set(Some(sha));
        Some(sha)
    }

    fn load(
        &self,
        _root: &Path,
        path: &Path,
        data: &mut dyn FnMut(&[u8]) -> CargoResult<()>,
    ) -> CargoResult<()> {
        // Note that the index calls this method and the filesystem is locked
        // in the index, so we don't need to worry about an `update_index`
        // happening in a different process.
        let repo = self.repo()?;
        let tree = self.tree()?;
        let entry = tree.get_path(path)?;
        let object = entry.to_object(repo)?;
        let blob = match object.as_blob() {
            Some(blob) => blob,
            None => failure::bail!("path `{}` is not a blob in the git repo", path.display()),
        };
        data(blob.content())
    }

    fn config(&mut self) -> CargoResult<Option<RegistryConfig>> {
        debug!("loading config");
        self.prepare()?;
        self.config.assert_package_cache_locked(&self.index_path);
        let mut config = None;
        self.load(Path::new(""), Path::new("config.json"), &mut |json| {
            config = Some(serde_json::from_slice(json)?);
            Ok(())
        })?;
        trace!("config loaded");
        Ok(config)
    }

    fn update_index(&mut self) -> CargoResult<()> {
        if self.config.offline() {
            if self.repo()?.is_empty()? {
                // An empty repository is guaranteed to fail, since hitting
                // this path means we need at least one crate. This is an
                // attempt to provide a better error message other than "no
                // matching package named …".
                failure::bail!(
                    "unable to fetch {} in offline mode\n\
                     Try running without the offline flag, or try running \
                     `cargo fetch` within your project directory before going offline.",
                    self.source_id
                );
            }
            return Ok(());
        }
        if self.config.cli_unstable().no_index_update {
            return Ok(());
        }
        // Make sure the index is only updated once per session since it is an
        // expensive operation. This generally only happens when the resolver
        // is run multiple times, such as during `cargo publish`.
        if self.config.updated_sources().contains(&self.source_id) {
            return Ok(());
        }

        debug!("updating the index");

        // Ensure that we'll actually be able to acquire an HTTP handle later on
        // once we start trying to download crates. This will weed out any
        // problems with `.cargo/config` configuration related to HTTP.
        //
        // This way if there's a problem the error gets printed before we even
        // hit the index, which may not actually read this configuration.
        self.config.http()?;

        self.prepare()?;
        self.head.set(None);
        *self.tree.borrow_mut() = None;
        self.current_sha.set(None);
        let path = self.config.assert_package_cache_locked(&self.index_path);
        self.config
            .shell()
            .status("Updating", self.source_id.display_index())?;

        // git fetch origin master
        let url = self.source_id.url();
        let refspec = "refs/heads/master:refs/remotes/origin/master";
        let repo = self.repo.borrow_mut().unwrap();
        git::fetch(repo, url.as_str(), refspec, self.config)
            .chain_err(|| format!("failed to fetch `{}`", url))?;
        self.config.updated_sources().insert(self.source_id);

        // Create a dummy file to record the mtime for when we updated the
        // index.
        File::create(&path.join(LAST_UPDATED_FILE))?;

        Ok(())
    }

    fn download(&mut self, pkg: PackageId, _checksum: &str) -> CargoResult<MaybeLock> {
        let filename = self.filename(pkg);

        // Attempt to open an read-only copy first to avoid an exclusive write
        // lock and also work with read-only filesystems. Note that we check the
        // length of the file like below to handle interrupted downloads.
        //
        // If this fails then we fall through to the exclusive path where we may
        // have to redownload the file.
        let path = self.cache_path.join(&filename);
        let path = self.config.assert_package_cache_locked(&path);
        if let Ok(dst) = File::open(&path) {
            let meta = dst.metadata()?;
            if meta.len() > 0 {
                return Ok(MaybeLock::Ready(dst));
            }
        }

        let config = self.config()?.unwrap();
        let mut url = config.dl;
        if !url.contains(CRATE_TEMPLATE) && !url.contains(VERSION_TEMPLATE) {
            write!(url, "/{}/{}/download", CRATE_TEMPLATE, VERSION_TEMPLATE).unwrap();
        }
        let url = url
            .replace(CRATE_TEMPLATE, &*pkg.name())
            .replace(VERSION_TEMPLATE, &pkg.version().to_string());

        Ok(MaybeLock::Download {
            url,
            descriptor: pkg.to_string(),
        })
    }

    fn finish_download(
        &mut self,
        pkg: PackageId,
        checksum: &str,
        data: &[u8],
    ) -> CargoResult<File> {
        // Verify what we just downloaded
        let actual = Sha256::new().update(data).finish_hex();
        if actual != checksum {
            failure::bail!("failed to verify the checksum of `{}`", pkg)
        }

        let filename = self.filename(pkg);
        self.cache_path.create_dir()?;
        let path = self.cache_path.join(&filename);
        let path = self.config.assert_package_cache_locked(&path);
        let mut dst = OpenOptions::new()
            .create(true)
            .read(true)
            .write(true)
            .open(&path)?;
        let meta = dst.metadata()?;
        if meta.len() > 0 {
            return Ok(dst);
        }

        dst.write_all(data)?;
        dst.seek(SeekFrom::Start(0))?;
        Ok(dst)
    }

    fn is_crate_downloaded(&self, pkg: PackageId) -> bool {
        let filename = format!("{}-{}.crate", pkg.name(), pkg.version());
        let path = Path::new(&filename);

        let path = self.cache_path.join(path);
        let path = self.config.assert_package_cache_locked(&path);
        if let Ok(dst) = File::open(path) {
            if let Ok(meta) = dst.metadata() {
                return meta.len() > 0;
            }
        }
        false
    }
}

impl<'cfg> Drop for RemoteRegistry<'cfg> {
    fn drop(&mut self) {
        // Just be sure to drop this before our other fields
        self.tree.borrow_mut().take();
    }
}
<commit_msg>Auto merge of #7512 - Xyene:patch-1, r=alexcrichton<commit_after>use crate::core::{InternedString, PackageId, SourceId};
use crate::sources::git;
use crate::sources::registry::MaybeLock;
use crate::sources::registry::{RegistryConfig, RegistryData, CRATE_TEMPLATE, VERSION_TEMPLATE};
use crate::util::errors::{CargoResult, CargoResultExt};
use crate::util::paths;
use crate::util::{Config, Filesystem, Sha256};
use lazycell::LazyCell;
use log::{debug, trace};
use std::cell::{Cell, Ref, RefCell};
use std::fmt::Write as FmtWrite;
use std::fs::{File, OpenOptions};
use std::io::prelude::*;
use std::io::SeekFrom;
use std::mem;
use std::path::Path;
use std::str;

pub struct RemoteRegistry<'cfg> {
    index_path: Filesystem,
    cache_path: Filesystem,
    source_id: SourceId,
    config: &'cfg Config,
    tree: RefCell<Option<git2::Tree<'static>>>,
    repo: LazyCell<git2::Repository>,
    head: Cell<Option<git2::Oid>>,
    current_sha: Cell<Option<InternedString>>,
}

impl<'cfg> RemoteRegistry<'cfg> {
    pub fn new(source_id: SourceId, config: &'cfg Config, name: &str) -> RemoteRegistry<'cfg> {
        RemoteRegistry {
            index_path: config.registry_index_path().join(name),
            cache_path: config.registry_cache_path().join(name),
            source_id,
            config,
            tree: RefCell::new(None),
            repo: LazyCell::new(),
            head: Cell::new(None),
            current_sha: Cell::new(None),
        }
    }

    fn repo(&self) -> CargoResult<&git2::Repository> {
        self.repo.try_borrow_with(|| {
            let path = self.config.assert_package_cache_locked(&self.index_path);

            // Fast path without a lock
            if let Ok(repo) = git2::Repository::open(&path) {
                trace!("opened a repo without a lock");
                return Ok(repo);
            }

            // Ok, now we need to lock and try the whole thing over again.
            trace!("acquiring registry index lock");
            match git2::Repository::open(&path) {
                Ok(repo) => Ok(repo),
                Err(_) => {
                    drop(paths::remove_dir_all(&path));
                    paths::create_dir_all(&path)?;

                    // Note that we'd actually prefer to use a bare repository
                    // here as we're not actually going to check anything out.
                    // All versions of Cargo, though, share the same CARGO_HOME,
                    // so for compatibility with older Cargo which *does* do
                    // checkouts we make sure to initialize a new full
                    // repository (not a bare one).
                    //
                    // We should change this to `init_bare` whenever we feel
                    // like enough time has passed or if we change the directory
                    // that the folder is located in, such as by changing the
                    // hash at the end of the directory.
                    //
                    // Note that in the meantime we also skip `init.templatedir`
                    // as it can be misconfigured sometimes or otherwise add
                    // things that we don't want.
                    let mut opts = git2::RepositoryInitOptions::new();
                    opts.external_template(false);
                    Ok(git2::Repository::init_opts(&path, &opts)
                        .chain_err(|| "failed to initialize index git repository")?)
                }
            }
        })
    }

    fn head(&self) -> CargoResult<git2::Oid> {
        if self.head.get().is_none() {
            let oid = self.repo()?.refname_to_id("refs/remotes/origin/master")?;
            self.head.set(Some(oid));
        }
        Ok(self.head.get().unwrap())
    }

    fn tree(&self) -> CargoResult<Ref<'_, git2::Tree<'_>>> {
        {
            let tree = self.tree.borrow();
            if tree.is_some() {
                return Ok(Ref::map(tree, |s| s.as_ref().unwrap()));
            }
        }
        let repo = self.repo()?;
        let commit = repo.find_commit(self.head()?)?;
        let tree = commit.tree()?;

        // Unfortunately in libgit2 the tree objects look like they've got a
        // reference to the repository object which means that a tree cannot
        // outlive the repository that it came from. Here we want to cache this
        // tree, though, so to accomplish this we transmute it to a static
        // lifetime.
        //
        // Note that we don't actually hand out the static lifetime, instead we
        // only return a scoped one from this function. Additionally the repo
        // we loaded from (above) lives as long as this object
        // (`RemoteRegistry`) so we then just need to ensure that the tree is
        // destroyed first in the destructor, hence the destructor on
        // `RemoteRegistry` below.
        let tree = unsafe { mem::transmute::<git2::Tree<'_>, git2::Tree<'static>>(tree) };
        *self.tree.borrow_mut() = Some(tree);
        Ok(Ref::map(self.tree.borrow(), |s| s.as_ref().unwrap()))
    }

    fn filename(&self, pkg: PackageId) -> String {
        format!("{}-{}.crate", pkg.name(), pkg.version())
    }
}

const LAST_UPDATED_FILE: &str = ".last-updated";

impl<'cfg> RegistryData for RemoteRegistry<'cfg> {
    fn prepare(&self) -> CargoResult<()> {
        self.repo()?; // create intermediate dirs and initialize the repo
        Ok(())
    }

    fn index_path(&self) -> &Filesystem {
        &self.index_path
    }

    fn assert_index_locked<'a>(&self, path: &'a Filesystem) -> &'a Path {
        self.config.assert_package_cache_locked(path)
    }

    fn current_version(&self) -> Option<InternedString> {
        if let Some(sha) = self.current_sha.get() {
            return Some(sha);
        }
        let sha = InternedString::new(&self.head().ok()?.to_string());
        self.current_sha.set(Some(sha));
        Some(sha)
    }

    fn load(
        &self,
        _root: &Path,
        path: &Path,
        data: &mut dyn FnMut(&[u8]) -> CargoResult<()>,
    ) -> CargoResult<()> {
        // Note that the index calls this method and the filesystem is locked
        // in the index, so we don't need to worry about an `update_index`
        // happening in a different process.
        let repo = self.repo()?;
        let tree = self.tree()?;
        let entry = tree.get_path(path)?;
        let object = entry.to_object(repo)?;
        let blob = match object.as_blob() {
            Some(blob) => blob,
            None => failure::bail!("path `{}` is not a blob in the git repo", path.display()),
        };
        data(blob.content())
    }

    fn config(&mut self) -> CargoResult<Option<RegistryConfig>> {
        debug!("loading config");
        self.prepare()?;
        self.config.assert_package_cache_locked(&self.index_path);
        let mut config = None;
        self.load(Path::new(""), Path::new("config.json"), &mut |json| {
            config = Some(serde_json::from_slice(json)?);
            Ok(())
        })?;
        trace!("config loaded");
        Ok(config)
    }

    fn update_index(&mut self) -> CargoResult<()> {
        if self.config.offline() {
            if self.repo()?.is_empty()? {
                // An empty repository is guaranteed to fail, since hitting
                // this path means we need at least one crate. This is an
                // attempt to provide a better error message other than "no
                // matching package named …".
                failure::bail!(
                    "unable to fetch {} in offline mode\n\
                     Try running without the offline flag, or try running \
                     `cargo fetch` within your project directory before going offline.",
                    self.source_id
                );
            }
            return Ok(());
        }
        if self.config.cli_unstable().no_index_update {
            return Ok(());
        }
        // Make sure the index is only updated once per session since it is an
        // expensive operation. This generally only happens when the resolver
        // is run multiple times, such as during `cargo publish`.
        if self.config.updated_sources().contains(&self.source_id) {
            return Ok(());
        }

        debug!("updating the index");

        // Ensure that we'll actually be able to acquire an HTTP handle later on
        // once we start trying to download crates. This will weed out any
        // problems with `.cargo/config` configuration related to HTTP.
        //
        // This way if there's a problem the error gets printed before we even
        // hit the index, which may not actually read this configuration.
        self.config.http()?;

        self.prepare()?;
        self.head.set(None);
        *self.tree.borrow_mut() = None;
        self.current_sha.set(None);
        let path = self.config.assert_package_cache_locked(&self.index_path);
        self.config
            .shell()
            .status("Updating", self.source_id.display_index())?;

        // git fetch origin master
        let url = self.source_id.url();
        let refspec = "refs/heads/master:refs/remotes/origin/master";
        let repo = self.repo.borrow_mut().unwrap();
        git::fetch(repo, url.as_str(), refspec, self.config)
            .chain_err(|| format!("failed to fetch `{}`", url))?;
        self.config.updated_sources().insert(self.source_id);

        // Create a dummy file to record the mtime for when we updated the
        // index.
        File::create(&path.join(LAST_UPDATED_FILE))?;

        Ok(())
    }

    fn download(&mut self, pkg: PackageId, _checksum: &str) -> CargoResult<MaybeLock> {
        let filename = self.filename(pkg);

        // Attempt to open an read-only copy first to avoid an exclusive write
        // lock and also work with read-only filesystems. Note that we check the
        // length of the file like below to handle interrupted downloads.
        //
        // If this fails then we fall through to the exclusive path where we may
        // have to redownload the file.
        let path = self.cache_path.join(&filename);
        let path = self.config.assert_package_cache_locked(&path);
        if let Ok(dst) = File::open(&path) {
            let meta = dst.metadata()?;
            if meta.len() > 0 {
                return Ok(MaybeLock::Ready(dst));
            }
        }

        let config = self.config()?.unwrap();
        let mut url = config.dl;
        if !url.contains(CRATE_TEMPLATE) && !url.contains(VERSION_TEMPLATE) {
            write!(url, "/{}/{}/download", CRATE_TEMPLATE, VERSION_TEMPLATE).unwrap();
        }
        let url = url
            .replace(CRATE_TEMPLATE, &*pkg.name())
            .replace(VERSION_TEMPLATE, &pkg.version().to_string());

        Ok(MaybeLock::Download {
            url,
            descriptor: pkg.to_string(),
        })
    }

    fn finish_download(
        &mut self,
        pkg: PackageId,
        checksum: &str,
        data: &[u8],
    ) -> CargoResult<File> {
        // Verify what we just downloaded
        let actual = Sha256::new().update(data).finish_hex();
        if actual != checksum {
            failure::bail!("failed to verify the checksum of `{}`", pkg)
        }

        let filename = self.filename(pkg);
        self.cache_path.create_dir()?;
        let path = self.cache_path.join(&filename);
        let path = self.config.assert_package_cache_locked(&path);
        let mut dst = OpenOptions::new()
            .create(true)
            .read(true)
            .write(true)
            .open(&path)?;
        let meta = dst.metadata()?;
        if meta.len() > 0 {
            return Ok(dst);
        }

        dst.write_all(data)?;
        dst.seek(SeekFrom::Start(0))?;
        Ok(dst)
    }

    fn is_crate_downloaded(&self, pkg: PackageId) -> bool {
        let filename = format!("{}-{}.crate", pkg.name(), pkg.version());
        let path = Path::new(&filename);

        let path = self.cache_path.join(path);
        let path = self.config.assert_package_cache_locked(&path);
        if let Ok(dst) = File::open(path) {
            if let Ok(meta) = dst.metadata() {
                return meta.len() > 0;
            }
        }
        false
    }
}

impl<'cfg> Drop for RemoteRegistry<'cfg> {
    fn drop(&mut self) {
        // Just be sure to drop this before our other fields
        self.tree.borrow_mut().take();
    }
}
<|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 dom::bindings::codegen::BindingDeclarations::UIEventBinding;
use dom::bindings::codegen::InheritTypes::{EventCast, UIEventDerived};
use dom::bindings::js::{JS, JSRef, RootedReference, Temporary, OptionalSettable};
use dom::bindings::error::Fallible;
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
use dom::event::{Event, EventMethods, EventTypeId, UIEventTypeId};
use dom::node::Node;
use dom::window::Window;
use servo_util::str::DOMString;

use serialize::{Encoder, Encodable};

#[deriving(Encodable)]
pub struct UIEvent {
    pub event: Event,
    pub view: Option<JS<Window>>,
    pub detail: i32
}

impl UIEventDerived for Event {
    fn is_uievent(&self) -> bool {
        self.type_id == UIEventTypeId
    }
}

impl UIEvent {
    pub fn new_inherited(type_id: EventTypeId) -> UIEvent {
        UIEvent {
            event: Event::new_inherited(type_id),
            view: None,
            detail: 0
        }
    }

    pub fn new_uninitialized(window: &JSRef<Window>) -> Temporary<UIEvent> {
        reflect_dom_object(box UIEvent::new_inherited(UIEventTypeId),
                           window,
                           UIEventBinding::Wrap)
    }

    pub fn new(window: &JSRef<Window>,
               type_: DOMString,
               can_bubble: bool,
               cancelable: bool,
               view: Option<JSRef<Window>>,
               detail: i32) -> Temporary<UIEvent> {
        let mut ev = UIEvent::new_uninitialized(window).root();
        ev.InitUIEvent(type_, can_bubble, cancelable, view, detail);
        Temporary::from_rooted(&*ev)
    }

    pub fn Constructor(owner: &JSRef<Window>,
                       type_: DOMString,
                       init: &UIEventBinding::UIEventInit) -> Fallible<Temporary<UIEvent>> {
        let event = UIEvent::new(owner, type_,
                                 init.parent.bubbles, init.parent.cancelable,
                                 init.view.root_ref(), init.detail);
        Ok(event)
    }
}

pub trait UIEventMethods {
    fn GetView(&self) -> Option<Temporary<Window>>;
    fn Detail(&self) -> i32;
    fn LayerX(&self) -> i32;
    fn LayerY(&self) -> i32;
    fn PageX(&self) -> i32;
    fn PageY(&self) -> i32;
    fn Which(&self) -> u32;
    fn GetRangeParent(&self) -> Option<Temporary<Node>>;
    fn RangeOffset(&self) -> i32;
    fn CancelBubble(&self) -> bool;
    fn SetCancelBubble(&mut self, _val: bool);
    fn IsChar(&self) -> bool;
    fn InitUIEvent(&mut self,
                   type_: DOMString,
                   can_bubble: bool,
                   cancelable: bool,
                   view: Option<JSRef<Window>>,
                   detail: i32);
}

impl<'a> UIEventMethods for JSRef<'a, UIEvent> {
    fn GetView(&self) -> Option<Temporary<Window>> {
        self.view.clone().map(|view| Temporary::new(view))
    }

    fn Detail(&self) -> i32 {
        self.detail
    }

    fn InitUIEvent(&mut self,
                   type_: DOMString,
                   can_bubble: bool,
                   cancelable: bool,
                   view: Option<JSRef<Window>>,
                   detail: i32) {
        {
            let event: &mut JSRef<Event> = EventCast::from_mut_ref(self);
            event.InitEvent(type_, can_bubble, cancelable);
        }
        self.view.assign(view);
        self.detail = detail;
    }

    fn LayerX(&self) -> i32 {
        //TODO
        0
    }

    fn LayerY(&self) -> i32 {
        //TODO
        0
    }

    fn PageX(&self) -> i32 {
        //TODO
        0
    }

    fn PageY(&self) -> i32 {
        //TODO
        0
    }

    fn Which(&self) -> u32 {
        //TODO
        0
    }

    fn GetRangeParent(&self) -> Option<Temporary<Node>> {
        //TODO
        None
    }

    fn RangeOffset(&self) -> i32 {
        //TODO
        0
    }

    fn CancelBubble(&self) -> bool {
        //TODO
        false
    }

    fn SetCancelBubble(&mut self, _val: bool) {
        //TODO
    }

    fn IsChar(&self) -> bool {
        //TODO
        false
    }
}

impl Reflectable for UIEvent {
    fn reflector<'a>(&'a self) -> &'a Reflector {
        self.event.reflector()
    }

    fn mut_reflector<'a>(&'a mut self) -> &'a mut Reflector {
        self.event.mut_reflector()
    }
}
<commit_msg>Use Cell/RefCell for interior mutability of UIEvent.<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 dom::bindings::codegen::BindingDeclarations::UIEventBinding;
use dom::bindings::codegen::InheritTypes::{EventCast, UIEventDerived};
use dom::bindings::js::{JS, JSRef, RootedReference, Temporary, OptionalSettable};
use dom::bindings::error::Fallible;
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
use dom::event::{Event, EventMethods, EventTypeId, UIEventTypeId};
use dom::node::Node;
use dom::window::Window;
use servo_util::str::DOMString;

use serialize::{Encoder, Encodable};

#[deriving(Encodable)]
pub struct UIEvent {
    pub event: Event,
    pub view: Option<JS<Window>>,
    pub detail: i32
}

impl UIEventDerived for Event {
    fn is_uievent(&self) -> bool {
        self.type_id == UIEventTypeId
    }
}

impl UIEvent {
    pub fn new_inherited(type_id: EventTypeId) -> UIEvent {
        UIEvent {
            event: Event::new_inherited(type_id),
            view: None,
            detail: 0
        }
    }

    pub fn new_uninitialized(window: &JSRef<Window>) -> Temporary<UIEvent> {
        reflect_dom_object(box UIEvent::new_inherited(UIEventTypeId),
                           window,
                           UIEventBinding::Wrap)
    }

    pub fn new(window: &JSRef<Window>,
               type_: DOMString,
               can_bubble: bool,
               cancelable: bool,
               view: Option<JSRef<Window>>,
               detail: i32) -> Temporary<UIEvent> {
        let mut ev = UIEvent::new_uninitialized(window).root();
        ev.InitUIEvent(type_, can_bubble, cancelable, view, detail);
        Temporary::from_rooted(&*ev)
    }

    pub fn Constructor(owner: &JSRef<Window>,
                       type_: DOMString,
                       init: &UIEventBinding::UIEventInit) -> Fallible<Temporary<UIEvent>> {
        let event = UIEvent::new(owner, type_,
                                 init.parent.bubbles, init.parent.cancelable,
                                 init.view.root_ref(), init.detail);
        Ok(event)
    }
}

pub trait UIEventMethods {
    fn GetView(&self) -> Option<Temporary<Window>>;
    fn Detail(&self) -> i32;
    fn LayerX(&self) -> i32;
    fn LayerY(&self) -> i32;
    fn PageX(&self) -> i32;
    fn PageY(&self) -> i32;
    fn Which(&self) -> u32;
    fn GetRangeParent(&self) -> Option<Temporary<Node>>;
    fn RangeOffset(&self) -> i32;
    fn CancelBubble(&self) -> bool;
    fn SetCancelBubble(&mut self, _val: bool);
    fn IsChar(&self) -> bool;
    fn InitUIEvent(&mut self,
                   type_: DOMString,
                   can_bubble: bool,
                   cancelable: bool,
                   view: Option<JSRef<Window>>,
                   detail: i32);
}

impl<'a> UIEventMethods for JSRef<'a, UIEvent> {
    fn GetView(&self) -> Option<Temporary<Window>> {
        self.view.map(|view| Temporary::new(view))
    }

    fn Detail(&self) -> i32 {
        self.detail
    }

    fn InitUIEvent(&mut self,
                   type_: DOMString,
                   can_bubble: bool,
                   cancelable: bool,
                   view: Option<JSRef<Window>>,
                   detail: i32) {
        {
            let event: &mut JSRef<Event> = EventCast::from_mut_ref(self);
            event.InitEvent(type_, can_bubble, cancelable);
        }
        self.view.assign(view);
        self.detail = detail;
    }

    fn LayerX(&self) -> i32 {
        //TODO
        0
    }

    fn LayerY(&self) -> i32 {
        //TODO
        0
    }

    fn PageX(&self) -> i32 {
        //TODO
        0
    }

    fn PageY(&self) -> i32 {
        //TODO
        0
    }

    fn Which(&self) -> u32 {
        //TODO
        0
    }

    fn GetRangeParent(&self) -> Option<Temporary<Node>> {
        //TODO
        None
    }

    fn RangeOffset(&self) -> i32 {
        //TODO
        0
    }

    fn CancelBubble(&self) -> bool {
        //TODO
        false
    }

    fn SetCancelBubble(&mut self, _val: bool) {
        //TODO
    }

    fn IsChar(&self) -> bool {
        //TODO
        false
    }
}

impl Reflectable for UIEvent {
    fn reflector<'a>(&'a self) -> &'a Reflector {
        self.event.reflector()
    }

    fn mut_reflector<'a>(&'a mut self) -> &'a mut Reflector {
        self.event.mut_reflector()
    }
}
<|endoftext|>


<commit_before>// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use base::{error, RawDescriptor};
use std::convert::TryFrom;

use libvda::decode::Event as LibvdaEvent;

use crate::virtio::video::{
    decoder::backend::*,
    error::{VideoError, VideoResult},
    format::{Format, Rect},
};

impl TryFrom<Format> for libvda::Profile {
    type Error = VideoError;

    fn try_from(format: Format) -> Result<Self, Self::Error> {
        Ok(match format {
            Format::VP8 => libvda::Profile::VP8,
            Format::VP9 => libvda::Profile::VP9Profile0,
            Format::H264 => libvda::Profile::H264ProfileBaseline,
            _ => {
                error!("specified format {} is not supported by VDA", format);
                return Err(VideoError::InvalidParameter);
            }
        })
    }
}

impl TryFrom<Format> for libvda::PixelFormat {
    type Error = VideoError;

    fn try_from(format: Format) -> Result<Self, Self::Error> {
        Ok(match format {
            Format::NV12 => libvda::PixelFormat::NV12,
            _ => {
                error!("specified format {} is not supported by VDA", format);
                return Err(VideoError::InvalidParameter);
            }
        })
    }
}

impl From<&FramePlane> for libvda::FramePlane {
    fn from(plane: &FramePlane) -> Self {
        libvda::FramePlane {
            offset: plane.offset,
            stride: plane.stride,
        }
    }
}

impl From<libvda::decode::Event> for DecoderEvent {
    fn from(event: libvda::decode::Event) -> Self {
        // We cannot use the From trait here since neither libvda::decode::Response
        // no std::result::Result are defined in the current crate.
        fn vda_response_to_result(resp: libvda::decode::Response) -> VideoResult<()> {
            match resp {
                libvda::decode::Response::Success => Ok(()),
                resp => Err(VideoError::VdaFailure(resp)),
            }
        }

        match event {
            LibvdaEvent::ProvidePictureBuffers {
                min_num_buffers,
                width,
                height,
                visible_rect_left,
                visible_rect_top,
                visible_rect_right,
                visible_rect_bottom,
            } => DecoderEvent::ProvidePictureBuffers {
                min_num_buffers,
                width,
                height,
                visible_rect: Rect {
                    left: visible_rect_left,
                    top: visible_rect_top,
                    right: visible_rect_right,
                    bottom: visible_rect_bottom,
                },
            },
            LibvdaEvent::PictureReady {
                buffer_id,
                bitstream_id,
                left,
                top,
                right,
                bottom,
            } => DecoderEvent::PictureReady {
                picture_buffer_id: buffer_id,
                bitstream_id,
                visible_rect: Rect {
                    left,
                    top,
                    right,
                    bottom,
                },
            },
            LibvdaEvent::NotifyEndOfBitstreamBuffer { bitstream_id } => {
                DecoderEvent::NotifyEndOfBitstreamBuffer(bitstream_id)
            }
            LibvdaEvent::NotifyError(resp) => {
                DecoderEvent::NotifyError(VideoError::VdaFailure(resp))
            }
            LibvdaEvent::ResetResponse(resp) => {
                DecoderEvent::ResetCompleted(vda_response_to_result(resp))
            }
            LibvdaEvent::FlushResponse(resp) => {
                DecoderEvent::FlushCompleted(vda_response_to_result(resp))
            }
        }
    }
}

pub struct LibvdaSession<'a> {
    session: libvda::decode::Session<'a>,
}

impl<'a> DecoderSession for LibvdaSession<'a> {
    fn set_output_buffer_count(&self, count: usize) -> VideoResult<()> {
        Ok(self.session.set_output_buffer_count(count)?)
    }

    fn decode(
        &self,
        bitstream_id: i32,
        descriptor: RawDescriptor,
        offset: u32,
        bytes_used: u32,
    ) -> VideoResult<()> {
        Ok(self
            .session
            .decode(bitstream_id, descriptor, offset, bytes_used)?)
    }

    fn flush(&self) -> VideoResult<()> {
        Ok(self.session.flush()?)
    }

    fn reset(&self) -> VideoResult<()> {
        Ok(self.session.reset()?)
    }

    fn event_pipe(&self) -> &std::fs::File {
        self.session.pipe()
    }

    fn use_output_buffer(
        &self,
        picture_buffer_id: i32,
        format: Format,
        output_buffer: RawDescriptor,
        planes: &[FramePlane],
        modifier: u64,
    ) -> VideoResult<()> {
        let vda_planes: Vec<libvda::FramePlane> = planes.into_iter().map(Into::into).collect();
        Ok(self.session.use_output_buffer(
            picture_buffer_id,
            libvda::PixelFormat::try_from(format)?,
            output_buffer,
            &vda_planes,
            modifier,
        )?)
    }

    fn reuse_output_buffer(&self, picture_buffer_id: i32) -> VideoResult<()> {
        Ok(self.session.reuse_output_buffer(picture_buffer_id)?)
    }

    fn read_event(&mut self) -> VideoResult<DecoderEvent> {
        self.session
            .read_event()
            .map(Into::into)
            .map_err(Into::into)
    }
}

impl<'a> DecoderBackend for &'a libvda::decode::VdaInstance {
    type Session = LibvdaSession<'a>;

    fn new_session(&self, format: Format) -> VideoResult<Self::Session> {
        let profile = libvda::Profile::try_from(format)?;
        let session = self.open_session(profile).map_err(|e| {
            error!("failed to open a session for {:?}: {}", format, e);
            VideoError::InvalidOperation
        })?;

        Ok(LibvdaSession { session })
    }
}
<commit_msg>virtio: video: decoder: remove lifetimes on VDA instance/sessions<commit_after>// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use base::{error, RawDescriptor};
use std::convert::TryFrom;

use libvda::decode::Event as LibvdaEvent;

use crate::virtio::video::{
    decoder::backend::*,
    error::{VideoError, VideoResult},
    format::{Format, Rect},
};

impl TryFrom<Format> for libvda::Profile {
    type Error = VideoError;

    fn try_from(format: Format) -> Result<Self, Self::Error> {
        Ok(match format {
            Format::VP8 => libvda::Profile::VP8,
            Format::VP9 => libvda::Profile::VP9Profile0,
            Format::H264 => libvda::Profile::H264ProfileBaseline,
            _ => {
                error!("specified format {} is not supported by VDA", format);
                return Err(VideoError::InvalidParameter);
            }
        })
    }
}

impl TryFrom<Format> for libvda::PixelFormat {
    type Error = VideoError;

    fn try_from(format: Format) -> Result<Self, Self::Error> {
        Ok(match format {
            Format::NV12 => libvda::PixelFormat::NV12,
            _ => {
                error!("specified format {} is not supported by VDA", format);
                return Err(VideoError::InvalidParameter);
            }
        })
    }
}

impl From<&FramePlane> for libvda::FramePlane {
    fn from(plane: &FramePlane) -> Self {
        libvda::FramePlane {
            offset: plane.offset,
            stride: plane.stride,
        }
    }
}

impl From<libvda::decode::Event> for DecoderEvent {
    fn from(event: libvda::decode::Event) -> Self {
        // We cannot use the From trait here since neither libvda::decode::Response
        // no std::result::Result are defined in the current crate.
        fn vda_response_to_result(resp: libvda::decode::Response) -> VideoResult<()> {
            match resp {
                libvda::decode::Response::Success => Ok(()),
                resp => Err(VideoError::VdaFailure(resp)),
            }
        }

        match event {
            LibvdaEvent::ProvidePictureBuffers {
                min_num_buffers,
                width,
                height,
                visible_rect_left,
                visible_rect_top,
                visible_rect_right,
                visible_rect_bottom,
            } => DecoderEvent::ProvidePictureBuffers {
                min_num_buffers,
                width,
                height,
                visible_rect: Rect {
                    left: visible_rect_left,
                    top: visible_rect_top,
                    right: visible_rect_right,
                    bottom: visible_rect_bottom,
                },
            },
            LibvdaEvent::PictureReady {
                buffer_id,
                bitstream_id,
                left,
                top,
                right,
                bottom,
            } => DecoderEvent::PictureReady {
                picture_buffer_id: buffer_id,
                bitstream_id,
                visible_rect: Rect {
                    left,
                    top,
                    right,
                    bottom,
                },
            },
            LibvdaEvent::NotifyEndOfBitstreamBuffer { bitstream_id } => {
                DecoderEvent::NotifyEndOfBitstreamBuffer(bitstream_id)
            }
            LibvdaEvent::NotifyError(resp) => {
                DecoderEvent::NotifyError(VideoError::VdaFailure(resp))
            }
            LibvdaEvent::ResetResponse(resp) => {
                DecoderEvent::ResetCompleted(vda_response_to_result(resp))
            }
            LibvdaEvent::FlushResponse(resp) => {
                DecoderEvent::FlushCompleted(vda_response_to_result(resp))
            }
        }
    }
}

pub struct LibvdaSession {
    session: libvda::decode::Session,
}

impl DecoderSession for LibvdaSession {
    fn set_output_buffer_count(&self, count: usize) -> VideoResult<()> {
        Ok(self.session.set_output_buffer_count(count)?)
    }

    fn decode(
        &self,
        bitstream_id: i32,
        descriptor: RawDescriptor,
        offset: u32,
        bytes_used: u32,
    ) -> VideoResult<()> {
        Ok(self
            .session
            .decode(bitstream_id, descriptor, offset, bytes_used)?)
    }

    fn flush(&self) -> VideoResult<()> {
        Ok(self.session.flush()?)
    }

    fn reset(&self) -> VideoResult<()> {
        Ok(self.session.reset()?)
    }

    fn event_pipe(&self) -> &std::fs::File {
        self.session.pipe()
    }

    fn use_output_buffer(
        &self,
        picture_buffer_id: i32,
        format: Format,
        output_buffer: RawDescriptor,
        planes: &[FramePlane],
        modifier: u64,
    ) -> VideoResult<()> {
        let vda_planes: Vec<libvda::FramePlane> = planes.into_iter().map(Into::into).collect();
        Ok(self.session.use_output_buffer(
            picture_buffer_id,
            libvda::PixelFormat::try_from(format)?,
            output_buffer,
            &vda_planes,
            modifier,
        )?)
    }

    fn reuse_output_buffer(&self, picture_buffer_id: i32) -> VideoResult<()> {
        Ok(self.session.reuse_output_buffer(picture_buffer_id)?)
    }

    fn read_event(&mut self) -> VideoResult<DecoderEvent> {
        self.session
            .read_event()
            .map(Into::into)
            .map_err(Into::into)
    }
}

impl DecoderBackend for &libvda::decode::VdaInstance {
    type Session = LibvdaSession;

    fn new_session(&self, format: Format) -> VideoResult<Self::Session> {
        let profile = libvda::Profile::try_from(format)?;
        let session = self.open_session(profile).map_err(|e| {
            error!("failed to open a session for {:?}: {}", format, e);
            VideoError::InvalidOperation
        })?;

        Ok(LibvdaSession { session })
    }
}
<|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/. */

<%namespace name="helpers" file="/helpers.mako.rs" />
<% from data import Keyword %>
<% data.new_style_struct("InheritedText", inherited=True, gecko_name="Text") %>

${helpers.predefined_type(
    "line-height",
    "LineHeight",
    "computed::LineHeight::normal()",
    animation_value_type="LineHeight",
    flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE \
           APPLIES_TO_PLACEHOLDER GETCS_NEEDS_LAYOUT_FLUSH",
    spec="https://drafts.csswg.org/css2/visudet.html#propdef-line-height",
    servo_restyle_damage="reflow"
)}

// CSS Text Module Level 3

// TODO(pcwalton): `full-width`
${helpers.single_keyword(
    "text-transform",
    "none capitalize uppercase lowercase",
    extra_gecko_values="full-width full-size-kana",
    animation_value_type="discrete",
    flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
    spec="https://drafts.csswg.org/css-text/#propdef-text-transform",
    servo_restyle_damage="rebuild_and_reflow",
)}

${helpers.single_keyword(
    "hyphens",
    "manual none auto",
    gecko_enum_prefix="StyleHyphens",
    products="gecko",
    animation_value_type="discrete",
    extra_prefixes="moz",
    spec="https://drafts.csswg.org/css-text/#propdef-hyphens",
)}

// TODO: Support <percentage>
${helpers.single_keyword(
    "-moz-text-size-adjust",
    "auto none",
    gecko_constant_prefix="NS_STYLE_TEXT_SIZE_ADJUST",
    gecko_ffi_name="mTextSizeAdjust",
    products="gecko", animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-size-adjust/#adjustment-control",
    alias="-webkit-text-size-adjust",
)}

${helpers.predefined_type(
    "text-indent",
    "LengthOrPercentage",
    "computed::LengthOrPercentage::Length(computed::Length::new(0.))",
    animation_value_type="ComputedValue",
    spec="https://drafts.csswg.org/css-text/#propdef-text-indent",
    allow_quirks=True,
    servo_restyle_damage = "reflow",
)}

// Also known as "word-wrap" (which is more popular because of IE), but this is the preferred
// name per CSS-TEXT 6.2.
${helpers.single_keyword(
    "overflow-wrap",
    "normal break-word",
    gecko_constant_prefix="NS_STYLE_OVERFLOWWRAP",
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-text/#propdef-overflow-wrap",
    alias="word-wrap",
    servo_restyle_damage="rebuild_and_reflow",
)}

// TODO(pcwalton): Support `word-break: keep-all` once we have better CJK support.
${helpers.single_keyword(
    "word-break",
    "normal break-all keep-all",
    gecko_constant_prefix="NS_STYLE_WORDBREAK",
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-text/#propdef-word-break",
    servo_restyle_damage="rebuild_and_reflow",
)}

// TODO(pcwalton): Support `text-justify: distribute`.
<%helpers:single_keyword
    name="text-justify"
    values="auto none inter-word"
    extra_gecko_values="inter-character"
    extra_specified="${'distribute' if product == 'gecko' else ''}"
    gecko_enum_prefix="StyleTextJustify"
    animation_value_type="discrete"
    gecko_pref="layout.css.text-justify.enabled"
    flags="APPLIES_TO_PLACEHOLDER",
    spec="https://drafts.csswg.org/css-text/#propdef-text-justify"
    servo_restyle_damage="rebuild_and_reflow"
>
    % if product == 'gecko':
    impl ToComputedValue for SpecifiedValue {
        type ComputedValue = computed_value::T;

        #[inline]
        fn to_computed_value(&self, _: &Context) -> computed_value::T {
            match *self {
                % for value in "Auto None InterCharacter InterWord".split():
                SpecifiedValue::${value} => computed_value::T::${value},
                % endfor
                // https://drafts.csswg.org/css-text-3/#valdef-text-justify-distribute
                SpecifiedValue::Distribute => computed_value::T::InterCharacter,
            }
        }

        #[inline]
        fn from_computed_value(computed: &computed_value::T) -> SpecifiedValue {
            match *computed {
                % for value in "Auto None InterCharacter InterWord".split():
                computed_value::T::${value} => SpecifiedValue::${value},
                % endfor
            }
        }
    }
    % endif
</%helpers:single_keyword>

${helpers.single_keyword(
    "text-align-last",
    "auto start end left right center justify",
    products="gecko",
    gecko_constant_prefix="NS_STYLE_TEXT_ALIGN",
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-text/#propdef-text-align-last",
)}

// TODO make this a shorthand and implement text-align-last/text-align-all
${helpers.predefined_type(
    "text-align",
    "TextAlign",
    "computed::TextAlign::start()",
    animation_value_type="discrete",
    flags="APPLIES_TO_PLACEHOLDER",
    spec="https://drafts.csswg.org/css-text/#propdef-text-align",
    servo_restyle_damage = "reflow",
)}

${helpers.predefined_type(
    "letter-spacing",
    "LetterSpacing",
    "computed::LetterSpacing::normal()",
    animation_value_type="ComputedValue",
    flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
    spec="https://drafts.csswg.org/css-text/#propdef-letter-spacing",
    servo_restyle_damage="rebuild_and_reflow",
)}

${helpers.predefined_type(
    "word-spacing",
    "WordSpacing",
    "computed::WordSpacing::normal()",
    animation_value_type="ComputedValue",
    flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
    spec="https://drafts.csswg.org/css-text/#propdef-word-spacing",
    servo_restyle_damage="rebuild_and_reflow",
)}

<%helpers:single_keyword
    name="white-space"
    values="normal pre nowrap pre-wrap pre-line"
    extra_gecko_values="-moz-pre-space"
    gecko_enum_prefix="StyleWhiteSpace"
    needs_conversion="True"
    animation_value_type="discrete"
    // Only allowed for UA sheets, which set it !important.
    flags="APPLIES_TO_PLACEHOLDER"
    spec="https://drafts.csswg.org/css-text/#propdef-white-space"
    servo_restyle_damage="rebuild_and_reflow"
>
    % if product != "gecko":
    impl SpecifiedValue {
        pub fn allow_wrap(&self) -> bool {
            match *self {
                SpecifiedValue::Nowrap |
                SpecifiedValue::Pre => false,
                SpecifiedValue::Normal |
                SpecifiedValue::PreWrap |
                SpecifiedValue::PreLine => true,
            }
        }

        pub fn preserve_newlines(&self) -> bool {
            match *self {
                SpecifiedValue::Normal |
                SpecifiedValue::Nowrap => false,
                SpecifiedValue::Pre |
                SpecifiedValue::PreWrap |
                SpecifiedValue::PreLine => true,
            }
        }

        pub fn preserve_spaces(&self) -> bool {
            match *self {
                SpecifiedValue::Normal |
                SpecifiedValue::Nowrap |
                SpecifiedValue::PreLine => false,
                SpecifiedValue::Pre |
                SpecifiedValue::PreWrap => true,
            }
        }
    }
    % endif
</%helpers:single_keyword>

${helpers.predefined_type(
    "text-shadow",
    "SimpleShadow",
    None,
    vector=True,
    vector_animation_type="with_zero",
    animation_value_type="AnimatedTextShadowList",
    ignored_when_colors_disabled=True,
    flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
    spec="https://drafts.csswg.org/css-text-decor-3/#text-shadow-property",
)}

${helpers.predefined_type(
    "text-emphasis-style",
    "TextEmphasisStyle",
    None,
    initial_specified_value="SpecifiedValue::None",
    products="gecko",
    boxed=True,
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-text-decor/#propdef-text-emphasis-style",
)}

${helpers.predefined_type(
    "text-emphasis-position",
    "TextEmphasisPosition",
    "computed::TextEmphasisPosition::over_right()",
    initial_specified_value="specified::TextEmphasisPosition::over_right()",
    products="gecko",
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-text-decor/#propdef-text-emphasis-position",
)}

${helpers.predefined_type(
    "text-emphasis-color",
    "Color",
    "computed_value::T::currentcolor()",
    initial_specified_value="specified::Color::currentcolor()",
    products="gecko",
    animation_value_type="AnimatedColor",
    ignored_when_colors_disabled=True,
    spec="https://drafts.csswg.org/css-text-decor/#propdef-text-emphasis-color",
)}

${helpers.predefined_type(
    "-moz-tab-size",
    "MozTabSize",
    "generics::text::MozTabSize::Number(From::from(8.0))",
    products="gecko",
    animation_value_type="AnimatedMozTabSize",
    spec="https://drafts.csswg.org/css-text-3/#tab-size-property",
)}

// CSS Compatibility
// https://compat.spec.whatwg.org
${helpers.predefined_type(
    "-webkit-text-fill-color",
    "Color",
    "computed_value::T::currentcolor()",
    products="gecko",
    gecko_pref="layout.css.prefixes.webkit",
    animation_value_type="AnimatedColor",
    ignored_when_colors_disabled=True,
    flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
    spec="https://compat.spec.whatwg.org/#the-webkit-text-fill-color",
)}

${helpers.predefined_type(
    "-webkit-text-stroke-color",
    "Color",
    "computed_value::T::currentcolor()",
    initial_specified_value="specified::Color::currentcolor()",
    products="gecko",
    animation_value_type="AnimatedColor",
    ignored_when_colors_disabled=True,
    gecko_pref="layout.css.prefixes.webkit",
    flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
    spec="https://compat.spec.whatwg.org/#the-webkit-text-stroke-color",
)}

${helpers.predefined_type(
    "-webkit-text-stroke-width",
    "BorderSideWidth",
    "::values::computed::NonNegativeLength::new(0.)",
    initial_specified_value="specified::BorderSideWidth::Length(specified::Length::zero())",
    computed_type="::values::computed::NonNegativeLength",
    products="gecko",
    gecko_pref="layout.css.prefixes.webkit",
    flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
    spec="https://compat.spec.whatwg.org/#the-webkit-text-stroke-width",
    animation_value_type="discrete",
)}

// CSS Ruby Layout Module Level 1
// https://drafts.csswg.org/css-ruby/
${helpers.single_keyword(
    "ruby-align",
    "space-around start center space-between",
    products="gecko",
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-ruby/#ruby-align-property",
)}

${helpers.single_keyword(
    "ruby-position",
    "over under",
    products="gecko",
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-ruby/#ruby-position-property",
)}

// CSS Writing Modes Module Level 3
// https://drafts.csswg.org/css-writing-modes-3/

${helpers.single_keyword(
    "text-combine-upright",
    "none all",
    products="gecko",
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-writing-modes-3/#text-combine-upright",
)}

// SVG 1.1: Section 11 - Painting: Filling, Stroking and Marker Symbols
${helpers.single_keyword(
    "text-rendering",
    "auto optimizespeed optimizelegibility geometricprecision",
    animation_value_type="discrete",
    spec="https://www.w3.org/TR/SVG11/painting.html#TextRenderingProperty",
    servo_restyle_damage="rebuild_and_reflow",
)}

// FIXME Firefox expects the initial value of this property to change depending
// on the value of the layout.css.control-characters.visible pref.
${helpers.single_keyword(
    "-moz-control-character-visibility",
    "hidden visible",
    gecko_constant_prefix="NS_STYLE_CONTROL_CHARACTER_VISIBILITY",
    gecko_ffi_name="mControlCharacterVisibility",
    animation_value_type="none",
    products="gecko",
    spec="Nonstandard",
)}
<commit_msg>Backed out changeset a00b402fb8e8 (bug 1498148) for Linting failure in builds/worker/checkouts/gecko/tools/lint/wpt.yml CLOSED TREE<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/. */

<%namespace name="helpers" file="/helpers.mako.rs" />
<% from data import Keyword %>
<% data.new_style_struct("InheritedText", inherited=True, gecko_name="Text") %>

${helpers.predefined_type(
    "line-height",
    "LineHeight",
    "computed::LineHeight::normal()",
    animation_value_type="LineHeight",
    flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE \
           APPLIES_TO_PLACEHOLDER GETCS_NEEDS_LAYOUT_FLUSH",
    spec="https://drafts.csswg.org/css2/visudet.html#propdef-line-height",
    servo_restyle_damage="reflow"
)}

// CSS Text Module Level 3

// TODO(pcwalton): `full-width`
${helpers.single_keyword(
    "text-transform",
    "none capitalize uppercase lowercase",
    extra_gecko_values="full-width",
    animation_value_type="discrete",
    flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
    spec="https://drafts.csswg.org/css-text/#propdef-text-transform",
    servo_restyle_damage="rebuild_and_reflow",
)}

${helpers.single_keyword(
    "hyphens",
    "manual none auto",
    gecko_enum_prefix="StyleHyphens",
    products="gecko",
    animation_value_type="discrete",
    extra_prefixes="moz",
    spec="https://drafts.csswg.org/css-text/#propdef-hyphens",
)}

// TODO: Support <percentage>
${helpers.single_keyword(
    "-moz-text-size-adjust",
    "auto none",
    gecko_constant_prefix="NS_STYLE_TEXT_SIZE_ADJUST",
    gecko_ffi_name="mTextSizeAdjust",
    products="gecko", animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-size-adjust/#adjustment-control",
    alias="-webkit-text-size-adjust",
)}

${helpers.predefined_type(
    "text-indent",
    "LengthOrPercentage",
    "computed::LengthOrPercentage::Length(computed::Length::new(0.))",
    animation_value_type="ComputedValue",
    spec="https://drafts.csswg.org/css-text/#propdef-text-indent",
    allow_quirks=True,
    servo_restyle_damage = "reflow",
)}

// Also known as "word-wrap" (which is more popular because of IE), but this is the preferred
// name per CSS-TEXT 6.2.
${helpers.single_keyword(
    "overflow-wrap",
    "normal break-word",
    gecko_constant_prefix="NS_STYLE_OVERFLOWWRAP",
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-text/#propdef-overflow-wrap",
    alias="word-wrap",
    servo_restyle_damage="rebuild_and_reflow",
)}

// TODO(pcwalton): Support `word-break: keep-all` once we have better CJK support.
${helpers.single_keyword(
    "word-break",
    "normal break-all keep-all",
    gecko_constant_prefix="NS_STYLE_WORDBREAK",
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-text/#propdef-word-break",
    servo_restyle_damage="rebuild_and_reflow",
)}

// TODO(pcwalton): Support `text-justify: distribute`.
<%helpers:single_keyword
    name="text-justify"
    values="auto none inter-word"
    extra_gecko_values="inter-character"
    extra_specified="${'distribute' if product == 'gecko' else ''}"
    gecko_enum_prefix="StyleTextJustify"
    animation_value_type="discrete"
    gecko_pref="layout.css.text-justify.enabled"
    flags="APPLIES_TO_PLACEHOLDER",
    spec="https://drafts.csswg.org/css-text/#propdef-text-justify"
    servo_restyle_damage="rebuild_and_reflow"
>
    % if product == 'gecko':
    impl ToComputedValue for SpecifiedValue {
        type ComputedValue = computed_value::T;

        #[inline]
        fn to_computed_value(&self, _: &Context) -> computed_value::T {
            match *self {
                % for value in "Auto None InterCharacter InterWord".split():
                SpecifiedValue::${value} => computed_value::T::${value},
                % endfor
                // https://drafts.csswg.org/css-text-3/#valdef-text-justify-distribute
                SpecifiedValue::Distribute => computed_value::T::InterCharacter,
            }
        }

        #[inline]
        fn from_computed_value(computed: &computed_value::T) -> SpecifiedValue {
            match *computed {
                % for value in "Auto None InterCharacter InterWord".split():
                computed_value::T::${value} => SpecifiedValue::${value},
                % endfor
            }
        }
    }
    % endif
</%helpers:single_keyword>

${helpers.single_keyword(
    "text-align-last",
    "auto start end left right center justify",
    products="gecko",
    gecko_constant_prefix="NS_STYLE_TEXT_ALIGN",
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-text/#propdef-text-align-last",
)}

// TODO make this a shorthand and implement text-align-last/text-align-all
${helpers.predefined_type(
    "text-align",
    "TextAlign",
    "computed::TextAlign::start()",
    animation_value_type="discrete",
    flags="APPLIES_TO_PLACEHOLDER",
    spec="https://drafts.csswg.org/css-text/#propdef-text-align",
    servo_restyle_damage = "reflow",
)}

${helpers.predefined_type(
    "letter-spacing",
    "LetterSpacing",
    "computed::LetterSpacing::normal()",
    animation_value_type="ComputedValue",
    flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
    spec="https://drafts.csswg.org/css-text/#propdef-letter-spacing",
    servo_restyle_damage="rebuild_and_reflow",
)}

${helpers.predefined_type(
    "word-spacing",
    "WordSpacing",
    "computed::WordSpacing::normal()",
    animation_value_type="ComputedValue",
    flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
    spec="https://drafts.csswg.org/css-text/#propdef-word-spacing",
    servo_restyle_damage="rebuild_and_reflow",
)}

<%helpers:single_keyword
    name="white-space"
    values="normal pre nowrap pre-wrap pre-line"
    extra_gecko_values="-moz-pre-space"
    gecko_enum_prefix="StyleWhiteSpace"
    needs_conversion="True"
    animation_value_type="discrete"
    // Only allowed for UA sheets, which set it !important.
    flags="APPLIES_TO_PLACEHOLDER"
    spec="https://drafts.csswg.org/css-text/#propdef-white-space"
    servo_restyle_damage="rebuild_and_reflow"
>
    % if product != "gecko":
    impl SpecifiedValue {
        pub fn allow_wrap(&self) -> bool {
            match *self {
                SpecifiedValue::Nowrap |
                SpecifiedValue::Pre => false,
                SpecifiedValue::Normal |
                SpecifiedValue::PreWrap |
                SpecifiedValue::PreLine => true,
            }
        }

        pub fn preserve_newlines(&self) -> bool {
            match *self {
                SpecifiedValue::Normal |
                SpecifiedValue::Nowrap => false,
                SpecifiedValue::Pre |
                SpecifiedValue::PreWrap |
                SpecifiedValue::PreLine => true,
            }
        }

        pub fn preserve_spaces(&self) -> bool {
            match *self {
                SpecifiedValue::Normal |
                SpecifiedValue::Nowrap |
                SpecifiedValue::PreLine => false,
                SpecifiedValue::Pre |
                SpecifiedValue::PreWrap => true,
            }
        }
    }
    % endif
</%helpers:single_keyword>

${helpers.predefined_type(
    "text-shadow",
    "SimpleShadow",
    None,
    vector=True,
    vector_animation_type="with_zero",
    animation_value_type="AnimatedTextShadowList",
    ignored_when_colors_disabled=True,
    flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
    spec="https://drafts.csswg.org/css-text-decor-3/#text-shadow-property",
)}

${helpers.predefined_type(
    "text-emphasis-style",
    "TextEmphasisStyle",
    None,
    initial_specified_value="SpecifiedValue::None",
    products="gecko",
    boxed=True,
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-text-decor/#propdef-text-emphasis-style",
)}

${helpers.predefined_type(
    "text-emphasis-position",
    "TextEmphasisPosition",
    "computed::TextEmphasisPosition::over_right()",
    initial_specified_value="specified::TextEmphasisPosition::over_right()",
    products="gecko",
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-text-decor/#propdef-text-emphasis-position",
)}

${helpers.predefined_type(
    "text-emphasis-color",
    "Color",
    "computed_value::T::currentcolor()",
    initial_specified_value="specified::Color::currentcolor()",
    products="gecko",
    animation_value_type="AnimatedColor",
    ignored_when_colors_disabled=True,
    spec="https://drafts.csswg.org/css-text-decor/#propdef-text-emphasis-color",
)}

${helpers.predefined_type(
    "-moz-tab-size",
    "MozTabSize",
    "generics::text::MozTabSize::Number(From::from(8.0))",
    products="gecko",
    animation_value_type="AnimatedMozTabSize",
    spec="https://drafts.csswg.org/css-text-3/#tab-size-property",
)}

// CSS Compatibility
// https://compat.spec.whatwg.org
${helpers.predefined_type(
    "-webkit-text-fill-color",
    "Color",
    "computed_value::T::currentcolor()",
    products="gecko",
    gecko_pref="layout.css.prefixes.webkit",
    animation_value_type="AnimatedColor",
    ignored_when_colors_disabled=True,
    flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
    spec="https://compat.spec.whatwg.org/#the-webkit-text-fill-color",
)}

${helpers.predefined_type(
    "-webkit-text-stroke-color",
    "Color",
    "computed_value::T::currentcolor()",
    initial_specified_value="specified::Color::currentcolor()",
    products="gecko",
    animation_value_type="AnimatedColor",
    ignored_when_colors_disabled=True,
    gecko_pref="layout.css.prefixes.webkit",
    flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
    spec="https://compat.spec.whatwg.org/#the-webkit-text-stroke-color",
)}

${helpers.predefined_type(
    "-webkit-text-stroke-width",
    "BorderSideWidth",
    "::values::computed::NonNegativeLength::new(0.)",
    initial_specified_value="specified::BorderSideWidth::Length(specified::Length::zero())",
    computed_type="::values::computed::NonNegativeLength",
    products="gecko",
    gecko_pref="layout.css.prefixes.webkit",
    flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
    spec="https://compat.spec.whatwg.org/#the-webkit-text-stroke-width",
    animation_value_type="discrete",
)}

// CSS Ruby Layout Module Level 1
// https://drafts.csswg.org/css-ruby/
${helpers.single_keyword(
    "ruby-align",
    "space-around start center space-between",
    products="gecko",
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-ruby/#ruby-align-property",
)}

${helpers.single_keyword(
    "ruby-position",
    "over under",
    products="gecko",
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-ruby/#ruby-position-property",
)}

// CSS Writing Modes Module Level 3
// https://drafts.csswg.org/css-writing-modes-3/

${helpers.single_keyword(
    "text-combine-upright",
    "none all",
    products="gecko",
    animation_value_type="discrete",
    spec="https://drafts.csswg.org/css-writing-modes-3/#text-combine-upright",
)}

// SVG 1.1: Section 11 - Painting: Filling, Stroking and Marker Symbols
${helpers.single_keyword(
    "text-rendering",
    "auto optimizespeed optimizelegibility geometricprecision",
    animation_value_type="discrete",
    spec="https://www.w3.org/TR/SVG11/painting.html#TextRenderingProperty",
    servo_restyle_damage="rebuild_and_reflow",
)}

// FIXME Firefox expects the initial value of this property to change depending
// on the value of the layout.css.control-characters.visible pref.
${helpers.single_keyword(
    "-moz-control-character-visibility",
    "hidden visible",
    gecko_constant_prefix="NS_STYLE_CONTROL_CHARACTER_VISIBILITY",
    gecko_ffi_name="mControlCharacterVisibility",
    animation_value_type="none",
    products="gecko",
    spec="Nonstandard",
)}
<|endoftext|>


<commit_before>use std::io;
use std::io::stdio;
use std::collections;

struct Difficulty {
    min: uint,
    max: uint
}

fn main() {

    start();
}

fn start() {
    println!("WELCOME TO HANGMAN");
    println!("Please enter a difficulty: easy, medium, or hard:");

    loop {
        io::print(">");
        let input = &stdio::stdin()
                            .read_line()
                            .ok()
                            .expect("Failed to read line.");

        let difficulty_opt = match input.as_slice() {
            "easy\n"   => Some(Difficulty { min: 3, max: 5 }),
            "medium\n" => Some(Difficulty { min: 5, max: 7 }),
            "hard\n"   => Some(Difficulty { min: 7, max: 9 }),
            _          => None
        };

        let difficulty = match difficulty_opt {
            Some(d) => d,
            None    => {
                println!("Invalid input.");
                println!("Please enter a difficulty: easy, medium, or hard:");
                continue
            }
        };

        println!("Minimum word length set to {}", difficulty.min);
        println!("Maximum word length set to {}", difficulty.max);

        let words: Box<Vec<String>> = get_words(&difficulty);

    }
}

fn get_words(difficulty: &Difficulty) -> Box<Vec<String>> {
    let mut words = Vec::new();
    let min = difficulty.min;
    let max = difficulty.max;

    let path = Path::new("/usr/share/dict/words");
    let words_file = io::File::open(&path).ok().expect("Error opening file.");
    let mut reader = io::BufferedReader::new(words_file);
    let mut counter = 0u;
    loop {
        match reader.read_line() {
            Ok(line) => {
                if min < line.len() && line.len() < max {
                    words.push(line
                               .as_slice()
                               .trim_right_chars('\n')
                               .to_string());
                    counter += 1;
                }
            }
            Err(why) => match why.kind {
                io::EndOfFile => break,
                _             => fail!("Error reading file: {}", why)
            }
        }
    }
    println!("Read in {} words.", counter);
    box words
}

<commit_msg>Add a way to quit the game, also `fail!` is now `panic!`<commit_after>use std::io;
use std::io::stdio;
use std::collections;

struct Difficulty {
    min: uint,
    max: uint
}

fn main() {
    start();
}

fn start() {
    println!("WELCOME TO HANGMAN");
    println!("Type 'bye' at any time to quit.");
    println!("Please enter a difficulty: easy, medium, or hard.");

    loop {
        io::print(">");
        let input = &stdio::stdin()
                            .read_line()
                            .ok()
                            .expect("Failed to read line.");

        if input.as_slice() == "bye\n" {
            break;
        }

        let difficulty_opt = match input.as_slice() {
            "easy\n"   => Some(Difficulty { min: 3, max: 5 }),
            "medium\n" => Some(Difficulty { min: 5, max: 7 }),
            "hard\n"   => Some(Difficulty { min: 7, max: 9 }),
            _          => None
        };

        let difficulty = match difficulty_opt {
            Some(d) => d,
            None    => {
                println!("Invalid input.");
                println!("Please enter a difficulty: easy, medium, or hard:");
                continue
            }
        };

        println!("Minimum word length set to {}", difficulty.min);
        println!("Maximum word length set to {}", difficulty.max);

        let words: Box<Vec<String>> = get_words(&difficulty);
    }
}

fn get_words(difficulty: &Difficulty) -> Box<Vec<String>> {
    let mut words = Vec::new();

    let path = Path::new("/usr/share/dict/words");
    let words_file = io::File::open(&path).ok().expect("Error opening file.");
    let mut reader = io::BufferedReader::new(words_file);
    let mut counter = 0u;
    loop {
        match reader.read_line() {
            Ok(line) => {
                if difficulty.min < line.len() && line.len() < difficulty.max {
                    words.push(line
                               .as_slice()
                               .trim_right_chars('\n')
                               .to_string());
                    counter += 1;
                }
            }
            Err(why) => match why.kind {
                io::EndOfFile => break,
                _             => panic!("Error reading file: {}", why)
            }
        }
    }
    println!("Read in {} words.", counter);
    box words
}

<|endoftext|>


<commit_before>extern crate bindgen;
#[cfg(feature = "static")]
extern crate meson;
extern crate gl_generator;

use std::env;
use std::path::{Path, PathBuf};
use std::fs::File;
use gl_generator::{Registry, Api, Profile, Fallbacks, StaticGenerator};

// TODO these are wrong
static LIBRARIES: &'static [&'static str] =
    &["wlr-common", "wlr-backend", "wlr-session", "wlr-types"];

fn main() {
    let generated = bindgen::builder()
        .derive_debug(true)
        .generate_comments(true)
        .header("src/wlroots.h")
        .whitelisted_type(r"^wlr_.*$")
        .whitelisted_function(r"^wlr_.*$")
        .ctypes_prefix("libc")
        .clang_arg("-Iwlroots/include")
        .clang_arg("-Iwlroots/include/wlr")
        .clang_arg("-Iwlroots/include/xcursor")
        .clang_arg("-I/usr/include/pixman-1")
        .generate().unwrap();

    if cfg!(feature = "static") {
        println!("cargo:rustc-link-lib=dylib=wayland-server");
        println!("cargo:rustc-link-lib=dylib=EGL");
        println!("cargo:rustc-link-lib=dylib=GL");
        println!("cargo:rustc-link-lib=dylib=gbm");
        println!("cargo:rustc-link-lib=dylib=drm");
        println!("cargo:rustc-link-lib=dylib=input");
        println!("cargo:rustc-link-lib=dylib=udev");
        println!("cargo:rustc-link-lib=dylib=systemd");
        println!("cargo:rustc-link-lib=dylib=dbus-1");
        println!("cargo:rustc-link-lib=dylib=pixman");
    } else {
        for library in LIBRARIES {
            println!("cargo:rustc-link-lib=dylib={}", library);
        }
    }

    // generate the bindings
    generated.write_to_file("src/gen.rs").unwrap();

    meson();

    // Example Khronos building stuff
    // TODO Put behind feature flag?
    let dest = env::var("OUT_DIR").unwrap();
    let mut file = File::create(&Path::new(&dest).join("bindings.rs")).unwrap();
    Registry::new(Api::Gl, (4, 5), Profile::Core, Fallbacks::All, [])
        .write_bindings(StaticGenerator, &mut file)
        .unwrap();
}

#[cfg(not(feature = "static"))]
fn meson() {}

#[cfg(feature = "static")]
fn meson() {
    let build_path = PathBuf::from(env::var("OUT_DIR")
        .expect("Could not get OUT_DIR env variable"));
    build_path.join("build");
    let build_path_str = build_path.to_str()
        .expect("Could not turn build path into a string");
    println!("cargo:rustc-link-search=native=wlroots");
    println!("cargo:rustc-link-search=native={}/lib", build_path_str);
    println!("cargo:rustc-link-search=native={}/lib64", build_path_str);
    println!("cargo:rustc-link-search=native={}/build/", build_path_str);

    meson::build("wlroots", build_path_str);
}
<commit_msg>Fixed more linking<commit_after>extern crate bindgen;
#[cfg(feature = "static")]
extern crate meson;
extern crate gl_generator;

use std::env;
#[allow(unused_imports)]
use std::path::{Path, PathBuf};
use std::fs::File;
use gl_generator::{Registry, Api, Profile, Fallbacks, StaticGenerator};

// TODO these are wrong
static LIBRARIES: &'static [&'static str] =
    &["wlr-common", "wlr-backend", "wlr-session", "wlr-types"];

fn main() {
    let generated = bindgen::builder()
        .derive_debug(true)
        .generate_comments(true)
        .header("src/wlroots.h")
        .whitelisted_type(r"^wlr_.*$")
        .whitelisted_function(r"^wlr_.*$")
        .ctypes_prefix("libc")
        .clang_arg("-Iwlroots/include")
        .clang_arg("-Iwlroots/include/wlr")
        .clang_arg("-Iwlroots/include/xcursor")
        .clang_arg("-I/usr/include/pixman-1")
        .generate().unwrap();

    if cfg!(feature = "static") {
        println!("cargo:rustc-link-lib=dylib=X11");
        println!("cargo:rustc-link-lib=dylib=X11-xcb");
        println!("cargo:rustc-link-lib=dylib=xkbcommon");
        println!("cargo:rustc-link-lib=dylib=xcb");
        println!("cargo:rustc-link-lib=dylib=cap");
        println!("cargo:rustc-link-lib=dylib=wayland-egl");
        println!("cargo:rustc-link-lib=dylib=wayland-client");
        println!("cargo:rustc-link-lib=dylib=wayland-server");
        println!("cargo:rustc-link-lib=dylib=EGL");
        println!("cargo:rustc-link-lib=dylib=GL");
        println!("cargo:rustc-link-lib=dylib=gbm");
        println!("cargo:rustc-link-lib=dylib=drm");
        println!("cargo:rustc-link-lib=dylib=input");
        println!("cargo:rustc-link-lib=dylib=udev");
        println!("cargo:rustc-link-lib=dylib=systemd");
        println!("cargo:rustc-link-lib=dylib=dbus-1");
        println!("cargo:rustc-link-lib=dylib=pixman-1");

    } else {
        for library in LIBRARIES {
            println!("cargo:rustc-link-lib=dylib={}", library);
        }
    }

    // generate the bindings
    generated.write_to_file("src/gen.rs").unwrap();

    meson();

    // Example Khronos building stuff
    // TODO Put behind feature flag?
    let dest = env::var("OUT_DIR").unwrap();
    let mut file = File::create(&Path::new(&dest).join("bindings.rs")).unwrap();
    Registry::new(Api::Gl, (4, 5), Profile::Core, Fallbacks::All, [])
        .write_bindings(StaticGenerator, &mut file)
        .unwrap();
}

#[cfg(not(feature = "static"))]
fn meson() {}

#[cfg(feature = "static")]
fn meson() {
    let build_path = PathBuf::from(env::var("OUT_DIR")
        .expect("Could not get OUT_DIR env variable"));
    build_path.join("build");
    let build_path_str = build_path.to_str()
        .expect("Could not turn build path into a string");
    println!("cargo:rustc-link-search=native=wlroots");
    println!("cargo:rustc-link-search=native={}/lib", build_path_str);
    println!("cargo:rustc-link-search=native={}/lib64", build_path_str);
    println!("cargo:rustc-link-search=native={}/build/", build_path_str);
    if cfg!(feature = "static") {
        println!("cargo:rustc-link-search=native={}/util/", build_path_str);
        println!("cargo:rustc-link-search=native={}/types/", build_path_str);
        println!("cargo:rustc-link-search=native={}/protocol/", build_path_str);
        println!("cargo:rustc-link-search=native={}/xcursor/", build_path_str);
        println!("cargo:rustc-link-search=native={}/xwayland/", build_path_str);
        println!("cargo:rustc-link-search=native={}/backend/", build_path_str);
        println!("cargo:rustc-link-search=native={}/render/", build_path_str);

        println!("cargo:rustc-link-lib=static=wlr_util");
        println!("cargo:rustc-link-lib=static=wlr_types");
        println!("cargo:rustc-link-lib=static=wlr_xcursor");
        println!("cargo:rustc-link-lib=static=wlr_xwayland");
        println!("cargo:rustc-link-lib=static=wlr_backend");
        println!("cargo:rustc-link-lib=static=wlr_render");
        // wayland protocols
        println!("cargo:rustc-link-lib=static=wl_protos");
    }

    meson::build("wlroots", build_path_str);
}
<|endoftext|>


<commit_before>use audio::ac97::AC97;
use audio::intelhda::IntelHDA;

use collections::vec::Vec;

use common::debug;
use common::queue::Queue;

use drivers::pciconfig::PciConfig;

use network::intel8254x::Intel8254x;
use network::rtl8139::Rtl8139;

use programs::session::Session;

use schemes::file::FileScheme;

use usb::ehci::Ehci;
use usb::uhci::Uhci;
use usb::xhci::Xhci;

/// PCI device
pub unsafe fn pci_device(session: &mut Session,
                         mut pci: PciConfig,
                         class_id: u32,
                         subclass_id: u32,
                         interface_id: u32,
                         vendor_code: u32,
                         device_code: u32) {
    if class_id == 0x01 && subclass_id == 0x01 {
        if let Some(module) = FileScheme::new(pci) {
            session.items.push(module);
        }
    } else if class_id == 0x0C && subclass_id == 0x03 {
        if interface_id == 0x30 {
            let base = pci.read(0x10) as usize;

            let module = box Xhci {
                pci: pci,
                base: base & 0xFFFFFFF0,
                memory_mapped: base & 1 == 0,
                irq: pci.read(0x3C) as u8 & 0xF,
            };
            module.init();
            session.items.push(module);
        } else if interface_id == 0x20 {
            let base = pci.read(0x10) as usize;

            let mut module = box Ehci {
                pci: pci,
                base: base & 0xFFFFFFF0,
                memory_mapped: base & 1 == 0,
                irq: pci.read(0x3C) as u8 & 0xF,
            };
            module.init();
            session.items.push(module);
        } else if interface_id == 0x10 {
            let base = pci.read(0x10) as usize;

            debug::d("OHCI Controller on ");
            debug::dh(base & 0xFFFFFFF0);
            debug::dl();
        } else if interface_id == 0x00 {
            session.items.push(Uhci::new(pci));
        } else {
            debug::d("Unknown USB interface version\n");
        }
    } else {
        match vendor_code {
            0x10EC => match device_code { // REALTEK
                0x8139 => {
                    session.items.push(Rtl8139::new(pci));
                }
                _ => (),
            },
            0x8086 => match device_code { // INTEL
                0x100E => {
                    let base = pci.read(0x10) as usize;
                    let mut module = box Intel8254x {
                        pci: pci,
                        base: base & 0xFFFFFFF0,
                        memory_mapped: base & 1 == 0,
                        irq: pci.read(0x3C) as u8 & 0xF,
                        resources: Vec::new(),
                        inbound: Queue::new(),
                        outbound: Queue::new(),
                    };
                    module.init();
                    session.items.push(module);
                }
                0x2415 => session.items.push(AC97::new(pci)),
                0x24C5 => session.items.push(AC97::new(pci)),
                0x2668 => {
                    let base = pci.read(0x10) as usize;
                    let mut module = box IntelHDA {
                        pci: pci,
                        base: base & 0xFFFFFFF0,
                        memory_mapped: base & 1 == 0,
                        irq: pci.read(0x3C) as u8 & 0xF,
                    };
                    module.init();
                    session.items.push(module);
                }
                _ => (),
            },
            _ => (),
        }
    }
}

/// Initialize PCI session
pub unsafe fn pci_init(session: &mut Session) {
    for bus in 0..256 {
        for slot in 0..32 {
            for func in 0..8 {
                let mut pci = PciConfig::new(bus as u8, slot as u8, func as u8);
                let id = pci.read(0);

                if (id & 0xFFFF) != 0xFFFF {
                    let class_id = pci.read(8);

                    debug::d(" * PCI ");
                    debug::dd(bus);
                    debug::d(", ");
                    debug::dd(slot);
                    debug::d(", ");
                    debug::dd(func);
                    debug::d(": ID ");
                    debug::dh(id as usize);
                    debug::d(" CL ");
                    debug::dh(class_id as usize);

                    for i in 0..6 {
                        let bar = pci.read(i * 4 + 0x10);
                        if bar > 0 {
                            debug::d(" BAR");
                            debug::dd(i as usize);
                            debug::d(": ");
                            debug::dh(bar as usize);

                            pci.write(i * 4 + 0x10, 0xFFFFFFFF);
                            let size = (0xFFFFFFFF - (pci.read(i * 4 + 0x10) & 0xFFFFFFF0)) + 1;
                            pci.write(i * 4 + 0x10, bar);

                            if size > 0 {
                                debug::d(" ");
                                debug::dd(size as usize);
                            }
                        }
                    }

                    debug::dl();

                    pci_device(session,
                               pci,
                               (class_id >> 24) & 0xFF,
                               (class_id >> 16) & 0xFF,
                               (class_id >> 8) & 0xFF,
                               id & 0xFFFF,
                               (id >> 16) & 0xFFFF);
                }
            }
        }
    }
}
<commit_msg>Cleanup of debug calls<commit_after>use audio::ac97::AC97;
use audio::intelhda::IntelHDA;

use collections::vec::Vec;

use common::debug;
use common::queue::Queue;

use drivers::pciconfig::PciConfig;

use network::intel8254x::Intel8254x;
use network::rtl8139::Rtl8139;

use programs::session::Session;

use schemes::file::FileScheme;

use usb::ehci::Ehci;
use usb::uhci::Uhci;
use usb::xhci::Xhci;

/// PCI device
pub unsafe fn pci_device(session: &mut Session,
                         mut pci: PciConfig,
                         class_id: u32,
                         subclass_id: u32,
                         interface_id: u32,
                         vendor_code: u32,
                         device_code: u32) {
    if class_id == 0x01 && subclass_id == 0x01 {
        if let Some(module) = FileScheme::new(pci) {
            session.items.push(module);
        }
    } else if class_id == 0x0C && subclass_id == 0x03 {
        if interface_id == 0x30 {
            let base = pci.read(0x10) as usize;

            let module = box Xhci {
                pci: pci,
                base: base & 0xFFFFFFF0,
                memory_mapped: base & 1 == 0,
                irq: pci.read(0x3C) as u8 & 0xF,
            };
            module.init();
            session.items.push(module);
        } else if interface_id == 0x20 {
            let base = pci.read(0x10) as usize;

            let mut module = box Ehci {
                pci: pci,
                base: base & 0xFFFFFFF0,
                memory_mapped: base & 1 == 0,
                irq: pci.read(0x3C) as u8 & 0xF,
            };
            module.init();
            session.items.push(module);
        } else if interface_id == 0x10 {
            let base = pci.read(0x10) as usize;

            debug!("OHCI Controller on {}\n", base & 0xFFFFFFF0);
        } else if interface_id == 0x00 {
            session.items.push(Uhci::new(pci));
        } else {
            debug!("Unknown USB interface version\n");
        }
    } else {
        match vendor_code {
            0x10EC => match device_code { // REALTEK
                0x8139 => {
                    session.items.push(Rtl8139::new(pci));
                }
                _ => (),
            },
            0x8086 => match device_code { // INTEL
                0x100E => {
                    let base = pci.read(0x10) as usize;
                    let mut module = box Intel8254x {
                        pci: pci,
                        base: base & 0xFFFFFFF0,
                        memory_mapped: base & 1 == 0,
                        irq: pci.read(0x3C) as u8 & 0xF,
                        resources: Vec::new(),
                        inbound: Queue::new(),
                        outbound: Queue::new(),
                    };
                    module.init();
                    session.items.push(module);
                }
                0x2415 => session.items.push(AC97::new(pci)),
                0x24C5 => session.items.push(AC97::new(pci)),
                0x2668 => {
                    let base = pci.read(0x10) as usize;
                    let mut module = box IntelHDA {
                        pci: pci,
                        base: base & 0xFFFFFFF0,
                        memory_mapped: base & 1 == 0,
                        irq: pci.read(0x3C) as u8 & 0xF,
                    };
                    module.init();
                    session.items.push(module);
                }
                _ => (),
            },
            _ => (),
        }
    }
}

/// Initialize PCI session
pub unsafe fn pci_init(session: &mut Session) {
    for bus in 0..256 {
        for slot in 0..32 {
            for func in 0..8 {
                let mut pci = PciConfig::new(bus as u8, slot as u8, func as u8);
                let id = pci.read(0);

                if (id & 0xFFFF) != 0xFFFF {
                    let class_id = pci.read(8);

                    debug!(" * PCI {}, {}, {}: ID {:X} CL {:X}", bus, slot, func, id, class_id);

                    for i in 0..6 {
                        let bar = pci.read(i * 4 + 0x10);
                        if bar > 0 {
                            debug!(" BAR{}: {:X}", i, bar);

                            pci.write(i * 4 + 0x10, 0xFFFFFFFF);
                            let size = (0xFFFFFFFF - (pci.read(i * 4 + 0x10) & 0xFFFFFFF0)) + 1;
                            pci.write(i * 4 + 0x10, bar);

                            if size > 0 {
                                debug!(" {}", size);
                            }
                        }
                    }

                    debug::dl();

                    pci_device(session,
                               pci,
                               (class_id >> 24) & 0xFF,
                               (class_id >> 16) & 0xFF,
                               (class_id >> 8) & 0xFF,
                               id & 0xFFFF,
                               (id >> 16) & 0xFFFF);
                }
            }
        }
    }
}
<|endoftext|>