<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/. */

//! The [`@font-face`][ff] at-rule.
//!
//! [ff]: https://drafts.csswg.org/css-fonts/#at-font-face-rule

#![deny(missing_docs)]

#[cfg(feature = "gecko")] use computed_values::{font_style,  font_weight};
use computed_values::font_family::FamilyName;
use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser, Parser};
use parser::{ParserContext, log_css_error, Parse};
use std::fmt;
use std::iter;
use style_traits::{ToCss, CommaSeparated};
use values::specified::url::SpecifiedUrl;

/// A source for a font-face rule.
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))]
pub enum Source {
    /// A `url()` source.
    Url(UrlSource),
    /// A `local()` source.
    Local(FamilyName),
}

impl ToCss for Source {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result
        where W: fmt::Write,
    {
        match *self {
            Source::Url(ref url) => {
                try!(dest.write_str("url(\""));
                try!(url.to_css(dest));
            },
            Source::Local(ref family) => {
                try!(dest.write_str("local(\""));
                try!(family.to_css(dest));
            },
        }
        dest.write_str("\")")
    }
}

impl CommaSeparated for Source {}

/// A `UrlSource` represents a font-face source that has been specified with a
/// `url()` function.
///
/// https://drafts.csswg.org/css-fonts/#src-desc
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))]
pub struct UrlSource {
    /// The specified url.
    pub url: SpecifiedUrl,
    /// The format hints specified with the `format()` function.
    pub format_hints: Vec<String>,
}

impl ToCss for UrlSource {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result
        where W: fmt::Write,
    {
        dest.write_str(self.url.as_str())
    }
}

/// Parse the block inside a `@font-face` rule.
///
/// Note that the prelude parsing code lives in the `stylesheets` module.
pub fn parse_font_face_block(context: &ParserContext, input: &mut Parser)
                             -> Result<FontFaceRule, ()> {
    let mut rule = FontFaceRule::initial();
    {
        let parser = FontFaceRuleParser {
            context: context,
            rule: &mut rule,
            missing: MissingDescriptors::new(),
        };
        let mut iter = DeclarationListParser::new(input, parser);
        while let Some(declaration) = iter.next() {
            if let Err(range) = declaration {
                let pos = range.start;
                let message = format!("Unsupported @font-face descriptor declaration: '{}'",
                                      iter.input.slice(range));
                log_css_error(iter.input, pos, &*message, context);
            }
        }
        if iter.parser.missing.any() {
            return Err(())
        }
    }
    Ok(rule)
}

/// A list of effective sources that we send over through IPC to the font cache.
#[derive(Clone, Debug)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
pub struct EffectiveSources(Vec<Source>);

impl FontFaceRule {
    /// Returns the list of effective sources for that font-face, that is the
    /// sources which don't list any format hint, or the ones which list at
    /// least "truetype" or "opentype".
    pub fn effective_sources(&self) -> EffectiveSources {
        EffectiveSources(self.sources.iter().rev().filter(|source| {
            if let Source::Url(ref url_source) = **source {
                let hints = &url_source.format_hints;
                // We support only opentype fonts and truetype is an alias for
                // that format. Sources without format hints need to be
                // downloaded in case we support them.
                hints.is_empty() || hints.iter().any(|hint| {
                    hint == "truetype" || hint == "opentype" || hint == "woff"
                })
            } else {
                true
            }
        }).cloned().collect())
    }
}

impl iter::Iterator for EffectiveSources {
    type Item = Source;
    fn next(&mut self) -> Option<Source> {
        self.0.pop()
    }
}

struct FontFaceRuleParser<'a, 'b: 'a> {
    context: &'a ParserContext<'b>,
    rule: &'a mut FontFaceRule,
    missing: MissingDescriptors,
}

/// Default methods reject all at rules.
impl<'a, 'b> AtRuleParser for FontFaceRuleParser<'a, 'b> {
    type Prelude = ();
    type AtRule = ();
}

impl Parse for Vec<Source> {
    fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
        input.parse_comma_separated(|input| Source::parse(context, input))
    }
}

impl Parse for Source {
    fn parse(context: &ParserContext, input: &mut Parser) -> Result<Source, ()> {
        if input.try(|input| input.expect_function_matching("local")).is_ok() {
            return input.parse_nested_block(|input| {
                FamilyName::parse(context, input)
            }).map(Source::Local)
        }

        let url = SpecifiedUrl::parse(context, input)?;

        // Parsing optional format()
        let format_hints = if input.try(|input| input.expect_function_matching("format")).is_ok() {
            input.parse_nested_block(|input| {
                input.parse_comma_separated(|input| {
                    Ok(input.expect_string()?.into_owned())
                })
            })?
        } else {
            vec![]
        };

        Ok(Source::Url(UrlSource {
            url: url,
            format_hints: format_hints,
        }))
    }
}

macro_rules! font_face_descriptors {
    (
        mandatory descriptors = [
            $( #[$m_doc: meta] $m_name: tt $m_ident: ident: $m_ty: ty = $m_initial: expr, )*
        ]
        optional descriptors = [
            $( #[$o_doc: meta] $o_name: tt $o_ident: ident: $o_ty: ty = $o_initial: expr, )*
        ]
    ) => {
        /// A `@font-face` rule.
        ///
        /// https://drafts.csswg.org/css-fonts/#font-face-rule
        #[derive(Debug, PartialEq, Eq)]
        #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
        pub struct FontFaceRule {
            $(
                #[$m_doc]
                pub $m_ident: $m_ty,
            )*
            $(
                #[$o_doc]
                pub $o_ident: $o_ty,
            )*
        }

        struct MissingDescriptors {
            $(
                $m_ident: bool,
            )*
        }

        impl MissingDescriptors {
            fn new() -> Self {
                MissingDescriptors {
                    $(
                        $m_ident: true,
                    )*
                }
            }

            fn any(&self) -> bool {
                $(
                    self.$m_ident
                )||*
            }
        }

        impl FontFaceRule {
            fn initial() -> Self {
                FontFaceRule {
                    $(
                        $m_ident: $m_initial,
                    )*
                    $(
                        $o_ident: $o_initial,
                    )*
                }
            }
        }

        impl ToCss for FontFaceRule {
            // Serialization of FontFaceRule is not specced.
            fn to_css<W>(&self, dest: &mut W) -> fmt::Result
                where W: fmt::Write,
            {
                dest.write_str("@font-face {\n")?;
                $(
                    dest.write_str(concat!("  ", $m_name, ": "))?;
                    self.$m_ident.to_css(dest)?;
                    dest.write_str(";\n")?;
                )*
                $(
                    // Because of parse_font_face_block,
                    // this condition is always true for "src" and "font-family".
                    // But it can be false for other descriptors.
                    if self.$o_ident != $o_initial {
                        dest.write_str(concat!("  ", $o_name, ": "))?;
                        self.$o_ident.to_css(dest)?;
                        dest.write_str(";\n")?;
                    }
                )*
                dest.write_str("}")
            }
        }

       impl<'a, 'b> DeclarationParser for FontFaceRuleParser<'a, 'b> {
            type Declaration = ();

            fn parse_value(&mut self, name: &str, input: &mut Parser) -> Result<(), ()> {
                match_ignore_ascii_case! { name,
                    $(
                        $m_name => {
                            self.rule.$m_ident = Parse::parse(self.context, input)?;
                            self.missing.$m_ident = false
                        },
                    )*
                    $(
                        $o_name => self.rule.$o_ident = Parse::parse(self.context, input)?,
                    )*
                    _ => return Err(())
                }
                Ok(())
            }
        }
    }
}

/// css-name rust_identifier: Type = initial_value,
#[cfg(feature = "gecko")]
font_face_descriptors! {
    mandatory descriptors = [
        /// The specified url.
        "font-family" family: FamilyName = FamilyName(atom!("")),

        /// The format hints specified with the `format()` function.
        "src" sources: Vec<Source> = Vec::new(),
    ]
    optional descriptors = [
        /// The style of this font face
        "font-style" style: font_style::T = font_style::T::normal,

        /// The weight of this font face
        "font-weight" weight: font_weight::T = font_weight::T::Weight400 /* normal */,
    ]
}

#[cfg(feature = "servo")]
font_face_descriptors! {
    mandatory descriptors = [
        /// The specified url.
        "font-family" family: FamilyName = FamilyName(atom!("")),

        /// The format hints specified with the `format()` function.
        "src" sources: Vec<Source> = Vec::new(),
    ]
    optional descriptors = [
    ]
}
<commit_msg>Add font-stretch descriptor to @font-face<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/. */

//! The [`@font-face`][ff] at-rule.
//!
//! [ff]: https://drafts.csswg.org/css-fonts/#at-font-face-rule

#![deny(missing_docs)]

#[cfg(feature = "gecko")] use computed_values::{font_style,  font_weight, font_stretch};
use computed_values::font_family::FamilyName;
use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser, Parser};
use parser::{ParserContext, log_css_error, Parse};
use std::fmt;
use std::iter;
use style_traits::{ToCss, CommaSeparated};
use values::specified::url::SpecifiedUrl;

/// A source for a font-face rule.
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))]
pub enum Source {
    /// A `url()` source.
    Url(UrlSource),
    /// A `local()` source.
    Local(FamilyName),
}

impl ToCss for Source {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result
        where W: fmt::Write,
    {
        match *self {
            Source::Url(ref url) => {
                try!(dest.write_str("url(\""));
                try!(url.to_css(dest));
            },
            Source::Local(ref family) => {
                try!(dest.write_str("local(\""));
                try!(family.to_css(dest));
            },
        }
        dest.write_str("\")")
    }
}

impl CommaSeparated for Source {}

/// A `UrlSource` represents a font-face source that has been specified with a
/// `url()` function.
///
/// https://drafts.csswg.org/css-fonts/#src-desc
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))]
pub struct UrlSource {
    /// The specified url.
    pub url: SpecifiedUrl,
    /// The format hints specified with the `format()` function.
    pub format_hints: Vec<String>,
}

