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

// NOTE: https://www.chromium.org/directwrite-font-proxy has useful
// information for an approach that we'll likely need to take when the
// renderer moves to a sandboxed process.

use app_units::Au;
use dwrote;
use dwrote::{Font, FontFace, FontFile};
use dwrote::{FontWeight, FontStretch, FontStyle};
use font::{FontHandleMethods, FontMetrics, FontTableMethods};
use font::{FontTableTag, FractionalPixel};
use platform::font_template::FontTemplateData;
use platform::windows::font_context::FontContextHandle;
use platform::windows::font_list::font_from_atom;
use std::sync::Arc;
use style::computed_values::{font_stretch, font_weight};
use text::glyph::GlyphId;
use truetype;

// 1em = 12pt = 16px, assuming 72 points per inch and 96 px per inch
fn pt_to_px(pt: f64) -> f64 { pt / 72. * 96. }
fn em_to_px(em: f64) -> f64 { em * 16. }
fn au_from_em(em: f64) -> Au { Au::from_f64_px(em_to_px(em)) }
fn au_from_pt(pt: f64) -> Au { Au::from_f64_px(pt_to_px(pt)) }

pub struct FontTable {
    data: Vec<u8>,
}

impl FontTable {
    pub fn wrap(data: &[u8]) -> FontTable {
        FontTable { data: data.to_vec() }
    }
}

impl FontTableMethods for FontTable {
    fn buffer(&self) -> &[u8] {
        &self.data
    }
}

fn make_tag(tag_bytes: &[u8]) -> FontTableTag {
    assert_eq!(tag_bytes.len(), 4);
    unsafe { *(tag_bytes.as_ptr() as *const FontTableTag) }
}

macro_rules! try_lossy(($result:expr) => (try!($result.map_err(|_| (())))));

// Given a set of records, figure out the string indices for the family and face
// names.  We want name_id 1 and 2, and we need to use platform_id == 1 and
// language_id == 0 to avoid limitations in the truetype crate.  We *could* just
// do our own parsing here, and use the offset/length data and pull the values out
// ourselves.
fn get_family_face_indices(records: &[truetype::naming_table::Record]) -> Option<(usize, usize)> {
    let mut family_name_index = None;
    let mut face_name_index = None;

    for i in 0..records.len() {
        // the truetype crate can only decode mac platform format names
        if records[i].platform_id != 1 {
            continue;
        }

        if records[i].language_id != 0 {
            continue;
        }

        if records[i].name_id == 1 {
            family_name_index = Some(i);
        } else if records[i].name_id == 2 {
            face_name_index = Some(i);
        }
    }

    if family_name_index.is_some() && face_name_index.is_some() {
        Some((family_name_index.unwrap(), face_name_index.unwrap()))
    } else {
        None
    }
}

// We need the font (DWriteFont) in order to be able to query things like
// the family name, face name, weight, etc.  On Windows 10, the
// DWriteFontFace3 interface provides this on the FontFace, but that's only
// available on Win10+.
//
// Instead, we do the parsing work using the truetype crate for raw fonts.
// We're just extracting basic info, so this is sufficient for now.

#[derive(Debug)]
struct FontInfo {
    family_name: String,
    face_name: String,
    weight: font_weight::T,
    stretch: font_stretch::T,
    style: FontStyle,
}

impl FontInfo {
    fn new_from_face(face: &FontFace) -> Result<FontInfo, ()> {
        use std::cmp::{min, max};
        use std::io::Cursor;
        use truetype::{NamingTable, Value, WindowsMetrics};

        let name_table_bytes = face.get_font_table(make_tag(b"name"));
        let os2_table_bytes = face.get_font_table(make_tag(b"OS/2"));
        if name_table_bytes.is_none() || os2_table_bytes.is_none() {
            return Err(());
        }

        let mut name_table_cursor = Cursor::new(name_table_bytes.as_ref().unwrap());
        let names = try_lossy!(NamingTable::read(&mut name_table_cursor));
        let (family, face) = match names {
            NamingTable::Format0(ref table) => {
                if let Some((family_index, face_index)) = get_family_face_indices(&table.records) {
                    let strings = table.strings().unwrap();
                    let family = strings[family_index].clone();
                    let face = strings[face_index].clone();
                    ((family, face))
                } else {
                    return Err(());
                }
            },
            NamingTable::Format1(ref table) => {
                if let Some((family_index, face_index)) = get_family_face_indices(&table.records) {
                    let strings = table.strings().unwrap();
                    let family = strings[family_index].clone();
                    let face = strings[face_index].clone();
                    ((family, face))
                } else {
                    return Err(());
                }
            }
        };

        let mut os2_table_cursor = Cursor::new(os2_table_bytes.as_ref().unwrap());
        let metrics = try_lossy!(WindowsMetrics::read(&mut os2_table_cursor));
        let (weight_val, width_val, italic_bool) = match metrics {
            WindowsMetrics::Version0(ref m) => {
                (m.weight_class, m.width_class, m.selection_flags.0 & 1 == 1)
            },
            WindowsMetrics::Version1(ref m) => {
                (m.weight_class, m.width_class, m.selection_flags.0 & 1 == 1)
            },
            WindowsMetrics::Version2(ref m) |
            WindowsMetrics::Version3(ref m) |
            WindowsMetrics::Version4(ref m) => {
                (m.weight_class, m.width_class, m.selection_flags.0 & 1 == 1)
            },
            WindowsMetrics::Version5(ref m) => {
                (m.weight_class, m.width_class, m.selection_flags.0 & 1 == 1)
            },
        };

        let weight = match min(9, max(1, weight_val / 100)) {
            1 => font_weight::T::Weight100,
            2 => font_weight::T::Weight200,
            3 => font_weight::T::Weight300,
            4 => font_weight::T::Weight400,
            5 => font_weight::T::Weight500,
            6 => font_weight::T::Weight600,
            7 => font_weight::T::Weight700,
            8 => font_weight::T::Weight800,
            9 => font_weight::T::Weight900,
            _ => return Err(()),
        };

        let stretch = match min(9, max(1, width_val)) {
            1 => font_stretch::T::ultra_condensed,
            2 => font_stretch::T::extra_condensed,
            3 => font_stretch::T::condensed,
            4 => font_stretch::T::semi_condensed,
            5 => font_stretch::T::normal,
            6 => font_stretch::T::semi_expanded,
            7 => font_stretch::T::expanded,
            8 => font_stretch::T::extra_expanded,
            9 => font_stretch::T::ultra_expanded,
            _ => return Err(()),
        };

        let style = if italic_bool {
            FontStyle::Italic
        } else {
            FontStyle::Normal
        };

        Ok(FontInfo {
            family_name: family,
            face_name: face,
            weight: weight,
            stretch: stretch,
            style: style,
        })
    }

    fn new_from_font(font: &Font) -> Result<FontInfo, ()> {
        let style = font.style();
        let weight = match font.weight() {
            FontWeight::Thin => font_weight::T::Weight100,
            FontWeight::ExtraLight => font_weight::T::Weight200,
            FontWeight::Light => font_weight::T::Weight300,
            // slightly grayer gray
            FontWeight::SemiLight => font_weight::T::Weight300,
            FontWeight::Regular => font_weight::T::Weight400,
            FontWeight::Medium => font_weight::T::Weight500,
            FontWeight::SemiBold => font_weight::T::Weight600,
            FontWeight::Bold => font_weight::T::Weight700,
            FontWeight::ExtraBold => font_weight::T::Weight800,
            FontWeight::Black => font_weight::T::Weight900,
            // slightly blacker black
            FontWeight::ExtraBlack => font_weight::T::Weight900,
        };
        let stretch = match font.stretch() {
            FontStretch::Undefined => font_stretch::T::normal,
            FontStretch::UltraCondensed => font_stretch::T::ultra_condensed,
            FontStretch::ExtraCondensed => font_stretch::T::extra_condensed,
            FontStretch::Condensed => font_stretch::T::condensed,
            FontStretch::SemiCondensed => font_stretch::T::semi_condensed,
            FontStretch::Normal => font_stretch::T::normal,
            FontStretch::SemiExpanded => font_stretch::T::semi_expanded,
            FontStretch::Expanded => font_stretch::T::expanded,
            FontStretch::ExtraExpanded => font_stretch::T::extra_expanded,
            FontStretch::UltraExpanded => font_stretch::T::ultra_expanded,
        };

        Ok(FontInfo {
            family_name: font.family_name(),
            face_name: font.face_name(),
            style: style,
            weight: weight,
            stretch: stretch,
        })
    }
}

#[derive(Debug)]
pub struct FontHandle {
    font_data: Arc<FontTemplateData>,
    face: FontFace,
    info: FontInfo,
    em_size: f32,
    du_per_em: f32,
    du_to_px: f32,
    scaled_du_to_px: f32,
}

impl FontHandle {
}