impl ToCss for UrlSource {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result
        where W: fmt::Write,
    {
        dest.write_str(self.url.as_str())
    }
}

/// Parse the block inside a `@font-face` rule.
///
/// Note that the prelude parsing code lives in the `stylesheets` module.
pub fn parse_font_face_block(context: &ParserContext, input: &mut Parser)
                             -> Result<FontFaceRule, ()> {
    let mut rule = FontFaceRule::initial();
    {
        let parser = FontFaceRuleParser {
            context: context,
            rule: &mut rule,
            missing: MissingDescriptors::new(),
        };
        let mut iter = DeclarationListParser::new(input, parser);
        while let Some(declaration) = iter.next() {
            if let Err(range) = declaration {
                let pos = range.start;
                let message = format!("Unsupported @font-face descriptor declaration: '{}'",
                                      iter.input.slice(range));
                log_css_error(iter.input, pos, &*message, context);
            }
        }
        if iter.parser.missing.any() {
            return Err(())
        }
    }
    Ok(rule)
}

/// A list of effective sources that we send over through IPC to the font cache.
#[derive(Clone, Debug)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
pub struct EffectiveSources(Vec<Source>);

impl FontFaceRule {
    /// Returns the list of effective sources for that font-face, that is the
    /// sources which don't list any format hint, or the ones which list at
    /// least "truetype" or "opentype".
    pub fn effective_sources(&self) -> EffectiveSources {
        EffectiveSources(self.sources.iter().rev().filter(|source| {
            if let Source::Url(ref url_source) = **source {
                let hints = &url_source.format_hints;
                // We support only opentype fonts and truetype is an alias for
                // that format. Sources without format hints need to be
                // downloaded in case we support them.
                hints.is_empty() || hints.iter().any(|hint| {
                    hint == "truetype" || hint == "opentype" || hint == "woff"
                })
            } else {
                true
            }
        }).cloned().collect())
    }
}

impl iter::Iterator for EffectiveSources {
    type Item = Source;
    fn next(&mut self) -> Option<Source> {
        self.0.pop()
    }
}

struct FontFaceRuleParser<'a, 'b: 'a> {
    context: &'a ParserContext<'b>,
    rule: &'a mut FontFaceRule,
    missing: MissingDescriptors,
}

/// Default methods reject all at rules.
impl<'a, 'b> AtRuleParser for FontFaceRuleParser<'a, 'b> {
    type Prelude = ();
    type AtRule = ();
}

impl Parse for Vec<Source> {
    fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
        input.parse_comma_separated(|input| Source::parse(context, input))
    }
}

impl Parse for Source {
    fn parse(context: &ParserContext, input: &mut Parser) -> Result<Source, ()> {
        if input.try(|input| input.expect_function_matching("local")).is_ok() {
            return input.parse_nested_block(|input| {
                FamilyName::parse(context, input)
            }).map(Source::Local)
        }

        let url = SpecifiedUrl::parse(context, input)?;

        // Parsing optional format()
        let format_hints = if input.try(|input| input.expect_function_matching("format")).is_ok() {
            input.parse_nested_block(|input| {
                input.parse_comma_separated(|input| {
                    Ok(input.expect_string()?.into_owned())
                })
            })?
        } else {
            vec![]
        };

        Ok(Source::Url(UrlSource {
            url: url,
            format_hints: format_hints,
        }))
    }
}

macro_rules! font_face_descriptors {
    (
        mandatory descriptors = [
            $( #[$m_doc: meta] $m_name: tt $m_ident: ident: $m_ty: ty = $m_initial: expr, )*
        ]
        optional descriptors = [
            $( #[$o_doc: meta] $o_name: tt $o_ident: ident: $o_ty: ty = $o_initial: expr, )*
        ]
    ) => {
        /// A `@font-face` rule.
        ///
        /// https://drafts.csswg.org/css-fonts/#font-face-rule
        #[derive(Debug, PartialEq, Eq)]
        #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
        pub struct FontFaceRule {
            $(
                #[$m_doc]
                pub $m_ident: $m_ty,
            )*
            $(
                #[$o_doc]
                pub $o_ident: $o_ty,
            )*
        }

        struct MissingDescriptors {
            $(
                $m_ident: bool,
            )*
        }

        impl MissingDescriptors {
            fn new() -> Self {
                MissingDescriptors {
                    $(
                        $m_ident: true,
                    )*
                }
            }

            fn any(&self) -> bool {
                $(
                    self.$m_ident
                )||*
            }
        }

        impl FontFaceRule {
            fn initial() -> Self {
                FontFaceRule {
                    $(
                        $m_ident: $m_initial,
                    )*
                    $(
                        $o_ident: $o_initial,
                    )*
                }
            }
        }

        impl ToCss for FontFaceRule {
            // Serialization of FontFaceRule is not specced.
            fn to_css<W>(&self, dest: &mut W) -> fmt::Result
                where W: fmt::Write,
            {
                dest.write_str("@font-face {\n")?;
                $(
                    dest.write_str(concat!("  ", $m_name, ": "))?;
                    self.$m_ident.to_css(dest)?;
                    dest.write_str(";\n")?;
                )*
                $(
                    // Because of parse_font_face_block,
                    // this condition is always true for "src" and "font-family".
                    // But it can be false for other descriptors.
                    if self.$o_ident != $o_initial {
                        dest.write_str(concat!("  ", $o_name, ": "))?;
                        self.$o_ident.to_css(dest)?;
                        dest.write_str(";\n")?;
                    }
                )*
                dest.write_str("}")
            }
        }

       impl<'a, 'b> DeclarationParser for FontFaceRuleParser<'a, 'b> {
            type Declaration = ();

            fn parse_value(&mut self, name: &str, input: &mut Parser) -> Result<(), ()> {
                match_ignore_ascii_case! { name,
                    $(
                        $m_name => {
                            self.rule.$m_ident = Parse::parse(self.context, input)?;
                            self.missing.$m_ident = false
                        },
                    )*
                    $(
                        $o_name => self.rule.$o_ident = Parse::parse(self.context, input)?,
                    )*
                    _ => return Err(())
                }
                Ok(())
            }
        }
    }
}

/// css-name rust_identifier: Type = initial_value,
#[cfg(feature = "gecko")]
font_face_descriptors! {
    mandatory descriptors = [
        /// The specified url.
        "font-family" family: FamilyName = FamilyName(atom!("")),

        /// The format hints specified with the `format()` function.
        "src" sources: Vec<Source> = Vec::new(),
    ]
    optional descriptors = [
        /// The style of this font face
        "font-style" style: font_style::T = font_style::T::normal,

        /// The weight of this font face
        "font-weight" weight: font_weight::T = font_weight::T::Weight400 /* normal */,

        /// The stretch of this font face
        "font-stretch" stretch: font_stretch::T = font_stretch::T::normal,
    ]
}

#[cfg(feature = "servo")]
font_face_descriptors! {
    mandatory descriptors = [
        /// The specified url.
        "font-family" family: FamilyName = FamilyName(atom!("")),

        /// The format hints specified with the `format()` function.
        "src" sources: Vec<Source> = Vec::new(),
    ]
    optional descriptors = [
    ]
}
<|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 cssparser::{AtRuleParser, Parser, QualifiedRuleParser, RuleListParser};
use cssparser::{DeclarationListParser, DeclarationParser, parse_one_rule};
use parking_lot::RwLock;
use parser::{ParserContext, ParserContextExtraData, log_css_error};
use properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock};
use properties::PropertyDeclarationParseResult;
use properties::animated_properties::TransitionProperty;
use std::fmt;
use std::sync::Arc;
use style_traits::ToCss;
use stylesheets::{MemoryHoleReporter, Stylesheet};

/// A number from 1 to 100, indicating the percentage of the animation where
/// this keyframe should run.
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct KeyframePercentage(pub f32);

impl ::std::cmp::Ord for KeyframePercentage {
    #[inline]
    fn cmp(&self, other: &Self) -> ::std::cmp::Ordering {
        // We know we have a number from 0 to 1, so unwrap() here is safe.
        self.0.partial_cmp(&other.0).unwrap()
    }
}

impl ::std::cmp::Eq for KeyframePercentage { }

impl KeyframePercentage {
    #[inline]
    pub fn new(value: f32) -> KeyframePercentage {
        debug_assert!(value >= 0. && value <= 1.);
        KeyframePercentage(value)
    }

    fn parse(input: &mut Parser) -> Result<KeyframePercentage, ()> {
        let percentage = if input.try(|input| input.expect_ident_matching("from")).is_ok() {
            KeyframePercentage::new(0.)
        } else if input.try(|input| input.expect_ident_matching("to")).is_ok() {
            KeyframePercentage::new(1.)
        } else {
            let percentage = try!(input.expect_percentage());
            if percentage > 1. || percentage < 0. {
                return Err(());
            }
            KeyframePercentage::new(percentage)
        };

        Ok(percentage)
    }
}

/// A keyframes selector is a list of percentages or from/to symbols, which are
/// converted at parse time to percentages.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct KeyframeSelector(Vec<KeyframePercentage>);
impl KeyframeSelector {
    #[inline]
    pub fn percentages(&self) -> &[KeyframePercentage] {
        &self.0
    }

    /// A dummy public function so we can write a unit test for this.
    pub fn new_for_unit_testing(percentages: Vec<KeyframePercentage>) -> KeyframeSelector {
        KeyframeSelector(percentages)
    }

    pub fn parse(input: &mut Parser) -> Result<Self, ()> {
        input.parse_comma_separated(KeyframePercentage::parse)
             .map(KeyframeSelector)
    }
}

/// A keyframe.
#[derive(Debug, Clone)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct Keyframe {
    pub selector: KeyframeSelector,

    /// `!important` is not allowed in keyframe declarations,
    /// so the second value of these tuples is always `Importance::Normal`.
    /// But including them enables `compute_style_for_animation_step` to create a `ApplicableDeclarationBlock`
    /// by cloning an `Arc<_>` (incrementing a reference count) rather than re-creating a `Vec<_>`.
    #[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
    pub block: Arc<RwLock<PropertyDeclarationBlock>>,
}

impl ToCss for Keyframe {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        let mut iter = self.selector.percentages().iter();
        try!(write!(dest, "{}%", iter.next().unwrap().0));
        for percentage in iter {
            try!(write!(dest, ", "));
            try!(write!(dest, "{}%", percentage.0));
        }
        try!(dest.write_str(" { "));
        try!(self.block.read().to_css(dest));
        try!(dest.write_str(" }"));
        Ok(())
    }
}

impl Keyframe {
    pub fn parse(css: &str, parent_stylesheet: &Stylesheet, extra_data: ParserContextExtraData)
                 -> Result<Arc<RwLock<Self>>, ()> {
        let error_reporter = Box::new(MemoryHoleReporter);
        let context = ParserContext::new_with_extra_data(parent_stylesheet.origin,
                                                         &parent_stylesheet.base_url,
                                                         error_reporter,
                                                         extra_data);
        let mut input = Parser::new(css);

        let mut rule_parser = KeyframeListParser {
            context: &context,
        };
        parse_one_rule(&mut input, &mut rule_parser)
    }
}

/// A keyframes step value. This can be a synthetised keyframes animation, that
/// is, one autogenerated from the current computed values, or a list of
/// declarations to apply.
// TODO: Find a better name for this?
#[derive(Debug, Clone)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum KeyframesStepValue {
    /// See `Keyframe::declarations`’s docs about the presence of `Importance`.
    Declarations {
        #[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
        block: Arc<RwLock<PropertyDeclarationBlock>>
    },
    ComputedValues,
}

/// A single step from a keyframe animation.
#[derive(Debug, Clone)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct KeyframesStep {
    /// The percentage of the animation duration when this step starts.
    pub start_percentage: KeyframePercentage,
    /// Declarations that will determine the final style during the step, or
    /// `ComputedValues` if this is an autogenerated step.
    pub value: KeyframesStepValue,
    /// Wether a animation-timing-function declaration exists in the list of
    /// declarations.
    ///
    /// This is used to know when to override the keyframe animation style.
    pub declared_timing_function: bool,
}

impl KeyframesStep {
    #[allow(unsafe_code)]
    #[inline]
    fn new(percentage: KeyframePercentage,
           value: KeyframesStepValue) -> Self {
        let declared_timing_function = match value {
            KeyframesStepValue::Declarations { ref block } => {
                block.read().declarations.iter().any(|&(ref prop_decl, _)| {
                    match *prop_decl {
                        PropertyDeclaration::AnimationTimingFunction(..) => true,
                        _ => false,
                    }
                })
            }
            _ => false,
        };

        KeyframesStep {
            start_percentage: percentage,
            value: value,
            declared_timing_function: declared_timing_function,
        }
    }
}

/// This structure represents a list of animation steps computed from the list
/// of keyframes, in order.
///
/// It only takes into account animable properties.
#[derive(Debug, Clone)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct KeyframesAnimation {
    pub steps: Vec<KeyframesStep>,
    /// The properties that change in this animation.
    pub properties_changed: Vec<TransitionProperty>,
}

/// Get all the animated properties in a keyframes animation. Note that it's not
/// defined what happens when a property is not on a keyframe, so we only peek
/// the props of the first one.
///
/// In practice, browsers seem to try to do their best job at it, so we might
/// want to go through all the actual keyframes and deduplicate properties.
#[allow(unsafe_code)]
fn get_animated_properties(keyframe: &Keyframe) -> Vec<TransitionProperty> {
    let mut ret = vec![];
    // NB: declarations are already deduplicated, so we don't have to check for
    // it here.
    for &(ref declaration, _) in keyframe.block.read().declarations.iter() {
        if let Some(property) = TransitionProperty::from_declaration(declaration) {
            ret.push(property);
        }
    }

    ret
}

impl KeyframesAnimation {
    pub fn from_keyframes(keyframes: &[Arc<RwLock<Keyframe>>]) -> Option<Self> {
        if keyframes.is_empty() {
            return None;
        }

        let animated_properties = get_animated_properties(&keyframes[0].read());
        if animated_properties.is_empty() {
            return None;
        }

        let mut steps = vec![];

        for keyframe in keyframes {
            let keyframe = keyframe.read();
            for percentage in keyframe.selector.0.iter() {
                steps.push(KeyframesStep::new(*percentage, KeyframesStepValue::Declarations {
                    block: keyframe.block.clone(),
                }));
            }
        }

        // Sort by the start percentage, so we can easily find a frame.
        steps.sort_by_key(|step| step.start_percentage);

        // Prepend autogenerated keyframes if appropriate.
        if steps[0].start_percentage.0 != 0. {
            steps.insert(0, KeyframesStep::new(KeyframePercentage::new(0.),
                                               KeyframesStepValue::ComputedValues));
        }

        if steps.last().unwrap().start_percentage.0 != 1. {
            steps.push(KeyframesStep::new(KeyframePercentage::new(0.),
                                          KeyframesStepValue::ComputedValues));
        }

        Some(KeyframesAnimation {
            steps: steps,
            properties_changed: animated_properties,
        })
    }
}

/// Parses a keyframes list, like:
/// 0%, 50% {
///     width: 50%;
/// }
///
/// 40%, 60%, 100% {
///     width: 100%;
/// }
struct KeyframeListParser<'a> {
    context: &'a ParserContext<'a>,
}

pub fn parse_keyframe_list(context: &ParserContext, input: &mut Parser) -> Vec<Arc<RwLock<Keyframe>>> {
    RuleListParser::new_for_nested_rule(input, KeyframeListParser { context: context })
        .filter_map(Result::ok)
        .collect()
}

enum Void {}
impl<'a> AtRuleParser for KeyframeListParser<'a> {
    type Prelude = Void;
    type AtRule = Arc<RwLock<Keyframe>>;
}

impl<'a> QualifiedRuleParser for KeyframeListParser<'a> {
    type Prelude = KeyframeSelector;
    type QualifiedRule = Arc<RwLock<Keyframe>>;

    fn parse_prelude(&mut self, input: &mut Parser) -> Result<Self::Prelude, ()> {
        let start = input.position();
        match KeyframeSelector::parse(input) {
            Ok(sel) => Ok(sel),
            Err(()) => {
                let message = format!("Invalid keyframe rule: '{}'", input.slice_from(start));
                log_css_error(input, start, &message, self.context);
                Err(())
            }
        }
    }

    fn parse_block(&mut self, prelude: Self::Prelude, input: &mut Parser)
                   -> Result<Self::QualifiedRule, ()> {
        let mut declarations = Vec::new();
        let parser = KeyframeDeclarationParser {
            context: self.context,
        };
        let mut iter = DeclarationListParser::new(input, parser);
        while let Some(declaration) = iter.next() {
            match declaration {
                Ok(d) => declarations.extend(d.into_iter().map(|d| (d, Importance::Normal))),
                Err(range) => {
                    let pos = range.start;
                    let message = format!("Unsupported keyframe property declaration: '{}'",
                                          iter.input.slice(range));
                    log_css_error(iter.input, pos, &*message, self.context);
                }
            }
            // `parse_important` is not called here, `!important` is not allowed in keyframe blocks.
        }
        Ok(Arc::new(RwLock::new(Keyframe {
            selector: prelude,
            block: Arc::new(RwLock::new(PropertyDeclarationBlock {
                declarations: declarations,
                important_count: 0,
            })),
        })))
    }
}

struct KeyframeDeclarationParser<'a, 'b: 'a> {
    context: &'a ParserContext<'b>,
}

/// Default methods reject all at rules.
impl<'a, 'b> AtRuleParser for KeyframeDeclarationParser<'a, 'b> {
    type Prelude = ();
    type AtRule = Vec<PropertyDeclaration>;
}

impl<'a, 'b> DeclarationParser for KeyframeDeclarationParser<'a, 'b> {
    type Declaration = Vec<PropertyDeclaration>;

    fn parse_value(&mut self, name: &str, input: &mut Parser) -> Result<Vec<PropertyDeclaration>, ()> {
        let mut results = Vec::new();
        match PropertyDeclaration::parse(name, self.context, input, &mut results, true) {
            PropertyDeclarationParseResult::ValidOrIgnoredDeclaration => {}
            _ => return Err(())
        }
        Ok(results)
    }
}
<commit_msg>Fix Keyframe selector serialization<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 cssparser::{AtRuleParser, Parser, QualifiedRuleParser, RuleListParser};
use cssparser::{DeclarationListParser, DeclarationParser, parse_one_rule};
use parking_lot::RwLock;
use parser::{ParserContext, ParserContextExtraData, log_css_error};
use properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock};
use properties::PropertyDeclarationParseResult;
use properties::animated_properties::TransitionProperty;
use std::fmt;
use std::sync::Arc;
use style_traits::ToCss;
use stylesheets::{MemoryHoleReporter, Stylesheet};

/// A number from 0 to 1, indicating the percentage of the animation where
/// this keyframe should run.
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct KeyframePercentage(pub f32);

impl ::std::cmp::Ord for KeyframePercentage {
    #[inline]
    fn cmp(&self, other: &Self) -> ::std::cmp::Ordering {
        // We know we have a number from 0 to 1, so unwrap() here is safe.
        self.0.partial_cmp(&other.0).unwrap()
    }
}

impl ::std::cmp::Eq for KeyframePercentage { }