impl FontHandleMethods for FontHandle {
    fn new_from_template(_: &FontContextHandle, template: Arc<FontTemplateData>, pt_size: Option<Au>)
                         -> Result<Self, ()>
    {
        let (info, face) = if let Some(ref raw_font) = template.bytes {
            let font_file = FontFile::new_from_data(&raw_font);
            if font_file.is_none() {
                // failed to load raw font
                return Err(());
            }

            let face = font_file.unwrap().create_face(0, dwrote::DWRITE_FONT_SIMULATIONS_NONE);
            let info = try!(FontInfo::new_from_face(&face));
            (info, face)
        } else {
            let font = font_from_atom(&template.identifier);
            let face = font.create_font_face();
            let info = try!(FontInfo::new_from_font(&font));
            (info, face)
        };

        let pt_size = pt_size.unwrap_or(au_from_pt(12.));
        let du_per_em = face.metrics().designUnitsPerEm as f32;

        let em_size = pt_size.to_f32_px() / 16.;
        let design_units_per_pixel = du_per_em / 16.;

        let design_units_to_pixels = 1. / design_units_per_pixel;
        let scaled_design_units_to_pixels = em_size / design_units_per_pixel;

        Ok(FontHandle {
            font_data: template.clone(),
            face: face,
            info: info,
            em_size: em_size,
            du_per_em: du_per_em,
            du_to_px: design_units_to_pixels,
            scaled_du_to_px: scaled_design_units_to_pixels,
        })
    }

    fn template(&self) -> Arc<FontTemplateData> {
        self.font_data.clone()
    }

    fn family_name(&self) -> String {
        self.info.family_name.clone()
    }

    fn face_name(&self) -> Option<String> {
        Some(self.info.face_name.clone())
    }

    fn is_italic(&self) -> bool {
        match self.info.style {
            FontStyle::Normal => false,
            FontStyle::Oblique | FontStyle::Italic => true,
        }
    }

    fn boldness(&self) -> font_weight::T {
        self.info.weight
    }

    fn stretchiness(&self) -> font_stretch::T {
        self.info.stretch
    }

    fn glyph_index(&self, codepoint: char) -> Option<GlyphId> {
        let glyph = self.face.get_glyph_indices(&[codepoint as u32])[0];
        if glyph == 0 {
            return None;
        }
        Some(glyph as GlyphId)
    }

    fn glyph_h_advance(&self, glyph: GlyphId) -> Option<FractionalPixel> {
        if glyph == 0 {
            return None;
        }

        let gm = self.face.get_design_glyph_metrics(&[glyph as u16], false)[0];
        let f = (gm.advanceWidth as f32 * self.scaled_du_to_px) as FractionalPixel;

        Some(f)
    }

    /// Can this font do basic horizontal LTR shaping without Harfbuzz?
    fn can_do_fast_shaping(&self) -> bool {
        // TODO copy CachedKernTable from the MacOS X implementation to
        // somehwere global and use it here.  We could also implement the
        // IDirectWriteFontFace1 interface and use the glyph kerning pair
        // methods there.
        false
    }

    fn glyph_h_kerning(&self, _: GlyphId, _: GlyphId) -> FractionalPixel {
        0.0
    }

    fn metrics(&self) -> FontMetrics {
        let dm = self.face.metrics();

        let au_from_du = |du| -> Au { Au::from_f32_px(du as f32 * self.du_to_px) };
        let au_from_du_s = |du| -> Au { Au:: from_f32_px(du as f32 * self.scaled_du_to_px) };

        // anything that we calculate and don't just pull out of self.face.metrics
        // is pulled out here for clarity
        let leading = dm.ascent - dm.capHeight;

        let metrics = FontMetrics {
            underline_size:   au_from_du(dm.underlineThickness as i32),
            underline_offset: au_from_du_s(dm.underlinePosition as i32),
            strikeout_size:   au_from_du(dm.strikethroughThickness as i32),
            strikeout_offset: au_from_du_s(dm.strikethroughPosition as i32),
            leading:          au_from_du_s(leading as i32),
            x_height:         au_from_du_s(dm.xHeight as i32),
            em_size:          au_from_em(self.em_size as f64),
            ascent:           au_from_du_s(dm.ascent as i32),
            descent:          au_from_du_s(dm.descent as i32),
            max_advance:      au_from_pt(0.0), // FIXME
            average_advance:  au_from_pt(0.0), // FIXME
            line_gap:         au_from_du((dm.ascent + dm.descent + dm.lineGap as u16) as i32),
        };
        debug!("Font metrics (@{} pt): {:?}", self.em_size * 12., metrics);
        metrics
    }

    fn table_for_tag(&self, tag: FontTableTag) -> Option<FontTable> {
        self.face.get_font_table(tag).map(|bytes| FontTable { data: bytes })
    }
}
<commit_msg>scale line gap by em size<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/. */

// NOTE: https://www.chromium.org/directwrite-font-proxy has useful
// information for an approach that we'll likely need to take when the
// renderer moves to a sandboxed process.

use app_units::Au;
use dwrote;
use dwrote::{Font, FontFace, FontFile};
use dwrote::{FontWeight, FontStretch, FontStyle};
use font::{FontHandleMethods, FontMetrics, FontTableMethods};
use font::{FontTableTag, FractionalPixel};
use platform::font_template::FontTemplateData;
use platform::windows::font_context::FontContextHandle;
use platform::windows::font_list::font_from_atom;
use std::sync::Arc;
use style::computed_values::{font_stretch, font_weight};
use text::glyph::GlyphId;
use truetype;

// 1em = 12pt = 16px, assuming 72 points per inch and 96 px per inch
fn pt_to_px(pt: f64) -> f64 { pt / 72. * 96. }
fn em_to_px(em: f64) -> f64 { em * 16. }
fn au_from_em(em: f64) -> Au { Au::from_f64_px(em_to_px(em)) }
fn au_from_pt(pt: f64) -> Au { Au::from_f64_px(pt_to_px(pt)) }

pub struct FontTable {
    data: Vec<u8>,
}

impl FontTable {
    pub fn wrap(data: &[u8]) -> FontTable {
        FontTable { data: data.to_vec() }
    }
}

impl FontTableMethods for FontTable {
    fn buffer(&self) -> &[u8] {
        &self.data
    }
}

fn make_tag(tag_bytes: &[u8]) -> FontTableTag {
    assert_eq!(tag_bytes.len(), 4);
    unsafe { *(tag_bytes.as_ptr() as *const FontTableTag) }
}

macro_rules! try_lossy(($result:expr) => (try!($result.map_err(|_| (())))));

// Given a set of records, figure out the string indices for the family and face
// names.  We want name_id 1 and 2, and we need to use platform_id == 1 and
// language_id == 0 to avoid limitations in the truetype crate.  We *could* just
// do our own parsing here, and use the offset/length data and pull the values out
// ourselves.
fn get_family_face_indices(records: &[truetype::naming_table::Record]) -> Option<(usize, usize)> {
    let mut family_name_index = None;
    let mut face_name_index = None;

    for i in 0..records.len() {
        // the truetype crate can only decode mac platform format names
        if records[i].platform_id != 1 {
            continue;
        }

        if records[i].language_id != 0 {
            continue;
        }

        if records[i].name_id == 1 {
            family_name_index = Some(i);
        } else if records[i].name_id == 2 {
            face_name_index = Some(i);
        }
    }

    if family_name_index.is_some() && face_name_index.is_some() {
        Some((family_name_index.unwrap(), face_name_index.unwrap()))
    } else {
        None
    }
}

// We need the font (DWriteFont) in order to be able to query things like
// the family name, face name, weight, etc.  On Windows 10, the
// DWriteFontFace3 interface provides this on the FontFace, but that's only
// available on Win10+.
//
// Instead, we do the parsing work using the truetype crate for raw fonts.
// We're just extracting basic info, so this is sufficient for now.

#[derive(Debug)]
struct FontInfo {
    family_name: String,
    face_name: String,
    weight: font_weight::T,
    stretch: font_stretch::T,
    style: FontStyle,
}

impl FontInfo {
    fn new_from_face(face: &FontFace) -> Result<FontInfo, ()> {
        use std::cmp::{min, max};
        use std::io::Cursor;
        use truetype::{NamingTable, Value, WindowsMetrics};

        let name_table_bytes = face.get_font_table(make_tag(b"name"));
        let os2_table_bytes = face.get_font_table(make_tag(b"OS/2"));
        if name_table_bytes.is_none() || os2_table_bytes.is_none() {
            return Err(());
        }

        let mut name_table_cursor = Cursor::new(name_table_bytes.as_ref().unwrap());
        let names = try_lossy!(NamingTable::read(&mut name_table_cursor));
        let (family, face) = match names {
            NamingTable::Format0(ref table) => {
                if let Some((family_index, face_index)) = get_family_face_indices(&table.records) {
                    let strings = table.strings().unwrap();
                    let family = strings[family_index].clone();
                    let face = strings[face_index].clone();
                    ((family, face))
                } else {
                    return Err(());
                }
            },
            NamingTable::Format1(ref table) => {
                if let Some((family_index, face_index)) = get_family_face_indices(&table.records) {
                    let strings = table.strings().unwrap();
                    let family = strings[family_index].clone();
                    let face = strings[face_index].clone();
                    ((family, face))
                } else {
                    return Err(());
                }
            }
        };

        let mut os2_table_cursor = Cursor::new(os2_table_bytes.as_ref().unwrap());
        let metrics = try_lossy!(WindowsMetrics::read(&mut os2_table_cursor));
        let (weight_val, width_val, italic_bool) = match metrics {
            WindowsMetrics::Version0(ref m) => {
                (m.weight_class, m.width_class, m.selection_flags.0 & 1 == 1)
            },
            WindowsMetrics::Version1(ref m) => {
                (m.weight_class, m.width_class, m.selection_flags.0 & 1 == 1)
            },
            WindowsMetrics::Version2(ref m) |
            WindowsMetrics::Version3(ref m) |
            WindowsMetrics::Version4(ref m) => {
                (m.weight_class, m.width_class, m.selection_flags.0 & 1 == 1)
            },
            WindowsMetrics::Version5(ref m) => {
                (m.weight_class, m.width_class, m.selection_flags.0 & 1 == 1)
            },
        };

        let weight = match min(9, max(1, weight_val / 100)) {
            1 => font_weight::T::Weight100,
            2 => font_weight::T::Weight200,
            3 => font_weight::T::Weight300,
            4 => font_weight::T::Weight400,
            5 => font_weight::T::Weight500,
            6 => font_weight::T::Weight600,
            7 => font_weight::T::Weight700,
            8 => font_weight::T::Weight800,
            9 => font_weight::T::Weight900,
            _ => return Err(()),
        };

        let stretch = match min(9, max(1, width_val)) {
            1 => font_stretch::T::ultra_condensed,
            2 => font_stretch::T::extra_condensed,
            3 => font_stretch::T::condensed,
            4 => font_stretch::T::semi_condensed,
            5 => font_stretch::T::normal,
            6 => font_stretch::T::semi_expanded,
            7 => font_stretch::T::expanded,
            8 => font_stretch::T::extra_expanded,
            9 => font_stretch::T::ultra_expanded,
            _ => return Err(()),
        };

        let style = if italic_bool {
            FontStyle::Italic
        } else {
            FontStyle::Normal
        };

        Ok(FontInfo {
            family_name: family,
            face_name: face,
            weight: weight,
            stretch: stretch,
            style: style,
        })
    }

    fn new_from_font(font: &Font) -> Result<FontInfo, ()> {
        let style = font.style();
        let weight = match font.weight() {
            FontWeight::Thin => font_weight::T::Weight100,
            FontWeight::ExtraLight => font_weight::T::Weight200,
            FontWeight::Light => font_weight::T::Weight300,
            // slightly grayer gray
            FontWeight::SemiLight => font_weight::T::Weight300,
            FontWeight::Regular => font_weight::T::Weight400,
            FontWeight::Medium => font_weight::T::Weight500,
            FontWeight::SemiBold => font_weight::T::Weight600,
            FontWeight::Bold => font_weight::T::Weight700,
            FontWeight::ExtraBold => font_weight::T::Weight800,
            FontWeight::Black => font_weight::T::Weight900,
            // slightly blacker black
            FontWeight::ExtraBlack => font_weight::T::Weight900,
        };
        let stretch = match font.stretch() {
            FontStretch::Undefined => font_stretch::T::normal,
            FontStretch::UltraCondensed => font_stretch::T::ultra_condensed,
            FontStretch::ExtraCondensed => font_stretch::T::extra_condensed,
            FontStretch::Condensed => font_stretch::T::condensed,
            FontStretch::SemiCondensed => font_stretch::T::semi_condensed,
            FontStretch::Normal => font_stretch::T::normal,
            FontStretch::SemiExpanded => font_stretch::T::semi_expanded,
            FontStretch::Expanded => font_stretch::T::expanded,
            FontStretch::ExtraExpanded => font_stretch::T::extra_expanded,
            FontStretch::UltraExpanded => font_stretch::T::ultra_expanded,
        };

        Ok(FontInfo {
            family_name: font.family_name(),
            face_name: font.face_name(),
            style: style,
            weight: weight,
            stretch: stretch,
        })
    }
}

#[derive(Debug)]
pub struct FontHandle {
    font_data: Arc<FontTemplateData>,
    face: FontFace,
    info: FontInfo,
    em_size: f32,
    du_per_em: f32,
    du_to_px: f32,
    scaled_du_to_px: f32,
}

impl FontHandle {
}

impl FontHandleMethods for FontHandle {
    fn new_from_template(_: &FontContextHandle, template: Arc<FontTemplateData>, pt_size: Option<Au>)
                         -> Result<Self, ()>
    {
        let (info, face) = if let Some(ref raw_font) = template.bytes {
            let font_file = FontFile::new_from_data(&raw_font);
            if font_file.is_none() {
                // failed to load raw font
                return Err(());
            }

            let face = font_file.unwrap().create_face(0, dwrote::DWRITE_FONT_SIMULATIONS_NONE);
            let info = try!(FontInfo::new_from_face(&face));
            (info, face)
        } else {
            let font = font_from_atom(&template.identifier);
            let face = font.create_font_face();
            let info = try!(FontInfo::new_from_font(&font));
            (info, face)
        };

        let pt_size = pt_size.unwrap_or(au_from_pt(12.));
        let du_per_em = face.metrics().designUnitsPerEm as f32;

        let em_size = pt_size.to_f32_px() / 16.;
        let design_units_per_pixel = du_per_em / 16.;

        let design_units_to_pixels = 1. / design_units_per_pixel;
        let scaled_design_units_to_pixels = em_size / design_units_per_pixel;

        Ok(FontHandle {
            font_data: template.clone(),
            face: face,
            info: info,
            em_size: em_size,
            du_per_em: du_per_em,
            du_to_px: design_units_to_pixels,
            scaled_du_to_px: scaled_design_units_to_pixels,
        })
    }

    fn template(&self) -> Arc<FontTemplateData> {
        self.font_data.clone()
    }

    fn family_name(&self) -> String {
        self.info.family_name.clone()
    }

    fn face_name(&self) -> Option<String> {
        Some(self.info.face_name.clone())
    }

    fn is_italic(&self) -> bool {
        match self.info.style {
            FontStyle::Normal => false,
            FontStyle::Oblique | FontStyle::Italic => true,
        }
    }

    fn boldness(&self) -> font_weight::T {
        self.info.weight
    }

    fn stretchiness(&self) -> font_stretch::T {
        self.info.stretch
    }

    fn glyph_index(&self, codepoint: char) -> Option<GlyphId> {
        let glyph = self.face.get_glyph_indices(&[codepoint as u32])[0];
        if glyph == 0 {
            return None;
        }
        Some(glyph as GlyphId)
    }

    fn glyph_h_advance(&self, glyph: GlyphId) -> Option<FractionalPixel> {
        if glyph == 0 {
            return None;
        }

        let gm = self.face.get_design_glyph_metrics(&[glyph as u16], false)[0];
        let f = (gm.advanceWidth as f32 * self.scaled_du_to_px) as FractionalPixel;

        Some(f)
    }

    /// Can this font do basic horizontal LTR shaping without Harfbuzz?
    fn can_do_fast_shaping(&self) -> bool {
        // TODO copy CachedKernTable from the MacOS X implementation to
        // somehwere global and use it here.  We could also implement the
        // IDirectWriteFontFace1 interface and use the glyph kerning pair
        // methods there.
        false
    }

    fn glyph_h_kerning(&self, _: GlyphId, _: GlyphId) -> FractionalPixel {
        0.0
    }

    fn metrics(&self) -> FontMetrics {
        let dm = self.face.metrics();

        let au_from_du = |du| -> Au { Au::from_f32_px(du as f32 * self.du_to_px) };
        let au_from_du_s = |du| -> Au { Au:: from_f32_px(du as f32 * self.scaled_du_to_px) };

        // anything that we calculate and don't just pull out of self.face.metrics
        // is pulled out here for clarity
        let leading = dm.ascent - dm.capHeight;

        let metrics = FontMetrics {
            underline_size:   au_from_du(dm.underlineThickness as i32),
            underline_offset: au_from_du_s(dm.underlinePosition as i32),
            strikeout_size:   au_from_du(dm.strikethroughThickness as i32),
            strikeout_offset: au_from_du_s(dm.strikethroughPosition as i32),
            leading:          au_from_du_s(leading as i32),
            x_height:         au_from_du_s(dm.xHeight as i32),
            em_size:          au_from_em(self.em_size as f64),
            ascent:           au_from_du_s(dm.ascent as i32),
            descent:          au_from_du_s(dm.descent as i32),
            max_advance:      au_from_pt(0.0), // FIXME
            average_advance:  au_from_pt(0.0), // FIXME
            line_gap:         au_from_du_s((dm.ascent + dm.descent + dm.lineGap as u16) as i32),
        };
        debug!("Font metrics (@{} pt): {:?}", self.em_size * 12., metrics);
        metrics
    }