impl ToCss for KeyframePercentage {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        write!(dest, "{}%", self.0 * 100.0)
    }
}

impl KeyframePercentage {
    #[inline]
    pub fn new(value: f32) -> KeyframePercentage {
        debug_assert!(value >= 0. && value <= 1.);
        KeyframePercentage(value)
    }

    fn parse(input: &mut Parser) -> Result<KeyframePercentage, ()> {
        let percentage = if input.try(|input| input.expect_ident_matching("from")).is_ok() {
            KeyframePercentage::new(0.)
        } else if input.try(|input| input.expect_ident_matching("to")).is_ok() {
            KeyframePercentage::new(1.)
        } else {
            let percentage = try!(input.expect_percentage());
            if percentage > 1. || percentage < 0. {
                return Err(());
            }
            KeyframePercentage::new(percentage)
        };

        Ok(percentage)
    }
}

/// A keyframes selector is a list of percentages or from/to symbols, which are
/// converted at parse time to percentages.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct KeyframeSelector(Vec<KeyframePercentage>);
impl KeyframeSelector {
    #[inline]
    pub fn percentages(&self) -> &[KeyframePercentage] {
        &self.0
    }

    /// A dummy public function so we can write a unit test for this.
    pub fn new_for_unit_testing(percentages: Vec<KeyframePercentage>) -> KeyframeSelector {
        KeyframeSelector(percentages)
    }

    pub fn parse(input: &mut Parser) -> Result<Self, ()> {
        input.parse_comma_separated(KeyframePercentage::parse)
             .map(KeyframeSelector)
    }
}

/// A keyframe.
#[derive(Debug, Clone)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct Keyframe {
    pub selector: KeyframeSelector,

    /// `!important` is not allowed in keyframe declarations,
    /// so the second value of these tuples is always `Importance::Normal`.
    /// But including them enables `compute_style_for_animation_step` to create a `ApplicableDeclarationBlock`
    /// by cloning an `Arc<_>` (incrementing a reference count) rather than re-creating a `Vec<_>`.
    #[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
    pub block: Arc<RwLock<PropertyDeclarationBlock>>,
}

impl ToCss for Keyframe {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        let mut iter = self.selector.percentages().iter();
        try!(iter.next().unwrap().to_css(dest));
        for percentage in iter {
            try!(write!(dest, ", "));
            try!(percentage.to_css(dest));
        }
        try!(dest.write_str(" { "));
        try!(self.block.read().to_css(dest));
        try!(dest.write_str(" }"));
        Ok(())
    }
}

impl Keyframe {
    pub fn parse(css: &str, parent_stylesheet: &Stylesheet, extra_data: ParserContextExtraData)
                 -> Result<Arc<RwLock<Self>>, ()> {
        let error_reporter = Box::new(MemoryHoleReporter);
        let context = ParserContext::new_with_extra_data(parent_stylesheet.origin,
                                                         &parent_stylesheet.base_url,
                                                         error_reporter,
                                                         extra_data);
        let mut input = Parser::new(css);

        let mut rule_parser = KeyframeListParser {
            context: &context,
        };
        parse_one_rule(&mut input, &mut rule_parser)
    }
}

/// A keyframes step value. This can be a synthetised keyframes animation, that
/// is, one autogenerated from the current computed values, or a list of
/// declarations to apply.
// TODO: Find a better name for this?
#[derive(Debug, Clone)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum KeyframesStepValue {
    /// See `Keyframe::declarations`’s docs about the presence of `Importance`.
    Declarations {
        #[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
        block: Arc<RwLock<PropertyDeclarationBlock>>
    },
    ComputedValues,
}

/// A single step from a keyframe animation.
#[derive(Debug, Clone)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct KeyframesStep {
    /// The percentage of the animation duration when this step starts.
    pub start_percentage: KeyframePercentage,
    /// Declarations that will determine the final style during the step, or
    /// `ComputedValues` if this is an autogenerated step.
    pub value: KeyframesStepValue,
    /// Wether a animation-timing-function declaration exists in the list of
    /// declarations.
    ///
    /// This is used to know when to override the keyframe animation style.
    pub declared_timing_function: bool,
}

impl KeyframesStep {
    #[allow(unsafe_code)]
    #[inline]
    fn new(percentage: KeyframePercentage,
           value: KeyframesStepValue) -> Self {
        let declared_timing_function = match value {
            KeyframesStepValue::Declarations { ref block } => {
                block.read().declarations.iter().any(|&(ref prop_decl, _)| {
                    match *prop_decl {
                        PropertyDeclaration::AnimationTimingFunction(..) => true,
                        _ => false,
                    }
                })
            }
            _ => false,
        };

        KeyframesStep {
            start_percentage: percentage,
            value: value,
            declared_timing_function: declared_timing_function,
        }
    }
}

/// This structure represents a list of animation steps computed from the list
/// of keyframes, in order.
///
/// It only takes into account animable properties.
#[derive(Debug, Clone)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct KeyframesAnimation {
    pub steps: Vec<KeyframesStep>,
    /// The properties that change in this animation.
    pub properties_changed: Vec<TransitionProperty>,
}

/// Get all the animated properties in a keyframes animation. Note that it's not
/// defined what happens when a property is not on a keyframe, so we only peek
/// the props of the first one.
///
/// In practice, browsers seem to try to do their best job at it, so we might
/// want to go through all the actual keyframes and deduplicate properties.
#[allow(unsafe_code)]
fn get_animated_properties(keyframe: &Keyframe) -> Vec<TransitionProperty> {
    let mut ret = vec![];
    // NB: declarations are already deduplicated, so we don't have to check for
    // it here.
    for &(ref declaration, _) in keyframe.block.read().declarations.iter() {
        if let Some(property) = TransitionProperty::from_declaration(declaration) {
            ret.push(property);
        }
    }

    ret
}

impl KeyframesAnimation {
    pub fn from_keyframes(keyframes: &[Arc<RwLock<Keyframe>>]) -> Option<Self> {
        if keyframes.is_empty() {
            return None;
        }

        let animated_properties = get_animated_properties(&keyframes[0].read());
        if animated_properties.is_empty() {
            return None;
        }

        let mut steps = vec![];

        for keyframe in keyframes {
            let keyframe = keyframe.read();
            for percentage in keyframe.selector.0.iter() {
                steps.push(KeyframesStep::new(*percentage, KeyframesStepValue::Declarations {
                    block: keyframe.block.clone(),
                }));
            }
        }

        // Sort by the start percentage, so we can easily find a frame.
        steps.sort_by_key(|step| step.start_percentage);

        // Prepend autogenerated keyframes if appropriate.
        if steps[0].start_percentage.0 != 0. {
            steps.insert(0, KeyframesStep::new(KeyframePercentage::new(0.),
                                               KeyframesStepValue::ComputedValues));
        }

        if steps.last().unwrap().start_percentage.0 != 1. {
            steps.push(KeyframesStep::new(KeyframePercentage::new(0.),
                                          KeyframesStepValue::ComputedValues));
        }

        Some(KeyframesAnimation {
            steps: steps,
            properties_changed: animated_properties,
        })
    }
}

/// Parses a keyframes list, like:
/// 0%, 50% {
///     width: 50%;
/// }
///
/// 40%, 60%, 100% {
///     width: 100%;
/// }
struct KeyframeListParser<'a> {
    context: &'a ParserContext<'a>,
}

pub fn parse_keyframe_list(context: &ParserContext, input: &mut Parser) -> Vec<Arc<RwLock<Keyframe>>> {
    RuleListParser::new_for_nested_rule(input, KeyframeListParser { context: context })
        .filter_map(Result::ok)
        .collect()
}

enum Void {}
impl<'a> AtRuleParser for KeyframeListParser<'a> {
    type Prelude = Void;
    type AtRule = Arc<RwLock<Keyframe>>;
}

impl<'a> QualifiedRuleParser for KeyframeListParser<'a> {
    type Prelude = KeyframeSelector;
    type QualifiedRule = Arc<RwLock<Keyframe>>;

    fn parse_prelude(&mut self, input: &mut Parser) -> Result<Self::Prelude, ()> {
        let start = input.position();
        match KeyframeSelector::parse(input) {
            Ok(sel) => Ok(sel),
            Err(()) => {
                let message = format!("Invalid keyframe rule: '{}'", input.slice_from(start));
                log_css_error(input, start, &message, self.context);
                Err(())
            }
        }
    }

    fn parse_block(&mut self, prelude: Self::Prelude, input: &mut Parser)
                   -> Result<Self::QualifiedRule, ()> {
        let mut declarations = Vec::new();
        let parser = KeyframeDeclarationParser {
            context: self.context,
        };
        let mut iter = DeclarationListParser::new(input, parser);
        while let Some(declaration) = iter.next() {
            match declaration {
                Ok(d) => declarations.extend(d.into_iter().map(|d| (d, Importance::Normal))),
                Err(range) => {
                    let pos = range.start;
                    let message = format!("Unsupported keyframe property declaration: '{}'",
                                          iter.input.slice(range));
                    log_css_error(iter.input, pos, &*message, self.context);
                }
            }
            // `parse_important` is not called here, `!important` is not allowed in keyframe blocks.
        }
        Ok(Arc::new(RwLock::new(Keyframe {
            selector: prelude,
            block: Arc::new(RwLock::new(PropertyDeclarationBlock {
                declarations: declarations,
                important_count: 0,
            })),
        })))
    }
}

struct KeyframeDeclarationParser<'a, 'b: 'a> {
    context: &'a ParserContext<'b>,
}

/// Default methods reject all at rules.
impl<'a, 'b> AtRuleParser for KeyframeDeclarationParser<'a, 'b> {
    type Prelude = ();
    type AtRule = Vec<PropertyDeclaration>;
}

impl<'a, 'b> DeclarationParser for KeyframeDeclarationParser<'a, 'b> {
    type Declaration = Vec<PropertyDeclaration>;