    fn table_for_tag(&self, tag: FontTableTag) -> Option<FontTable> {
        self.face.get_font_table(tag).map(|bytes| FontTable { data: bytes })
    }
}
<|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::Bindings::HTMLDivElementBinding::{self, HTMLDivElementMethods};
use dom::bindings::js::Root;
use dom::bindings::str::DOMString;
use dom::document::Document;
use dom::htmlelement::HTMLElement;
use dom::node::Node;
use string_cache::Atom;

#[dom_struct]
pub struct HTMLDivElement {
    htmlelement: HTMLElement
}

impl HTMLDivElement {
    fn new_inherited(localName: Atom,
                     prefix: Option<DOMString>,
                     document: &Document) -> HTMLDivElement {
        HTMLDivElement {
            htmlelement: HTMLElement::new_inherited(localName, prefix, document)
        }
    }

    #[allow(unrooted_must_root)]
    pub fn new(localName: Atom,
               prefix: Option<DOMString>,
               document: &Document) -> Root<HTMLDivElement> {
        let element = HTMLDivElement::new_inherited(localName, prefix, document);
        Node::reflect_node(box element, document, HTMLDivElementBinding::Wrap)
    }
}

impl HTMLDivElementMethods for HTMLDivElement {
    // https://html.spec.whatwg.org/multipage/#dom-div-align
    make_getter!(Align, "align");

    // https://html.spec.whatwg.org/multipage/#dom-div-align
    make_setter!(SetAlign, "align");
}
<commit_msg>Avoid memmove in HTMLDivElement constructor.<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::Bindings::HTMLDivElementBinding::{self, HTMLDivElementMethods};
use dom::bindings::js::Root;
use dom::bindings::str::DOMString;
use dom::document::Document;
use dom::htmlelement::HTMLElement;
use dom::node::Node;
use string_cache::Atom;

#[dom_struct]
pub struct HTMLDivElement {
    htmlelement: HTMLElement
}

impl HTMLDivElement {
    fn new_inherited(localName: Atom,
                     prefix: Option<DOMString>,
                     document: &Document) -> HTMLDivElement {
        HTMLDivElement {
            htmlelement: HTMLElement::new_inherited(localName, prefix, document)
        }
    }

    #[allow(unrooted_must_root)]
    pub fn new(localName: Atom,
               prefix: Option<DOMString>,
               document: &Document) -> Root<HTMLDivElement> {
        Node::reflect_node(box HTMLDivElement::new_inherited(localName, prefix, document),
                           document,
                           HTMLDivElementBinding::Wrap)
    }
}

impl HTMLDivElementMethods for HTMLDivElement {
    // https://html.spec.whatwg.org/multipage/#dom-div-align
    make_getter!(Align, "align");

    // https://html.spec.whatwg.org/multipage/#dom-div-align
    make_setter!(SetAlign, "align");
}
<|endoftext|>


<commit_before>#![feature(phase)]
#[phase(syntax, link)] extern crate log;

extern crate http;
extern crate sync;
use std::io::net::ip::SocketAddr;
use std::vec::Vec;
use std::cell::RefCell;
use http::server::ResponseWriter;
use http::server::Server;

use sync::{RWLock, Arc};

#[deriving(Clone)]
struct Oxidize<'a> {
    pub config : &'a Config,
    // pub app : &'a App,
    pub router : RefCell<~Router:Send>,
    // pub filters : ~[~MiddleWare],
}

trait App {
    fn get_routes(&self) -> ~Router:Send;
}

struct MyApp {
    pub render: Renderer,
}

struct Renderer;

impl Renderer {
    fn print() {
        println!("Rendered!");
    }
}

struct Config {
    pub bind_addr : SocketAddr,
}

struct Request<'a> {
    url: &'a str,
}

struct Response {
    text: ~str
}

trait Router:Send {
    fn add_route(&self, &str, |Request, &mut Response|);
    fn route(&self, Request, &mut Response);
    fn copy(&self) -> ~Router:Send;
}

impl Clone for ~Router:Send {
    fn clone(&self) -> ~Router:Send {
        self.copy()
    }
}

// not fully operational but good enough for now
struct MatchRouter<'a> {
    routes : Arc<RWLock<Vec<|Request, &mut Response|: 'a>>>,
}

impl<'a> Router for MatchRouter<'a> {
    fn add_route(&self, path: &str, f: |Request, &mut Response|: 'a){
        self.routes.write().push(f);
    }
    fn route(&self, req: Request, res: &mut Response) {
        match req.url {
            "/index" => (self.routes.read().get(0))(req, res),
            "/hello" => (self.routes.read().get(1))(req, res),
            _ => unreachable!(),
        };
    }
    fn copy(&self) -> ~Router:Send {
        ~MatchRouter {
            routes: self.routes.clone(),
        } as ~Router:Send
    }
}

impl App for MyApp {
    fn get_router(&self) -> ~Router:Send {
        let a = ~MatchRouter{routes: Arc::new(RWLock::new(Vec::new()))};
        a.add_route("/index", |req, &mut res| {self.index()});
        a.add_route("/hello", |req, &mut res| {self.hello()});
        a as ~Router:Send
    }
}

impl MyApp {
    fn index(&self) { self.render(); }
    fn hello(&self) { println!("hello!"); }
}

impl<'a> Server for Oxidize<'a> {
    fn get_config(&self) -> http::server::Config {
        let bind_addr = self.conf.bind_addr;
        http::server::Config { bind_address: bind_addr }
    }

    fn handle_request(&self, req: &http::server::Request, response: &mut ResponseWriter) {
        let q = Request{ method: "test" };
        let mut s = Response{ text: ~"hehe" };

        self.router.route(q, &mut s);
    }
}

impl<'a> Oxidize<'a> {
    fn serve(self) {
        println!("Server is now running at {}", self.conf.bind_addr.to_str());
        self.serve_forever();
    }
}
fn main() {

    let conf = Config {
        bind_addr: from_str::<SocketAddr>("127.0.0.1:8001").unwrap(),
    };
}<commit_msg>Hoping to get some help from IRC<commit_after>#![feature(phase)]
#[phase(syntax, link)] extern crate log;

extern crate http;
extern crate sync;
use std::io::net::ip::SocketAddr;
use std::vec::Vec;
use std::cell::RefCell;
use http::server::ResponseWriter;
use http::server::Server;

use sync::{RWLock, Arc};

#[deriving(Clone)]
struct Oxidize<'a> {
    pub conf : &'a Config,
    // pub app : &'a App,
    pub router : RefCell<~Router<'a>:Send>,
    // pub filters : ~[~MiddleWare],
}

trait App<'a> {
    fn get_router(&self) -> ~Router<'a>:Send;
}

struct MyApp {
    renderer: Renderer,
}

struct Renderer;

impl Renderer {
    fn print(&self) {
        println!("Rendered!");
    }
}

struct Config {
    pub bind_addr : SocketAddr,
}

struct Request<'a> {
    url: &'a str,
}

struct Response {
    text: ~str
}

trait Router<'a>:Send {
    fn add_route(&self, &str, |Request, &mut Response|: 'a);
    fn route(&self, Request, &mut Response);
    fn copy(&self) -> ~Router<'a>:Send;
}

impl<'a> Clone for ~Router<'a>:Send {
    fn clone(&self) -> ~Router<'a>:Send {
        self.copy()
    }
}

// not fully operational but good enough for now
struct MatchRouter<'a> {
    // make this a tuple of uris method and closure?
    routes : Arc<RWLock<~[|Request, &mut Response|: 'a]>>,
}

impl<'a> Router<'a> for MatchRouter<'a> {
    fn add_route(&self, path: &str, f: |Request, &mut Response|: 'a){
        // self.routes.write().push(f);
    }
    fn route(&self, req: Request, res: &mut Response) {
        match req.url {
            "/index" => (*self.routes.read().get(0).unwrap())(req, res),
            "/hello" => (*self.routes.read().get(1).unwrap())(req, res),
            _ => unreachable!(),
        };
    }
    fn copy(&self) -> ~Router<'a>:Send {
        ~MatchRouter {
            routes: self.routes.clone(),
        } as ~Router<'a>:Send
    }
}

impl<'a> App<'a> for MyApp {
    fn get_router(&self) -> ~Router<'a>:Send {
        let routes : ~[|Request, &mut Response|: 'a] = ~[
            |req, res| {self.index()},
            |req, res| {self.hello()},
        ];
        let a = ~MatchRouter{routes: Arc::new(RWLock::new(routes))};
        // a.add_route("/index", |req, res| {self.index()});
        // a.add_route("/hello", |req, res| {self.hello()});
        a as ~Router<'a>:Send
    }
}

impl MyApp {
    fn index(&self) { self.renderer.print(); }
    fn hello(&self) { println!("hello!"); }
}

impl<'a> Server for Oxidize<'a> {
    fn get_config(&self) -> http::server::Config {
        let bind_addr = self.conf.bind_addr;
        http::server::Config { bind_address: bind_addr }
    }

    fn handle_request(&self, req: &http::server::Request, response: &mut ResponseWriter) {
        let q = Request{ url: "test" };
        let mut s = Response{ text: ~"hehe" };

        self.router.borrow().route(q, &mut s);
    }
}