    fn parse_value(&mut self, name: &str, input: &mut Parser) -> Result<Vec<PropertyDeclaration>, ()> {
        let mut results = Vec::new();
        match PropertyDeclaration::parse(name, self.context, input, &mut results, true) {
            PropertyDeclarationParseResult::ValidOrIgnoredDeclaration => {}
            _ => return Err(())
        }
        Ok(results)
    }
}
<|endoftext|>


<commit_before>//! # Page table entry
//! Some code borrowed from [Phil Opp's Blog](http://os.phil-opp.com/modifying-page-tables.html)

use memory::Frame;

use super::PhysicalAddress;

/// A page table entry
pub struct Entry(u64);

bitflags! {
    pub struct EntryFlags: u64 {
        const PRESENT =         1 << 0;
        const WRITABLE =        1 << 1;
        const USER_ACCESSIBLE = 1 << 2;
        const WRITE_THROUGH =   1 << 3;
        const NO_CACHE =        1 << 4;
        const ACCESSED =        1 << 5;
        const DIRTY =           1 << 6;
        const HUGE_PAGE =       1 << 7;
        const GLOBAL =          1 << 8;
        const NO_EXECUTE =      1 << 63;
    }
}

pub const ADDRESS_MASK: usize = 0x000f_ffff_ffff_f000;
pub const COUNTER_MASK: u64 = 0x3ff00000_00000000;

impl Entry {
    /// Is the entry unused?
    pub fn is_unused(&self) -> bool {
        self.0 == 0
    }

    /// Make the entry unused
    pub fn set_unused(&mut self) {
        self.0 = 0;
    }

    /// Get the address this page references
    pub fn address(&self) -> PhysicalAddress {
        PhysicalAddress::new(self.0 as usize & ADDRESS_MASK)
    }

    /// Get the current entry flags
    pub fn flags(&self) -> EntryFlags {
        EntryFlags::from_bits_truncate(self.0)
    }

    /// Get the associated frame, if available
    pub fn pointed_frame(&self) -> Option<Frame> {
        if self.flags().contains(EntryFlags::PRESENT) {
            Some(Frame::containing_address(self.address()))
        } else {
            None
        }
    }

    pub fn set(&mut self, frame: Frame, flags: EntryFlags) {
        debug_assert!(frame.start_address().get() & !ADDRESS_MASK == 0);
        self.0 = (frame.start_address().get() as u64) | flags.bits() | (self.0 & COUNTER_MASK);
    }

    /// Get bits 52-61 in entry, used as counter for page table
    pub fn counter_bits(&self) -> u64 {
        (self.0 & COUNTER_MASK) >> 52
    }

    /// Set bits 52-61 in entry, used as counter for page table
    pub fn set_counter_bits(&mut self, count: u64) {
        self.0 = (self.0 & !COUNTER_MASK) | (count << 52);
    }
}
<commit_msg>don't change counter in set_unused<commit_after>//! # Page table entry
//! Some code borrowed from [Phil Opp's Blog](http://os.phil-opp.com/modifying-page-tables.html)

use memory::Frame;

use super::PhysicalAddress;

/// A page table entry
pub struct Entry(u64);

bitflags! {
    pub struct EntryFlags: u64 {
        const PRESENT =         1 << 0;
        const WRITABLE =        1 << 1;
        const USER_ACCESSIBLE = 1 << 2;
        const WRITE_THROUGH =   1 << 3;
        const NO_CACHE =        1 << 4;
        const ACCESSED =        1 << 5;
        const DIRTY =           1 << 6;
        const HUGE_PAGE =       1 << 7;
        const GLOBAL =          1 << 8;
        const NO_EXECUTE =      1 << 63;
    }
}

pub const ADDRESS_MASK: usize = 0x000f_ffff_ffff_f000;
pub const COUNTER_MASK: u64 = 0x3ff00000_00000000;

impl Entry {
    /// Is the entry unused?
    pub fn is_unused(&self) -> bool {
        self.0 == (self.0 & COUNTER_MASK)
    }

    /// Make the entry unused
    pub fn set_unused(&mut self) {
        self.0 = self.0 & COUNTER_MASK;
    }

    /// Get the address this page references
    pub fn address(&self) -> PhysicalAddress {
        PhysicalAddress::new(self.0 as usize & ADDRESS_MASK)
    }

    /// Get the current entry flags
    pub fn flags(&self) -> EntryFlags {
        EntryFlags::from_bits_truncate(self.0)
    }

    /// Get the associated frame, if available
    pub fn pointed_frame(&self) -> Option<Frame> {
        if self.flags().contains(EntryFlags::PRESENT) {
            Some(Frame::containing_address(self.address()))
        } else {
            None
        }
    }

    pub fn set(&mut self, frame: Frame, flags: EntryFlags) {
        debug_assert!(frame.start_address().get() & !ADDRESS_MASK == 0);
        self.0 = (frame.start_address().get() as u64) | flags.bits() | (self.0 & COUNTER_MASK);
    }

    /// Get bits 52-61 in entry, used as counter for page table
    pub fn counter_bits(&self) -> u64 {
        (self.0 & COUNTER_MASK) >> 52
    }

    /// Set bits 52-61 in entry, used as counter for page table
    pub fn set_counter_bits(&mut self, count: u64) {
        self.0 = (self.0 & !COUNTER_MASK) | (count << 52);
    }
}
<|endoftext|>


<commit_before>use std::path::Path;
use syntect::easy::HighlightLines;
use syntect::highlighting::ThemeSet;
use syntect::html::{
    append_highlighted_html_for_styled_line, start_highlighted_html_snippet, IncludeBackground,
};
use syntect::parsing::{SyntaxReference, SyntaxSet};
use syntect::util::LinesWithEndings;

#[derive(Debug)]
#[non_exhaustive]
pub struct Syntax {
    syntax_set: SyntaxSet,
    theme_set: ThemeSet,
    default_theme: Option<String>,
}

impl Syntax {
    pub fn new() -> Self {
        Self {
            syntax_set: SyntaxSet::load_defaults_newlines(),
            theme_set: ThemeSet::load_defaults(),
            default_theme: None,
        }
    }

    pub fn load_custom_syntaxes(&mut self, syntaxes_path: &Path) {
        let mut builder = self.syntax_set.clone().into_builder();
        builder.add_from_folder(syntaxes_path, true).unwrap();
        self.syntax_set = builder.build();
    }

    pub fn has_theme(&self, name: &str) -> bool {
        self.theme_set.themes.contains_key(name)
    }

    pub fn themes(&self) -> impl Iterator<Item = String> + '_ {
        self.theme_set.themes.keys().cloned()
    }

    pub fn syntaxes(&self) -> impl Iterator<Item = String> + '_ {
        fn reference_to_string(sd: &SyntaxReference) -> String {
            let extensions = sd.file_extensions.join(", ");
            format!("{} [{}]", sd.name, extensions)
        }

        let mut syntaxes = self
            .syntax_set
            .syntaxes()
            .iter()
            .map(reference_to_string)
            .collect::<Vec<_>>();

        // sort alphabetically with insensitive ascii case
        syntaxes.sort_by_key(|a| a.to_ascii_lowercase());

        syntaxes.into_iter()
    }

    pub fn default_theme(&self) -> Option<&str> {
        self.default_theme.as_deref()
    }

    pub fn set_default_theme(&mut self, theme: impl Into<String>) {
        self.default_theme = Some(theme.into());
    }

    pub fn format(&self, code: &str, lang: Option<&str>, theme: Option<&str>) -> String {
        if let Some(theme) = theme.or_else(|| self.default_theme()) {
            let theme = &self.theme_set.themes[theme];

            let syntax = lang
                .and_then(|l| self.syntax_set.find_syntax_by_token(l))
                .unwrap_or_else(|| self.syntax_set.find_syntax_plain_text());

            // Essentially the same as `syntect::html::highlighted_html_for_string`,
            // but adding  tags between the
 tags
            // See: https://docs.rs/syntect/5.0.0/src/syntect/html.rs.html#269
            let mut highlighter = HighlightLines::new(syntax, theme);
            let (mut output, bg) = start_highlighted_html_snippet(theme);
            output.push_str("");

            for line in LinesWithEndings::from(code) {
                let regions = highlighter.highlight_line(line, &self.syntax_set).unwrap();
                append_highlighted_html_for_styled_line(
                    &regions[..],
                    IncludeBackground::IfDifferent(bg),
                    &mut output,
                )
                .unwrap();
            }
            output.push_str("
\n");
            output
        } else {
            crate::Raw::new().format(code, lang, theme)
        }
    }
}

impl Default for Syntax {
    fn default() -> Self {
        Self::new()
    }
}

#[cfg(test)]
mod test {
    use super::*;

    const CODEBLOCK: &str = "mod test {
        fn hello(arg: int) -> bool {
            \
                                      true
        }
    }
    ";

    const CODEBLOCK_RENDERED: &str =
        "
\n\
         mod \
         test {\n\
                 \
         fn \
         hello(\
         arg: int) -> \
         bool {\n\
                     \
         true\n\
                 }\n\
             }\n\

\n";

    #[test]
    fn highlight_block_renders_rust() {
        let syntax = Syntax::new();
        let output = syntax.format(CODEBLOCK, Some("rust"), Some("base16-ocean.dark"));
        assert_eq!(output, CODEBLOCK_RENDERED.to_string());
    }

    const CUSTOM_CODEBLOCK: &str = "[[[]]]]";

    const CUSTOM_CODEBLOCK_RENDERED: &str = "
\n\
          [[[]]]\
          ]\