impl<'a> Oxidize<'a> {
    fn serve(self) {
        println!("Server is now running at {}", self.conf.bind_addr.to_str());
        self.serve_forever();
    }
}
fn main() {

    let conf = Config {
        bind_addr: from_str::<SocketAddr>("127.0.0.1:8001").unwrap(),
    };
}<|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 https://mozilla.org/MPL/2.0/. */

//! Gecko's media-query device and expression representation.

use crate::custom_properties::CssEnvironment;
use crate::gecko::values::{convert_nscolor_to_rgba, convert_rgba_to_nscolor};
use crate::gecko_bindings::bindings;
use crate::gecko_bindings::structs;
use crate::media_queries::MediaType;
use crate::properties::ComputedValues;
use crate::string_cache::Atom;
use crate::values::computed::font::FontSize;
use crate::values::{CustomIdent, KeyframesName};
use app_units::Au;
use app_units::AU_PER_PX;
use cssparser::RGBA;
use euclid::default::Size2D;
use euclid::Scale;
use servo_arc::Arc;
use std::fmt;
use std::sync::atomic::{AtomicBool, AtomicIsize, AtomicUsize, Ordering};
use style_traits::viewport::ViewportConstraints;
use style_traits::{CSSPixel, DevicePixel};

/// The `Device` in Gecko wraps a pres context, has a default values computed,
/// and contains all the viewport rule state.
pub struct Device {
    /// NB: The document owns the styleset, who owns the stylist, and thus the
    /// `Device`, so having a raw document pointer here is fine.
    document: *const structs::Document,
    default_values: Arc<ComputedValues>,
    /// The font size of the root element
    /// This is set when computing the style of the root
    /// element, and used for rem units in other elements.
    ///
    /// When computing the style of the root element, there can't be any
    /// other style being computed at the same time, given we need the style of
    /// the parent to compute everything else. So it is correct to just use
    /// a relaxed atomic here.
    root_font_size: AtomicIsize,
    /// The body text color, stored as an `nscolor`, used for the "tables
    /// inherit from body" quirk.
    ///
    /// <https://quirks.spec.whatwg.org/#the-tables-inherit-color-from-body-quirk>
    body_text_color: AtomicUsize,
    /// Whether any styles computed in the document relied on the root font-size
    /// by using rem units.
    used_root_font_size: AtomicBool,
    /// Whether any styles computed in the document relied on the viewport size
    /// by using vw/vh/vmin/vmax units.
    used_viewport_size: AtomicBool,
    /// The CssEnvironment object responsible of getting CSS environment
    /// variables.
    environment: CssEnvironment,
}

impl fmt::Debug for Device {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use nsstring::nsCString;

        let mut doc_uri = nsCString::new();
        unsafe {
            bindings::Gecko_nsIURI_Debug(
                (*self.document()).mDocumentURI.raw::<structs::nsIURI>(),
                &mut doc_uri,
            )
        };

        f.debug_struct("Device")
            .field("document_url", &doc_uri)
            .finish()
    }
}

unsafe impl Sync for Device {}
unsafe impl Send for Device {}

impl Device {
    /// Trivially constructs a new `Device`.
    pub fn new(document: *const structs::Document) -> Self {
        assert!(!document.is_null());
        let doc = unsafe { &*document };
        let prefs = unsafe { &*bindings::Gecko_GetPrefSheetPrefs(doc) };
        Device {
            document,
            default_values: ComputedValues::default_values(doc),
            // FIXME(bz): Seems dubious?
            root_font_size: AtomicIsize::new(FontSize::medium().size().0 as isize),
            body_text_color: AtomicUsize::new(prefs.mDefaultColor as usize),
            used_root_font_size: AtomicBool::new(false),
            used_viewport_size: AtomicBool::new(false),
            environment: CssEnvironment,
        }
    }

    /// Get the relevant environment to resolve `env()` functions.
    #[inline]
    pub fn environment(&self) -> &CssEnvironment {
        &self.environment
    }

    /// Tells the device that a new viewport rule has been found, and stores the
    /// relevant viewport constraints.
    pub fn account_for_viewport_rule(&mut self, _constraints: &ViewportConstraints) {
        unreachable!("Gecko doesn't support @viewport");
    }

    /// Whether any animation name may be referenced from the style of any
    /// element.
    pub fn animation_name_may_be_referenced(&self, name: &KeyframesName) -> bool {
        let pc = match self.pres_context() {
            Some(pc) => pc,
            None => return false,
        };

        unsafe {
            bindings::Gecko_AnimationNameMayBeReferencedFromStyle(pc, name.as_atom().as_ptr())
        }
    }

    /// Returns the default computed values as a reference, in order to match
    /// Servo.
    pub fn default_computed_values(&self) -> &ComputedValues {
        &self.default_values
    }

    /// Returns the default computed values as an `Arc`.
    pub fn default_computed_values_arc(&self) -> &Arc<ComputedValues> {
        &self.default_values
    }

    /// Get the font size of the root element (for rem)
    pub fn root_font_size(&self) -> Au {
        self.used_root_font_size.store(true, Ordering::Relaxed);
        Au::new(self.root_font_size.load(Ordering::Relaxed) as i32)
    }

    /// Set the font size of the root element (for rem)
    pub fn set_root_font_size(&self, size: Au) {
        self.root_font_size
            .store(size.0 as isize, Ordering::Relaxed)
    }

    /// Sets the body text color for the "inherit color from body" quirk.
    ///
    /// <https://quirks.spec.whatwg.org/#the-tables-inherit-color-from-body-quirk>
    pub fn set_body_text_color(&self, color: RGBA) {
        self.body_text_color
            .store(convert_rgba_to_nscolor(&color) as usize, Ordering::Relaxed)
    }

    /// Returns the body text color.
    pub fn body_text_color(&self) -> RGBA {
        convert_nscolor_to_rgba(self.body_text_color.load(Ordering::Relaxed) as u32)
    }

    /// Gets the document pointer.
    #[inline]
    pub fn document(&self) -> &structs::Document {
        unsafe { &*self.document }
    }

    /// Gets the pres context associated with this document.
    #[inline]
    pub fn pres_context(&self) -> Option<&structs::nsPresContext> {
        unsafe {
            self.document()
                .mPresShell
                .as_ref()?
                .mPresContext
                .mRawPtr
                .as_ref()
        }
    }

    /// Gets the preference stylesheet prefs for our document.
    #[inline]
    pub fn pref_sheet_prefs(&self) -> &structs::PreferenceSheet_Prefs {
        unsafe { &*bindings::Gecko_GetPrefSheetPrefs(self.document()) }
    }

    /// Recreates the default computed values.
    pub fn reset_computed_values(&mut self) {
        self.default_values = ComputedValues::default_values(self.document());
    }

    /// Rebuild all the cached data.
    pub fn rebuild_cached_data(&mut self) {
        self.reset_computed_values();
        self.used_root_font_size.store(false, Ordering::Relaxed);
        self.used_viewport_size.store(false, Ordering::Relaxed);
    }

    /// Returns whether we ever looked up the root font size of the Device.
    pub fn used_root_font_size(&self) -> bool {
        self.used_root_font_size.load(Ordering::Relaxed)
    }

    /// Recreates all the temporary state that the `Device` stores.
    ///
    /// This includes the viewport override from `@viewport` rules, and also the
    /// default computed values.
    pub fn reset(&mut self) {
        self.reset_computed_values();
    }

    /// Returns the current media type of the device.
    pub fn media_type(&self) -> MediaType {
        let pc = match self.pres_context() {
            Some(pc) => pc,
            None => return MediaType::screen(),
        };

        // Gecko allows emulating random media with mMediaEmulated.
        let medium_to_use = if !pc.mMediaEmulated.mRawPtr.is_null() {
            pc.mMediaEmulated.mRawPtr
        } else {
            pc.mMedium as *const bindings::nsAtom as *mut _
        };

        MediaType(CustomIdent(unsafe { Atom::from_raw(medium_to_use) }))
    }

    /// Returns the current viewport size in app units.
    pub fn au_viewport_size(&self) -> Size2D<Au> {
        let pc = match self.pres_context() {
            Some(pc) => pc,
            None => return Size2D::new(Au(0), Au(0)),
        };
        let area = &pc.mVisibleArea;
        Size2D::new(Au(area.width), Au(area.height))
    }

    /// Returns the current viewport size in app units, recording that it's been
    /// used for viewport unit resolution.
    pub fn au_viewport_size_for_viewport_unit_resolution(&self) -> Size2D<Au> {
        self.used_viewport_size.store(true, Ordering::Relaxed);
        self.au_viewport_size()
    }

    /// Returns whether we ever looked up the viewport size of the Device.
    pub fn used_viewport_size(&self) -> bool {
        self.used_viewport_size.load(Ordering::Relaxed)
    }

    /// Returns the device pixel ratio.
    pub fn device_pixel_ratio(&self) -> Scale<f32, CSSPixel, DevicePixel> {
        let pc = match self.pres_context() {
            Some(pc) => pc,
            None => return Scale::new(1.),
        };

        let override_dppx = pc.mOverrideDPPX;
        if override_dppx > 0.0 {
            return Scale::new(override_dppx);
        }

        let au_per_dpx = pc.mCurAppUnitsPerDevPixel as f32;
        let au_per_px = AU_PER_PX as f32;
        Scale::new(au_per_px / au_per_dpx)
    }