\n";

    #[test]
    fn highlight_custom_syntax() {
        let mut syntax = Syntax::new();
        let path = Path::new("./tests/fixtures/custom_syntaxes/");
        syntax.load_custom_syntaxes(path);
        let output = syntax.format(
            CUSTOM_CODEBLOCK,
            Some("brackets"),
            Some("base16-ocean.dark"),
        );
        assert_eq!(output, CUSTOM_CODEBLOCK_RENDERED);
    }
}
<commit_msg>fix: update syntax highlighting tests<commit_after>use std::path::Path;
use syntect::easy::HighlightLines;
use syntect::highlighting::ThemeSet;
use syntect::html::{
    append_highlighted_html_for_styled_line, start_highlighted_html_snippet, IncludeBackground,
};
use syntect::parsing::{SyntaxReference, SyntaxSet};
use syntect::util::LinesWithEndings;

#[derive(Debug)]
#[non_exhaustive]
pub struct Syntax {
    syntax_set: SyntaxSet,
    theme_set: ThemeSet,
    default_theme: Option<String>,
}

impl Syntax {
    pub fn new() -> Self {
        Self {
            syntax_set: SyntaxSet::load_defaults_newlines(),
            theme_set: ThemeSet::load_defaults(),
            default_theme: None,
        }
    }

    pub fn load_custom_syntaxes(&mut self, syntaxes_path: &Path) {
        let mut builder = self.syntax_set.clone().into_builder();
        builder.add_from_folder(syntaxes_path, true).unwrap();
        self.syntax_set = builder.build();
    }

    pub fn has_theme(&self, name: &str) -> bool {
        self.theme_set.themes.contains_key(name)
    }

    pub fn themes(&self) -> impl Iterator<Item = String> + '_ {
        self.theme_set.themes.keys().cloned()
    }

    pub fn syntaxes(&self) -> impl Iterator<Item = String> + '_ {
        fn reference_to_string(sd: &SyntaxReference) -> String {
            let extensions = sd.file_extensions.join(", ");
            format!("{} [{}]", sd.name, extensions)
        }

        let mut syntaxes = self
            .syntax_set
            .syntaxes()
            .iter()
            .map(reference_to_string)
            .collect::<Vec<_>>();

        // sort alphabetically with insensitive ascii case
        syntaxes.sort_by_key(|a| a.to_ascii_lowercase());

        syntaxes.into_iter()
    }

    pub fn default_theme(&self) -> Option<&str> {
        self.default_theme.as_deref()
    }

    pub fn set_default_theme(&mut self, theme: impl Into<String>) {
        self.default_theme = Some(theme.into());
    }

    pub fn format(&self, code: &str, lang: Option<&str>, theme: Option<&str>) -> String {
        if let Some(theme) = theme.or_else(|| self.default_theme()) {
            let theme = &self.theme_set.themes[theme];

            let syntax = lang
                .and_then(|l| self.syntax_set.find_syntax_by_token(l))
                .unwrap_or_else(|| self.syntax_set.find_syntax_plain_text());

            // Essentially the same as `syntect::html::highlighted_html_for_string`,
            // but adding  tags between the
 tags
            // See: https://docs.rs/syntect/5.0.0/src/syntect/html.rs.html#269
            let mut highlighter = HighlightLines::new(syntax, theme);
            let (mut output, bg) = start_highlighted_html_snippet(theme);
            output.push_str("");

            for line in LinesWithEndings::from(code) {
                let regions = highlighter.highlight_line(line, &self.syntax_set).unwrap();
                append_highlighted_html_for_styled_line(
                    &regions[..],
                    IncludeBackground::IfDifferent(bg),
                    &mut output,
                )
                .unwrap();
            }
            output.push_str("
\n");
            output
        } else {
            crate::Raw::new().format(code, lang, theme)
        }
    }
}

impl Default for Syntax {
    fn default() -> Self {
        Self::new()
    }
}

#[cfg(test)]
mod test {
    use super::*;

    const CODEBLOCK: &str = "mod test {
        fn hello(arg: int) -> bool {
            \
                                      true
        }
    }
    ";

    const CODEBLOCK_RENDERED: &str =
        "
\n\
         mod \
         test {\n\
                 \
         fn \
         hello(\
         arg: int) -> \
         bool {\n\
                     \
         true\n\
                 }\n\
             }\n\

\n";

    #[test]
    fn highlight_block_renders_rust() {
        let syntax = Syntax::new();
        let output = syntax.format(CODEBLOCK, Some("rust"), Some("base16-ocean.dark"));
        assert_eq!(output, CODEBLOCK_RENDERED.to_string());
    }

    const CUSTOM_CODEBLOCK: &str = "[[[]]]]";

    const CUSTOM_CODEBLOCK_RENDERED: &str = "
\n\
          [[[]]]\
          ]\

\n";

    #[test]
    fn highlight_custom_syntax() {
        let mut syntax = Syntax::new();
        let path = Path::new("./tests/fixtures/custom_syntaxes/");
        syntax.load_custom_syntaxes(path);
        let output = syntax.format(
            CUSTOM_CODEBLOCK,
            Some("brackets"),
            Some("base16-ocean.dark"),
        );
        assert_eq!(output, CUSTOM_CODEBLOCK_RENDERED);
    }
}
<|endoftext|>


<commit_before>use cairo;
use cairo::{MatrixTrait, Pattern};
use cairo_sys;
use glib;
use glib::translate::*;
use glib_sys;
use libc;
use std::cell::{Cell, RefCell};
use std::ptr;

use aspect_ratio::AspectRatio;
use attributes::Attribute;
use bbox::BoundingBox;
use drawing_ctx::DrawingCtx;
use handle::RsvgHandle;
use length::*;
use node::*;
use parsers::{parse, parse_and_validate};
use property_bag::PropertyBag;

pub struct NodeImage {
    aspect: Cell<AspectRatio>,
    x: Cell<RsvgLength>,
    y: Cell<RsvgLength>,
    w: Cell<RsvgLength>,
    h: Cell<RsvgLength>,
    surface: RefCell<Option<cairo::ImageSurface>>,
}

impl NodeImage {
    pub fn new() -> NodeImage {
        NodeImage {
            aspect: Cell::new(AspectRatio::default()),
            x: Cell::new(RsvgLength::default()),
            y: Cell::new(RsvgLength::default()),
            w: Cell::new(RsvgLength::default()),
            h: Cell::new(RsvgLength::default()),
            surface: RefCell::new(None),
        }
    }
}

impl NodeTrait for NodeImage {
    fn set_atts(
        &self,
        node: &RsvgNode,
        handle: *const RsvgHandle,
        pbag: &PropertyBag,
    ) -> NodeResult {
        // SVG element has overflow:hidden
        // https://www.w3.org/TR/SVG/styling.html#UAStyleSheet
        node.set_overflow_hidden();

        for (_key, attr, value) in pbag.iter() {
            match attr {
                Attribute::X => self.x.set(parse("x", value, LengthDir::Horizontal)?),
                Attribute::Y => self.y.set(parse("y", value, LengthDir::Vertical)?),
                Attribute::Width => self.w.set(parse_and_validate(
                    "width",
                    value,
                    LengthDir::Horizontal,
                    RsvgLength::check_nonnegative,
                )?),
                Attribute::Height => self.h.set(parse_and_validate(
                    "height",
                    value,
                    LengthDir::Vertical,
                    RsvgLength::check_nonnegative,
                )?),

                Attribute::PreserveAspectRatio => {
                    self.aspect.set(parse("preserveAspectRatio", value, ())?)
                }

                Attribute::XlinkHref | Attribute::Path => {
                    // "path" is used by some older Adobe Illustrator versions

                    extern "C" {
                        fn rsvg_cairo_surface_new_from_href(
                            handle: *const RsvgHandle,
                            href: *const libc::c_char,
                            error: *mut *mut glib_sys::GError,
                        ) -> *mut cairo_sys::cairo_surface_t;
                    }

                    let mut error = ptr::null_mut();

                    let raw_surface = unsafe {
                        rsvg_cairo_surface_new_from_href(handle, value.to_glib_none().0, &mut error)
                    };
                    if !raw_surface.is_null() {
                        *self.surface.borrow_mut() = Some(unsafe {
                            cairo::ImageSurface::from_raw_full(raw_surface).unwrap()
                        });
                    } else {
                        let _: glib::Error = unsafe { from_glib_full(error) }; // FIXME: we should note that the image couldn't be loaded
                    }
                }

                _ => (),
            }
        }

        Ok(())
    }

    fn draw(
        &self,
        node: &RsvgNode,
        cascaded: &CascadedValues,
        draw_ctx: &mut DrawingCtx,
        clipping: bool,
    ) {
        let values = cascaded.get();

        if let Some(ref surface) = *self.surface.borrow() {
            let x = self.x.get().normalize(values, draw_ctx);
            let y = self.y.get().normalize(values, draw_ctx);
            let w = self.w.get().normalize(values, draw_ctx);
            let h = self.h.get().normalize(values, draw_ctx);

            draw_ctx.with_discrete_layer(node, values, clipping, &mut |dc| {
                let aspect = self.aspect.get();

                if !values.is_overflow() && aspect.is_slice() {
                    dc.clip(x, y, w, h);
                }

                let width = surface.get_width();
                let height = surface.get_height();
                if clipping || width == 0 || height == 0 {
                    return;
                }

                let width = f64::from(width);
                let height = f64::from(height);

                let (x, y, w, h) = aspect.compute(width, height, x, y, w, h);

                let cr = dc.get_cairo_context();
                let affine = cr.get_matrix();

                // This is the target bbox after drawing.
                let bbox = BoundingBox::new(&affine).with_rect(Some(cairo::Rectangle {
                    x,
                    y,
                    width: w,
                    height: h,
                }));

                cr.save();

                dc.set_affine_on_cr(&cr);
                cr.scale(w / width, h / height);
                let x = x * width / w;
                let y = y * height / h;

                cr.set_operator(cairo::Operator::from(values.comp_op));

                // We need to set extend appropriately, so can't use cr.set_source_surface().
                //
                // If extend is left at its default value (None), then bilinear scaling uses
                // transparency outside of the image producing incorrect results.
                // For example, in svg1.1/filters-blend-01-b.svgthere's a completely
                // opaque 100×1 image of a gradient scaled to 100×98 which ends up
                // transparent almost everywhere without this fix (which it shouldn't).
                let ptn = cairo::SurfacePattern::create(&surface);
                let mut matrix = cairo::Matrix::identity();
                matrix.translate(-x, -y);
                ptn.set_matrix(matrix);
                ptn.set_extend(cairo::Extend::Pad);
                cr.set_source(&ptn);

                // Clip is needed due to extend being set to pad.
                cr.rectangle(x, y, width, height);
                cr.clip();

                cr.paint();

                cr.restore();

                dc.insert_bbox(&bbox);
            });
        }
    }
}
<commit_msg>Fix <image> bbox once again<commit_after>use cairo;
use cairo::{MatrixTrait, Pattern};
use cairo_sys;
use glib;
use glib::translate::*;
use glib_sys;
use libc;
use std::cell::{Cell, RefCell};
use std::ptr;