    /// Returns whether document colors are enabled.
    #[inline]
    pub fn use_document_colors(&self) -> bool {
        let doc = self.document();
        if doc.mIsBeingUsedAsImage() {
            return true;
        }
        let document_color_use =
            unsafe { structs::StaticPrefs::sVarCache_browser_display_document_color_use };
        let prefs = self.pref_sheet_prefs();
        match document_color_use {
            1 => true,
            2 => prefs.mIsChrome,
            _ => !prefs.mUseAccessibilityTheme,
        }
    }

    /// Returns the default background color.
    pub fn default_background_color(&self) -> RGBA {
        convert_nscolor_to_rgba(self.pref_sheet_prefs().mDefaultBackgroundColor)
    }

    /// Returns the current effective text zoom.
    #[inline]
    fn effective_text_zoom(&self) -> f32 {
        let pc = match self.pres_context() {
            Some(pc) => pc,
            None => return 1.,
        };
        pc.mEffectiveTextZoom
    }

    /// Applies text zoom to a font-size or line-height value (see nsStyleFont::ZoomText).
    #[inline]
    pub fn zoom_text(&self, size: Au) -> Au {
        size.scale_by(self.effective_text_zoom())
    }

    /// Un-apply text zoom.
    #[inline]
    pub fn unzoom_text(&self, size: Au) -> Au {
        size.scale_by(1. / self.effective_text_zoom())
    }
}
<commit_msg>style: Move the overrides to a separate struct in nsPresContext.<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 https://mozilla.org/MPL/2.0/. */

//! Gecko's media-query device and expression representation.

use crate::custom_properties::CssEnvironment;
use crate::gecko::values::{convert_nscolor_to_rgba, convert_rgba_to_nscolor};
use crate::gecko_bindings::bindings;
use crate::gecko_bindings::structs;
use crate::media_queries::MediaType;
use crate::properties::ComputedValues;
use crate::string_cache::Atom;
use crate::values::computed::font::FontSize;
use crate::values::{CustomIdent, KeyframesName};
use app_units::Au;
use app_units::AU_PER_PX;
use cssparser::RGBA;
use euclid::default::Size2D;
use euclid::Scale;
use servo_arc::Arc;
use std::fmt;
use std::sync::atomic::{AtomicBool, AtomicIsize, AtomicUsize, Ordering};
use style_traits::viewport::ViewportConstraints;
use style_traits::{CSSPixel, DevicePixel};

/// The `Device` in Gecko wraps a pres context, has a default values computed,
/// and contains all the viewport rule state.
pub struct Device {
    /// NB: The document owns the styleset, who owns the stylist, and thus the
    /// `Device`, so having a raw document pointer here is fine.
    document: *const structs::Document,
    default_values: Arc<ComputedValues>,
    /// The font size of the root element
    /// This is set when computing the style of the root
    /// element, and used for rem units in other elements.
    ///
    /// When computing the style of the root element, there can't be any
    /// other style being computed at the same time, given we need the style of
    /// the parent to compute everything else. So it is correct to just use
    /// a relaxed atomic here.
    root_font_size: AtomicIsize,
    /// The body text color, stored as an `nscolor`, used for the "tables
    /// inherit from body" quirk.
    ///
    /// <https://quirks.spec.whatwg.org/#the-tables-inherit-color-from-body-quirk>
    body_text_color: AtomicUsize,
    /// Whether any styles computed in the document relied on the root font-size
    /// by using rem units.
    used_root_font_size: AtomicBool,
    /// Whether any styles computed in the document relied on the viewport size
    /// by using vw/vh/vmin/vmax units.
    used_viewport_size: AtomicBool,
    /// The CssEnvironment object responsible of getting CSS environment
    /// variables.
    environment: CssEnvironment,
}

impl fmt::Debug for Device {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use nsstring::nsCString;

        let mut doc_uri = nsCString::new();
        unsafe {
            bindings::Gecko_nsIURI_Debug(
                (*self.document()).mDocumentURI.raw::<structs::nsIURI>(),
                &mut doc_uri,
            )
        };

        f.debug_struct("Device")
            .field("document_url", &doc_uri)
            .finish()
    }
}

unsafe impl Sync for Device {}
unsafe impl Send for Device {}

impl Device {
    /// Trivially constructs a new `Device`.
    pub fn new(document: *const structs::Document) -> Self {
        assert!(!document.is_null());
        let doc = unsafe { &*document };
        let prefs = unsafe { &*bindings::Gecko_GetPrefSheetPrefs(doc) };
        Device {
            document,
            default_values: ComputedValues::default_values(doc),
            // FIXME(bz): Seems dubious?
            root_font_size: AtomicIsize::new(FontSize::medium().size().0 as isize),
            body_text_color: AtomicUsize::new(prefs.mDefaultColor as usize),
            used_root_font_size: AtomicBool::new(false),
            used_viewport_size: AtomicBool::new(false),
            environment: CssEnvironment,
        }
    }

    /// Get the relevant environment to resolve `env()` functions.
    #[inline]
    pub fn environment(&self) -> &CssEnvironment {
        &self.environment
    }

    /// Tells the device that a new viewport rule has been found, and stores the
    /// relevant viewport constraints.
    pub fn account_for_viewport_rule(&mut self, _constraints: &ViewportConstraints) {
        unreachable!("Gecko doesn't support @viewport");
    }

    /// Whether any animation name may be referenced from the style of any
    /// element.
    pub fn animation_name_may_be_referenced(&self, name: &KeyframesName) -> bool {
        let pc = match self.pres_context() {
            Some(pc) => pc,
            None => return false,
        };

        unsafe {
            bindings::Gecko_AnimationNameMayBeReferencedFromStyle(pc, name.as_atom().as_ptr())
        }
    }

    /// Returns the default computed values as a reference, in order to match
    /// Servo.
    pub fn default_computed_values(&self) -> &ComputedValues {
        &self.default_values
    }

    /// Returns the default computed values as an `Arc`.
    pub fn default_computed_values_arc(&self) -> &Arc<ComputedValues> {
        &self.default_values
    }

    /// Get the font size of the root element (for rem)
    pub fn root_font_size(&self) -> Au {
        self.used_root_font_size.store(true, Ordering::Relaxed);
        Au::new(self.root_font_size.load(Ordering::Relaxed) as i32)
    }

    /// Set the font size of the root element (for rem)
    pub fn set_root_font_size(&self, size: Au) {
        self.root_font_size
            .store(size.0 as isize, Ordering::Relaxed)
    }

    /// Sets the body text color for the "inherit color from body" quirk.
    ///
    /// <https://quirks.spec.whatwg.org/#the-tables-inherit-color-from-body-quirk>
    pub fn set_body_text_color(&self, color: RGBA) {
        self.body_text_color
            .store(convert_rgba_to_nscolor(&color) as usize, Ordering::Relaxed)
    }

    /// Returns the body text color.
    pub fn body_text_color(&self) -> RGBA {
        convert_nscolor_to_rgba(self.body_text_color.load(Ordering::Relaxed) as u32)
    }

    /// Gets the document pointer.
    #[inline]
    pub fn document(&self) -> &structs::Document {
        unsafe { &*self.document }
    }

    /// Gets the pres context associated with this document.
    #[inline]
    pub fn pres_context(&self) -> Option<&structs::nsPresContext> {
        unsafe {
            self.document()
                .mPresShell
                .as_ref()?
                .mPresContext
                .mRawPtr
                .as_ref()
        }
    }

    /// Gets the preference stylesheet prefs for our document.
    #[inline]
    pub fn pref_sheet_prefs(&self) -> &structs::PreferenceSheet_Prefs {
        unsafe { &*bindings::Gecko_GetPrefSheetPrefs(self.document()) }
    }

    /// Recreates the default computed values.
    pub fn reset_computed_values(&mut self) {
        self.default_values = ComputedValues::default_values(self.document());
    }

    /// Rebuild all the cached data.
    pub fn rebuild_cached_data(&mut self) {
        self.reset_computed_values();
        self.used_root_font_size.store(false, Ordering::Relaxed);
        self.used_viewport_size.store(false, Ordering::Relaxed);
    }

    /// Returns whether we ever looked up the root font size of the Device.
    pub fn used_root_font_size(&self) -> bool {
        self.used_root_font_size.load(Ordering::Relaxed)
    }

    /// Recreates all the temporary state that the `Device` stores.
    ///
    /// This includes the viewport override from `@viewport` rules, and also the
    /// default computed values.
    pub fn reset(&mut self) {
        self.reset_computed_values();
    }

    /// Returns the current media type of the device.
    pub fn media_type(&self) -> MediaType {
        let pc = match self.pres_context() {
            Some(pc) => pc,
            None => return MediaType::screen(),
        };

        // Gecko allows emulating random media with mMediaEmulationData.mMedium.
        let medium_to_use = if !pc.mMediaEmulationData.mMedium.mRawPtr.is_null() {
            pc.mMediaEmulationData.mMedium.mRawPtr
        } else {
            pc.mMedium as *const structs::nsAtom as *mut _
        };

        MediaType(CustomIdent(unsafe { Atom::from_raw(medium_to_use) }))
    }