use aspect_ratio::AspectRatio;
use attributes::Attribute;
use bbox::BoundingBox;
use drawing_ctx::DrawingCtx;
use handle::RsvgHandle;
use length::*;
use node::*;
use parsers::{parse, parse_and_validate};
use property_bag::PropertyBag;

pub struct NodeImage {
    aspect: Cell<AspectRatio>,
    x: Cell<RsvgLength>,
    y: Cell<RsvgLength>,
    w: Cell<RsvgLength>,
    h: Cell<RsvgLength>,
    surface: RefCell<Option<cairo::ImageSurface>>,
}

impl NodeImage {
    pub fn new() -> NodeImage {
        NodeImage {
            aspect: Cell::new(AspectRatio::default()),
            x: Cell::new(RsvgLength::default()),
            y: Cell::new(RsvgLength::default()),
            w: Cell::new(RsvgLength::default()),
            h: Cell::new(RsvgLength::default()),
            surface: RefCell::new(None),
        }
    }
}

impl NodeTrait for NodeImage {
    fn set_atts(
        &self,
        node: &RsvgNode,
        handle: *const RsvgHandle,
        pbag: &PropertyBag,
    ) -> NodeResult {
        // SVG element has overflow:hidden
        // https://www.w3.org/TR/SVG/styling.html#UAStyleSheet
        node.set_overflow_hidden();

        for (_key, attr, value) in pbag.iter() {
            match attr {
                Attribute::X => self.x.set(parse("x", value, LengthDir::Horizontal)?),
                Attribute::Y => self.y.set(parse("y", value, LengthDir::Vertical)?),
                Attribute::Width => self.w.set(parse_and_validate(
                    "width",
                    value,
                    LengthDir::Horizontal,
                    RsvgLength::check_nonnegative,
                )?),
                Attribute::Height => self.h.set(parse_and_validate(
                    "height",
                    value,
                    LengthDir::Vertical,
                    RsvgLength::check_nonnegative,
                )?),

                Attribute::PreserveAspectRatio => {
                    self.aspect.set(parse("preserveAspectRatio", value, ())?)
                }

                Attribute::XlinkHref | Attribute::Path => {
                    // "path" is used by some older Adobe Illustrator versions

                    extern "C" {
                        fn rsvg_cairo_surface_new_from_href(
                            handle: *const RsvgHandle,
                            href: *const libc::c_char,
                            error: *mut *mut glib_sys::GError,
                        ) -> *mut cairo_sys::cairo_surface_t;
                    }

                    let mut error = ptr::null_mut();

                    let raw_surface = unsafe {
                        rsvg_cairo_surface_new_from_href(handle, value.to_glib_none().0, &mut error)
                    };
                    if !raw_surface.is_null() {
                        *self.surface.borrow_mut() = Some(unsafe {
                            cairo::ImageSurface::from_raw_full(raw_surface).unwrap()
                        });
                    } else {
                        let _: glib::Error = unsafe { from_glib_full(error) }; // FIXME: we should note that the image couldn't be loaded
                    }
                }

                _ => (),
            }
        }

        Ok(())
    }

    fn draw(
        &self,
        node: &RsvgNode,
        cascaded: &CascadedValues,
        draw_ctx: &mut DrawingCtx,
        clipping: bool,
    ) {
        let values = cascaded.get();

        if let Some(ref surface) = *self.surface.borrow() {
            let x = self.x.get().normalize(values, draw_ctx);
            let y = self.y.get().normalize(values, draw_ctx);
            let w = self.w.get().normalize(values, draw_ctx);
            let h = self.h.get().normalize(values, draw_ctx);

            draw_ctx.with_discrete_layer(node, values, clipping, &mut |dc| {
                let aspect = self.aspect.get();

                if !values.is_overflow() && aspect.is_slice() {
                    dc.clip(x, y, w, h);
                }

                // The bounding box for <image> is decided by the values of x, y, w, h and not by
                // the final computed image bounds.
                let bbox = BoundingBox::new(&dc.get_cairo_context().get_matrix()).with_rect(Some(
                    cairo::Rectangle {
                        x,
                        y,
                        width: w,
                        height: h,
                    },
                ));

                let width = surface.get_width();
                let height = surface.get_height();
                if clipping || width == 0 || height == 0 {
                    return;
                }

                let width = f64::from(width);
                let height = f64::from(height);

                let (x, y, w, h) = aspect.compute(width, height, x, y, w, h);

                let cr = dc.get_cairo_context();
                let affine = cr.get_matrix();

                cr.save();

                dc.set_affine_on_cr(&cr);
                cr.scale(w / width, h / height);
                let x = x * width / w;
                let y = y * height / h;

                cr.set_operator(cairo::Operator::from(values.comp_op));

                // We need to set extend appropriately, so can't use cr.set_source_surface().
                //
                // If extend is left at its default value (None), then bilinear scaling uses
                // transparency outside of the image producing incorrect results.
                // For example, in svg1.1/filters-blend-01-b.svgthere's a completely
                // opaque 100×1 image of a gradient scaled to 100×98 which ends up
                // transparent almost everywhere without this fix (which it shouldn't).
                let ptn = cairo::SurfacePattern::create(&surface);
                let mut matrix = cairo::Matrix::identity();
                matrix.translate(-x, -y);
                ptn.set_matrix(matrix);
                ptn.set_extend(cairo::Extend::Pad);
                cr.set_source(&ptn);

                // Clip is needed due to extend being set to pad.
                cr.rectangle(x, y, width, height);
                cr.clip();

                cr.paint();

                cr.restore();

                dc.insert_bbox(&bbox);
            });
        }
    }
}
<|endoftext|>


<commit_before>// SPDX-License-Identifier: MIT
// Copyright (C) 2018-present iced project and contributors

use crate::block_enc::instr::*;
use crate::block_enc::*;
use crate::iced_error::IcedError;
use core::cell::RefCell;
use core::cmp;

pub(super) struct CallInstr {
	bitness: u32,
	instruction: Instruction,
	target_instr: TargetInstr,
	orig_instruction_size: u32,
	pointer_data: Option<Rc<RefCell<BlockData>>>,
	use_orig_instruction: bool,
	done: bool,
}

impl CallInstr {
	pub(super) fn new(block_encoder: &mut BlockEncInt, base: &mut InstrBase, instruction: &Instruction) -> Self {
		let mut instr_copy = *instruction;
		instr_copy.set_near_branch64(0);
		let orig_instruction_size = block_encoder.get_instruction_size(&instr_copy, 0);
		let mut done = false;
		let mut use_orig_instruction = false;
		base.size = if !block_encoder.fix_branches() {
			use_orig_instruction = true;
			done = true;
			orig_instruction_size
		} else if block_encoder.bitness() == 64 {
			// Make sure it's not shorter than the real instruction. It can happen if there are extra prefixes.
			cmp::max(orig_instruction_size, InstrUtils::CALL_OR_JMP_POINTER_DATA_INSTRUCTION_SIZE64)
		} else {
			orig_instruction_size
		};
		Self {
			bitness: block_encoder.bitness(),
			instruction: *instruction,
			target_instr: TargetInstr::default(),
			orig_instruction_size,
			pointer_data: None,
			use_orig_instruction,
			done,
		}
	}

	fn try_optimize<'a>(&mut self, base: &mut InstrBase, ctx: &mut InstrContext<'a>, gained: u64) -> bool {
		if self.done {
			base.done = true;
			return false;
		}

		// If it's in the same block, we assume the target is at most 2GB away.
		let mut use_short = self.bitness != 64 || self.target_instr.is_in_block(ctx.block);
		if !use_short {
			let target_address = self.target_instr.address(ctx);
			let next_rip = ctx.ip.wrapping_add(self.orig_instruction_size as u64);
			let diff = target_address.wrapping_sub(next_rip) as i64;
			let diff = correct_diff(self.target_instr.is_in_block(ctx.block), diff, gained);
			use_short = i32::MIN as i64 <= diff && diff <= i32::MAX as i64;
		}

		if use_short {
			if let Some(ref pointer_data) = self.pointer_data {
				pointer_data.borrow_mut().is_valid = false;
			}
			base.size = self.orig_instruction_size;
			self.use_orig_instruction = true;
			self.done = true;
			base.done = true;
			return true;
		}

		if self.pointer_data.is_none() {
			self.pointer_data = Some(ctx.block.alloc_pointer_location());
		}
		false
	}
}