    /// Returns the current viewport size in app units.
    pub fn au_viewport_size(&self) -> Size2D<Au> {
        let pc = match self.pres_context() {
            Some(pc) => pc,
            None => return Size2D::new(Au(0), Au(0)),
        };
        let area = &pc.mVisibleArea;
        Size2D::new(Au(area.width), Au(area.height))
    }

    /// Returns the current viewport size in app units, recording that it's been
    /// used for viewport unit resolution.
    pub fn au_viewport_size_for_viewport_unit_resolution(&self) -> Size2D<Au> {
        self.used_viewport_size.store(true, Ordering::Relaxed);
        self.au_viewport_size()
    }

    /// Returns whether we ever looked up the viewport size of the Device.
    pub fn used_viewport_size(&self) -> bool {
        self.used_viewport_size.load(Ordering::Relaxed)
    }

    /// Returns the device pixel ratio.
    pub fn device_pixel_ratio(&self) -> Scale<f32, CSSPixel, DevicePixel> {
        let pc = match self.pres_context() {
            Some(pc) => pc,
            None => return Scale::new(1.),
        };

        if pc.mMediaEmulationData.mDPPX > 0.0 {
            return Scale::new(pc.mMediaEmulationData.mDPPX);
        }

        let au_per_dpx = pc.mCurAppUnitsPerDevPixel as f32;
        let au_per_px = AU_PER_PX as f32;
        Scale::new(au_per_px / au_per_dpx)
    }

    /// Returns whether document colors are enabled.
    #[inline]
    pub fn use_document_colors(&self) -> bool {
        let doc = self.document();
        if doc.mIsBeingUsedAsImage() {
            return true;
        }
        let document_color_use =
            unsafe { structs::StaticPrefs::sVarCache_browser_display_document_color_use };
        let prefs = self.pref_sheet_prefs();
        match document_color_use {
            1 => true,
            2 => prefs.mIsChrome,
            _ => !prefs.mUseAccessibilityTheme,
        }
    }

    /// Returns the default background color.
    pub fn default_background_color(&self) -> RGBA {
        convert_nscolor_to_rgba(self.pref_sheet_prefs().mDefaultBackgroundColor)
    }

    /// Returns the current effective text zoom.
    #[inline]
    fn effective_text_zoom(&self) -> f32 {
        let pc = match self.pres_context() {
            Some(pc) => pc,
            None => return 1.,
        };
        pc.mEffectiveTextZoom
    }

    /// Applies text zoom to a font-size or line-height value (see nsStyleFont::ZoomText).
    #[inline]
    pub fn zoom_text(&self, size: Au) -> Au {
        size.scale_by(self.effective_text_zoom())
    }

    /// Un-apply text zoom.
    #[inline]
    pub fn unzoom_text(&self, size: Au) -> Au {
        size.scale_by(1. / self.effective_text_zoom())
    }
}
<|endoftext|>


<commit_before>// APIs that changed in FreeBSD12

pub type nlink_t = u64;
pub type dev_t = u64;
pub type ino_t = ::c_ulong;
pub type shmatt_t = ::c_uint;

s! {
    pub struct shmid_ds {
        pub shm_perm: ::ipc_perm,
        pub shm_segsz: ::size_t,
        pub shm_lpid: ::pid_t,
        pub shm_cpid: ::pid_t,
        pub shm_nattch: ::shmatt_t,
        pub shm_atime: ::time_t,
        pub shm_dtime: ::time_t,
        pub shm_ctime: ::time_t,
    }

    pub struct kevent {
        pub ident: ::uintptr_t,
        pub filter: ::c_short,
        pub flags: ::c_ushort,
        pub fflags: ::c_uint,
        pub data: ::intptr_t,
        pub udata: *mut ::c_void,
        pub ext: [u64; 4],
    }
}

s_no_extra_traits! {
    pub struct dirent {
        pub d_fileno: ::ino_t,
        pub d_off: ::off_t,
        pub d_reclen: u16,
        pub d_type: u8,
        d_pad0: u8,
        pub d_namlen: u16,
        d_pad1: u16,
        pub d_name: [::c_char; 256],
    }

    pub struct statfs {
        pub f_version: u32,
        pub f_type: u32,
        pub f_flags: u64,
        pub f_bsize: u64,
        pub f_iosize: u64,
        pub f_blocks: u64,
        pub f_bfree: u64,
        pub f_bavail: i64,
        pub f_files: u64,
        pub f_ffree: i64,
        pub f_syncwrites: u64,
        pub f_asyncwrites: u64,
        pub f_syncreads: u64,
        pub f_asyncreads: u64,
        f_spare: [u64; 10],
        pub f_namemax: u32,
        pub f_owner: ::uid_t,
        pub f_fsid: ::fsid_t,
        f_charspare: [::c_char; 80],
        pub f_fstypename: [::c_char; 16],
        pub f_mntfromname: [::c_char; 1024],
        pub f_mntonname: [::c_char; 1024],
    }
}

cfg_if! {
    if #[cfg(feature = "extra_traits")] {
        impl PartialEq for statfs {
            fn eq(&self, other: &statfs) -> bool {
                self.f_version == other.f_version
                    && self.f_type == other.f_type
                    && self.f_flags == other.f_flags
                    && self.f_bsize == other.f_bsize
                    && self.f_iosize == other.f_iosize
                    && self.f_blocks == other.f_blocks
                    && self.f_bfree == other.f_bfree
                    && self.f_bavail == other.f_bavail
                    && self.f_files == other.f_files
                    && self.f_ffree == other.f_ffree
                    && self.f_syncwrites == other.f_syncwrites
                    && self.f_asyncwrites == other.f_asyncwrites
                    && self.f_syncreads == other.f_syncreads
                    && self.f_asyncreads == other.f_asyncreads
                    && self.f_namemax == other.f_namemax
                    && self.f_owner == other.f_owner
                    && self.f_fsid == other.f_fsid
                    && self.f_fstypename == other.f_fstypename
                    && self
                    .f_mntfromname
                    .iter()
                    .zip(other.f_mntfromname.iter())
                    .all(|(a,b)| a == b)
                    && self
                    .f_mntonname
                    .iter()
                    .zip(other.f_mntonname.iter())
                    .all(|(a,b)| a == b)
            }
        }
        impl Eq for statfs {}
        impl ::fmt::Debug for statfs {
            fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
                f.debug_struct("statfs")
                    .field("f_bsize", &self.f_bsize)
                    .field("f_iosize", &self.f_iosize)
                    .field("f_blocks", &self.f_blocks)
                    .field("f_bfree", &self.f_bfree)
                    .field("f_bavail", &self.f_bavail)
                    .field("f_files", &self.f_files)
                    .field("f_ffree", &self.f_ffree)
                    .field("f_syncwrites", &self.f_syncwrites)
                    .field("f_asyncwrites", &self.f_asyncwrites)
                    .field("f_syncreads", &self.f_syncreads)
                    .field("f_asyncreads", &self.f_asyncreads)
                    .field("f_namemax", &self.f_namemax)
                    .field("f_owner", &self.f_owner)
                    .field("f_fsid", &self.f_fsid)
                    .field("f_fstypename", &self.f_fstypename)
                    .field("f_mntfromname", &&self.f_mntfromname[..])
                    .field("f_mntonname", &&self.f_mntonname[..])
                    .finish()
            }
        }
        impl ::hash::Hash for statfs {
            fn hash<H: ::hash::Hasher>(&self, state: &mut H) {
                self.f_version.hash(state);
                self.f_type.hash(state);
                self.f_flags.hash(state);
                self.f_bsize.hash(state);
                self.f_iosize.hash(state);
                self.f_blocks.hash(state);
                self.f_bfree.hash(state);
                self.f_bavail.hash(state);
                self.f_files.hash(state);
                self.f_ffree.hash(state);
                self.f_syncwrites.hash(state);
                self.f_asyncwrites.hash(state);
                self.f_syncreads.hash(state);
                self.f_asyncreads.hash(state);
                self.f_namemax.hash(state);
                self.f_owner.hash(state);
                self.f_fsid.hash(state);
                self.f_charspare.hash(state);
                self.f_fstypename.hash(state);
                self.f_mntfromname.hash(state);
                self.f_mntonname.hash(state);
            }
        }

        impl PartialEq for dirent {
            fn eq(&self, other: &dirent) -> bool {
                self.d_fileno == other.d_fileno
                    && self.d_off == other.d_off
                    && self.d_reclen == other.d_reclen
                    && self.d_type == other.d_type
                    && self.d_namlen == other.d_namlen
                    && self
                    .d_name[..self.d_namlen as _]
                    .iter()
                    .zip(other.d_name.iter())
                    .all(|(a,b)| a == b)
            }
        }
        impl Eq for dirent {}
        impl ::fmt::Debug for dirent {
            fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
                f.debug_struct("dirent")
                    .field("d_fileno", &self.d_fileno)
                    .field("d_off", &self.d_off)
                    .field("d_reclen", &self.d_reclen)
                    .field("d_type", &self.d_type)
                    .field("d_namlen", &self.d_namlen)
                    .field("d_name", &&self.d_name[..self.d_namlen as _])
                    .finish()
            }
        }
        impl ::hash::Hash for dirent {
            fn hash<H: ::hash::Hasher>(&self, state: &mut H) {
                self.d_fileno.hash(state);
                self.d_off.hash(state);
                self.d_reclen.hash(state);
                self.d_type.hash(state);
                self.d_namlen.hash(state);
                self.d_name[..self.d_namlen as _].hash(state);
            }
        }
    }
}

#[cfg(not(freebsd13))]
pub const ELAST: ::c_int = 96;
#[cfg(freebsd13)]
pub const ELAST: ::c_int = 97;

extern {
    pub fn setgrent();
    pub fn mprotect(addr: *mut ::c_void, len: ::size_t, prot: ::c_int)
                    -> ::c_int;
    pub fn freelocale(loc: ::locale_t);
    pub fn msgrcv(msqid: ::c_int, msgp: *mut ::c_void, msgsz: ::size_t,
                  msgtyp: ::c_long, msgflg: ::c_int) -> ::ssize_t;
}

cfg_if! {
    if #[cfg(target_arch = "x86_64")] {
        mod x86_64;
        pub use self::x86_64::*;
    }
}
<commit_msg>Add EINTEGRITY errno and fix style<commit_after>// APIs that changed in FreeBSD12

pub type nlink_t = u64;
pub type dev_t = u64;
pub type ino_t = ::c_ulong;
pub type shmatt_t = ::c_uint;

s! {
    pub struct shmid_ds {
        pub shm_perm: ::ipc_perm,
        pub shm_segsz: ::size_t,
        pub shm_lpid: ::pid_t,
        pub shm_cpid: ::pid_t,
        pub shm_nattch: ::shmatt_t,
        pub shm_atime: ::time_t,
        pub shm_dtime: ::time_t,
        pub shm_ctime: ::time_t,
    }

    pub struct kevent {
        pub ident: ::uintptr_t,
        pub filter: ::c_short,
        pub flags: ::c_ushort,
        pub fflags: ::c_uint,
        pub data: ::intptr_t,
        pub udata: *mut ::c_void,
        pub ext: [u64; 4],
    }
}

s_no_extra_traits! {
    pub struct dirent {
        pub d_fileno: ::ino_t,
        pub d_off: ::off_t,
        pub d_reclen: u16,
        pub d_type: u8,
        d_pad0: u8,
        pub d_namlen: u16,
        d_pad1: u16,
        pub d_name: [::c_char; 256],
    }

    pub struct statfs {
        pub f_version: u32,
        pub f_type: u32,
        pub f_flags: u64,
        pub f_bsize: u64,
        pub f_iosize: u64,
        pub f_blocks: u64,
        pub f_bfree: u64,
        pub f_bavail: i64,
        pub f_files: u64,
        pub f_ffree: i64,
        pub f_syncwrites: u64,
        pub f_asyncwrites: u64,
        pub f_syncreads: u64,
        pub f_asyncreads: u64,
        f_spare: [u64; 10],
        pub f_namemax: u32,
        pub f_owner: ::uid_t,
        pub f_fsid: ::fsid_t,
        f_charspare: [::c_char; 80],
        pub f_fstypename: [::c_char; 16],
        pub f_mntfromname: [::c_char; 1024],
        pub f_mntonname: [::c_char; 1024],
    }
}

cfg_if! {
    if #[cfg(feature = "extra_traits")] {
        impl PartialEq for statfs {
            fn eq(&self, other: &statfs) -> bool {
                self.f_version == other.f_version
                    && self.f_type == other.f_type
                    && self.f_flags == other.f_flags
                    && self.f_bsize == other.f_bsize
                    && self.f_iosize == other.f_iosize
                    && self.f_blocks == other.f_blocks
                    && self.f_bfree == other.f_bfree
                    && self.f_bavail == other.f_bavail
                    && self.f_files == other.f_files
                    && self.f_ffree == other.f_ffree
                    && self.f_syncwrites == other.f_syncwrites
                    && self.f_asyncwrites == other.f_asyncwrites
                    && self.f_syncreads == other.f_syncreads
                    && self.f_asyncreads == other.f_asyncreads
                    && self.f_namemax == other.f_namemax
                    && self.f_owner == other.f_owner
                    && self.f_fsid == other.f_fsid
                    && self.f_fstypename == other.f_fstypename
                    && self
                    .f_mntfromname
                    .iter()
                    .zip(other.f_mntfromname.iter())
                    .all(|(a,b)| a == b)
                    && self
                    .f_mntonname
                    .iter()
                    .zip(other.f_mntonname.iter())
                    .all(|(a,b)| a == b)
            }
        }
        impl Eq for statfs {}
        impl ::fmt::Debug for statfs {
            fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
                f.debug_struct("statfs")
                    .field("f_bsize", &self.f_bsize)
                    .field("f_iosize", &self.f_iosize)
                    .field("f_blocks", &self.f_blocks)
                    .field("f_bfree", &self.f_bfree)
                    .field("f_bavail", &self.f_bavail)
                    .field("f_files", &self.f_files)
                    .field("f_ffree", &self.f_ffree)
                    .field("f_syncwrites", &self.f_syncwrites)
                    .field("f_asyncwrites", &self.f_asyncwrites)
                    .field("f_syncreads", &self.f_syncreads)
                    .field("f_asyncreads", &self.f_asyncreads)
                    .field("f_namemax", &self.f_namemax)
                    .field("f_owner", &self.f_owner)
                    .field("f_fsid", &self.f_fsid)
                    .field("f_fstypename", &self.f_fstypename)
                    .field("f_mntfromname", &&self.f_mntfromname[..])
                    .field("f_mntonname", &&self.f_mntonname[..])
                    .finish()
            }
        }
        impl ::hash::Hash for statfs {
            fn hash<H: ::hash::Hasher>(&self, state: &mut H) {
                self.f_version.hash(state);
                self.f_type.hash(state);
                self.f_flags.hash(state);
                self.f_bsize.hash(state);
                self.f_iosize.hash(state);
                self.f_blocks.hash(state);
                self.f_bfree.hash(state);
                self.f_bavail.hash(state);
                self.f_files.hash(state);
                self.f_ffree.hash(state);
                self.f_syncwrites.hash(state);
                self.f_asyncwrites.hash(state);
                self.f_syncreads.hash(state);
                self.f_asyncreads.hash(state);
                self.f_namemax.hash(state);
                self.f_owner.hash(state);
                self.f_fsid.hash(state);
                self.f_charspare.hash(state);
                self.f_fstypename.hash(state);
                self.f_mntfromname.hash(state);
                self.f_mntonname.hash(state);
            }
        }

        impl PartialEq for dirent {
            fn eq(&self, other: &dirent) -> bool {
                self.d_fileno == other.d_fileno
                    && self.d_off == other.d_off
                    && self.d_reclen == other.d_reclen
                    && self.d_type == other.d_type
                    && self.d_namlen == other.d_namlen
                    && self
                    .d_name[..self.d_namlen as _]
                    .iter()
                    .zip(other.d_name.iter())
                    .all(|(a,b)| a == b)
            }
        }
        impl Eq for dirent {}
        impl ::fmt::Debug for dirent {
            fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
                f.debug_struct("dirent")
                    .field("d_fileno", &self.d_fileno)
                    .field("d_off", &self.d_off)
                    .field("d_reclen", &self.d_reclen)
                    .field("d_type", &self.d_type)
                    .field("d_namlen", &self.d_namlen)
                    .field("d_name", &&self.d_name[..self.d_namlen as _])
                    .finish()
            }
        }
        impl ::hash::Hash for dirent {
            fn hash<H: ::hash::Hasher>(&self, state: &mut H) {
                self.d_fileno.hash(state);
                self.d_off.hash(state);
                self.d_reclen.hash(state);
                self.d_type.hash(state);
                self.d_namlen.hash(state);
                self.d_name[..self.d_namlen as _].hash(state);
            }
        }
    }
}

cfg_if! {
    if #[cfg(not(freebsd13))] {
        pub const ELAST: ::c_int = 96;
    } else {
        pub const EINTEGRITY: ::c_int = 97;
        pub const ELAST: ::c_int = 97;
    }
}

extern {
    pub fn setgrent();
    pub fn mprotect(addr: *mut ::c_void, len: ::size_t, prot: ::c_int)
                    -> ::c_int;
    pub fn freelocale(loc: ::locale_t);
    pub fn msgrcv(msqid: ::c_int, msgp: *mut ::c_void, msgsz: ::size_t,
                  msgtyp: ::c_long, msgflg: ::c_int) -> ::ssize_t;
}

cfg_if! {
    if #[cfg(target_arch = "x86_64")] {
        mod x86_64;
        pub use self::x86_64::*;
    }
}
<|endoftext|>