impl Instr for CallInstr {
	fn initialize<'a>(&mut self, base: &mut InstrBase, block_encoder: &BlockEncInt, ctx: &mut InstrContext<'a>) {
		self.target_instr = block_encoder.get_target(base, self.instruction.near_branch_target());
		let _ = self.try_optimize(base, ctx, 0);
	}

	fn optimize<'a>(&mut self, base: &mut InstrBase, ctx: &mut InstrContext<'a>, gained: u64) -> bool {
		self.try_optimize(base, ctx, gained)
	}

	fn encode<'a>(&mut self, base: &mut InstrBase, ctx: &mut InstrContext<'a>) -> Result<(ConstantOffsets, bool), IcedError> {
		if self.use_orig_instruction {
			self.instruction.set_near_branch64(self.target_instr.address(ctx));
			ctx.block.encoder.encode(&self.instruction, ctx.ip).map_or_else(
				|err| Err(IcedError::with_string(InstrUtils::create_error_message(&err, &self.instruction))),
				|_| Ok((ctx.block.encoder.get_constant_offsets(), true)),
			)
		} else {
			debug_assert!(self.pointer_data.is_some());
			let pointer_data = self.pointer_data.clone().ok_or_else(|| IcedError::new("Internal error"))?;
			pointer_data.borrow_mut().data = self.target_instr.address(ctx);
			InstrUtils::encode_branch_to_pointer_data(ctx.block, true, ctx.ip, pointer_data, base.size).map_or_else(
				|err| Err(IcedError::with_string(InstrUtils::create_error_message(&err, &self.instruction))),
				|_| Ok((ConstantOffsets::default(), false)),
			)
		}
	}
}
<commit_msg>Remove unused field<commit_after>// SPDX-License-Identifier: MIT
// Copyright (C) 2018-present iced project and contributors

use crate::block_enc::instr::*;
use crate::block_enc::*;
use crate::iced_error::IcedError;
use core::cell::RefCell;
use core::cmp;

pub(super) struct CallInstr {
	bitness: u32,
	instruction: Instruction,
	target_instr: TargetInstr,
	orig_instruction_size: u32,
	pointer_data: Option<Rc<RefCell<BlockData>>>,
	use_orig_instruction: bool,
}

impl CallInstr {
	pub(super) fn new(block_encoder: &mut BlockEncInt, base: &mut InstrBase, instruction: &Instruction) -> Self {
		let mut instr_copy = *instruction;
		instr_copy.set_near_branch64(0);
		let orig_instruction_size = block_encoder.get_instruction_size(&instr_copy, 0);
		let mut use_orig_instruction = false;
		base.size = if !block_encoder.fix_branches() {
			use_orig_instruction = true;
			base.done = true;
			orig_instruction_size
		} else if block_encoder.bitness() == 64 {
			// Make sure it's not shorter than the real instruction. It can happen if there are extra prefixes.
			cmp::max(orig_instruction_size, InstrUtils::CALL_OR_JMP_POINTER_DATA_INSTRUCTION_SIZE64)
		} else {
			orig_instruction_size
		};
		Self {
			bitness: block_encoder.bitness(),
			instruction: *instruction,
			target_instr: TargetInstr::default(),
			orig_instruction_size,
			pointer_data: None,
			use_orig_instruction,
		}
	}

	fn try_optimize<'a>(&mut self, base: &mut InstrBase, ctx: &mut InstrContext<'a>, gained: u64) -> bool {
		if base.done {
			return false;
		}

		// If it's in the same block, we assume the target is at most 2GB away.
		let mut use_short = self.bitness != 64 || self.target_instr.is_in_block(ctx.block);
		if !use_short {
			let target_address = self.target_instr.address(ctx);
			let next_rip = ctx.ip.wrapping_add(self.orig_instruction_size as u64);
			let diff = target_address.wrapping_sub(next_rip) as i64;
			let diff = correct_diff(self.target_instr.is_in_block(ctx.block), diff, gained);
			use_short = i32::MIN as i64 <= diff && diff <= i32::MAX as i64;
		}

		if use_short {
			if let Some(ref pointer_data) = self.pointer_data {
				pointer_data.borrow_mut().is_valid = false;
			}
			base.size = self.orig_instruction_size;
			self.use_orig_instruction = true;
			base.done = true;
			return true;
		}

		if self.pointer_data.is_none() {
			self.pointer_data = Some(ctx.block.alloc_pointer_location());
		}
		false
	}
}

impl Instr for CallInstr {
	fn initialize<'a>(&mut self, base: &mut InstrBase, block_encoder: &BlockEncInt, ctx: &mut InstrContext<'a>) {
		self.target_instr = block_encoder.get_target(base, self.instruction.near_branch_target());
		let _ = self.try_optimize(base, ctx, 0);
	}

	fn optimize<'a>(&mut self, base: &mut InstrBase, ctx: &mut InstrContext<'a>, gained: u64) -> bool {
		self.try_optimize(base, ctx, gained)
	}

	fn encode<'a>(&mut self, base: &mut InstrBase, ctx: &mut InstrContext<'a>) -> Result<(ConstantOffsets, bool), IcedError> {
		if self.use_orig_instruction {
			self.instruction.set_near_branch64(self.target_instr.address(ctx));
			ctx.block.encoder.encode(&self.instruction, ctx.ip).map_or_else(
				|err| Err(IcedError::with_string(InstrUtils::create_error_message(&err, &self.instruction))),
				|_| Ok((ctx.block.encoder.get_constant_offsets(), true)),
			)
		} else {
			debug_assert!(self.pointer_data.is_some());
			let pointer_data = self.pointer_data.clone().ok_or_else(|| IcedError::new("Internal error"))?;
			pointer_data.borrow_mut().data = self.target_instr.address(ctx);
			InstrUtils::encode_branch_to_pointer_data(ctx.block, true, ctx.ip, pointer_data, base.size).map_or_else(
				|err| Err(IcedError::with_string(InstrUtils::create_error_message(&err, &self.instruction))),
				|_| Ok((ConstantOffsets::default(), false)),
			)
		}
	}
}
<|endoftext|>


<commit_before>use std;

pub struct Pairwise<I, T> {
    iter: I,
    prev: Option<T>,
}

impl<I: Iterator> Iterator for Pairwise<I, I::Item>
where
    I::Item: Clone,
{
    type Item = (I::Item, I::Item);

    fn next(&mut self) -> Option<Self::Item> {
        if self.prev.is_none() {
            self.prev = self.iter.next();
            if self.prev.is_none() {
                return None;
            }
        }

        let next = self.iter.next();
        if next.is_none() {
            return None;
        }

        use std::mem::replace;
        let pair = (
            replace(&mut self.prev, next.clone()).unwrap(),
            next.unwrap(),
        );
        Some(pair)
    }
}

trait IteratorExt2: Iterator + Sized {
    fn pairwise(self) -> Pairwise<Self, Self::Item>
    where
        Self::Item: Clone,
    {
        Pairwise {
            iter: self,
            prev: None,
        }
    }

    fn join(self, separator: &str) -> String
    where
        Self::Item: std::fmt::Display,
    {
        self.map(|x| format!("{}", x))
            .collect::<Vec<_>>()
            .join(separator)
    }
}

impl<T: Iterator> IteratorExt2 for T {}

#[cfg(test)]
mod tests {
    use super::IteratorExt2;

    #[test]
    fn test_join_empty() {
        assert_eq!("", Vec::<i64>::new().into_iter().join(" "));
    }

    #[test]
    fn test_join() {
        assert_eq!("0 1 2 3", (0..4).join(" "))
    }

    #[test]
    fn test_pairwise() {
        assert_eq!(
            vec![(0, 1), (1, 2), (2, 3)],
            (0..4).pairwise().collect::<Vec<_>>()
        )
    }

    #[test]
    fn test_pairwise_empty() {
        assert_eq!(0, (0..0).pairwise().count());
        assert_eq!(0, (0..1).pairwise().count());
    }
}
<commit_msg>Add Iterator::sort_by_key<commit_after>use std;

pub struct Pairwise<I, T> {
    iter: I,
    prev: Option<T>,
}

impl<I: Iterator> Iterator for Pairwise<I, I::Item>
where
    I::Item: Clone,
{
    type Item = (I::Item, I::Item);

    fn next(&mut self) -> Option<Self::Item> {
        if self.prev.is_none() {
            self.prev = self.iter.next();
            if self.prev.is_none() {
                return None;
            }
        }

        let next = self.iter.next();
        if next.is_none() {
            return None;
        }

        use std::mem::replace;
        let pair = (
            replace(&mut self.prev, next.clone()).unwrap(),
            next.unwrap(),
        );
        Some(pair)
    }
}

trait IteratorExt2: Iterator + Sized {
    fn pairwise(self) -> Pairwise<Self, Self::Item>
    where
        Self::Item: Clone,
    {
        Pairwise {
            iter: self,
            prev: None,
        }
    }

    fn join(self, separator: &str) -> String
    where
        Self::Item: std::fmt::Display,
    {
        self.map(|x| format!("{}", x))
            .collect::<Vec<_>>()
            .join(separator)
    }

    fn sort_by_key<K, F>(self, f: F) -> std::vec::IntoIter<Self::Item>
    where
        K: Ord,
        F: Fn(&Self::Item) -> K,
    {
        let mut v = self.collect::<Vec<_>>();
        v.sort_by_key(f);
        v.into_iter()
    }
}

impl<T: Iterator> IteratorExt2 for T {}

#[cfg(test)]
mod tests {
    use super::IteratorExt2;

    #[test]
    fn test_join_empty() {
        assert_eq!("", Vec::<i64>::new().into_iter().join(" "));
    }

    #[test]
    fn test_join() {
        assert_eq!("0 1 2 3", (0..4).join(" "))
    }

    #[test]
    fn test_pairwise() {
        assert_eq!(
            vec![(0, 1), (1, 2), (2, 3)],
            (0..4).pairwise().collect::<Vec<_>>()
        )
    }

    #[test]
    fn test_pairwise_empty() {
        assert_eq!(0, (0..0).pairwise().count());
        assert_eq!(0, (0..1).pairwise().count());
    }
}
<|endoftext|>