/* This Source Code Form is subject to the terms of the Mozilla Public *License,v.2.0.IfacopyoftheMPLwasnotdistributedwiththis
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
//! Gecko-specific logic for [`Device`].
usecrate::color::AbsoluteColor; usecrate::context::QuirksMode; usecrate::custom_properties::CssEnvironment; usecrate::device::Device; usecrate::font_metrics::FontMetrics; usecrate::gecko::wrapper::GeckoElement; usecrate::gecko_bindings::bindings; usecrate::gecko_bindings::structs; usecrate::logical_geometry::WritingMode; usecrate::media_queries::MediaType; usecrate::properties::ComputedValues; usecrate::string_cache::Atom; usecrate::values::computed::font::GenericFontFamily; usecrate::values::computed::{ColorScheme, Length, NonNegativeLength}; usecrate::values::specified::color::{ColorSchemeFlags, ForcedColors, SystemColor}; usecrate::values::specified::font::{
QueryFontMetricsFlags, FONT_MEDIUM_CAP_PX, FONT_MEDIUM_CH_PX, FONT_MEDIUM_EX_PX,
FONT_MEDIUM_IC_PX, FONT_MEDIUM_LINE_HEIGHT_PX, FONT_MEDIUM_PX,
}; usecrate::values::specified::ViewportVariant; usecrate::values::{CustomIdent, KeyframesName}; use app_units::{Au, AU_PER_PX}; use euclid::default::Size2D; use euclid::{Scale, SideOffsets2D}; use parking_lot::RwLock; use servo_arc::Arc; use std::sync::atomic::{AtomicBool, AtomicU32, Ordering}; use std::{cmp, fmt}; use style_traits::{CSSPixel, DevicePixel};
pub(super) struct ExtraDeviceData { /// 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,
}
unsafeimpl Sync for Device {} unsafeimpl Send for Device {}
impl Device { /// Trivially constructs a new `Device`. pubfn new(document: *const structs::Document) -> Self {
assert!(!document.is_null()); let doc = unsafe { &*document }; let prefs = unsafe { &*bindings::Gecko_GetPrefSheetPrefs(doc) }; let default_values = ComputedValues::default_values(doc); let root_style = RwLock::new(Arc::clone(&default_values));
Device {
default_values: default_values,
root_style: root_style,
root_font_size: AtomicU32::new(FONT_MEDIUM_PX.to_bits()),
root_line_height: AtomicU32::new(FONT_MEDIUM_LINE_HEIGHT_PX.to_bits()),
root_font_metrics_ex: AtomicU32::new(FONT_MEDIUM_EX_PX.to_bits()),
root_font_metrics_cap: AtomicU32::new(FONT_MEDIUM_CAP_PX.to_bits()),
root_font_metrics_ch: AtomicU32::new(FONT_MEDIUM_CH_PX.to_bits()),
root_font_metrics_ic: AtomicU32::new(FONT_MEDIUM_IC_PX.to_bits()),
used_root_font_size: AtomicBool::new(false),
used_root_line_height: AtomicBool::new(false),
used_root_font_metrics: RwLock::new(false),
used_font_metrics: AtomicBool::new(false),
used_viewport_size: AtomicBool::new(false),
used_dynamic_viewport_size: AtomicBool::new(false),
environment: CssEnvironment, // This gets updated when we see the <body>, so it doesn't really // matter which color-scheme we look at here.
body_text_color: AtomicU32::new(prefs.mLightColors.mDefault),
extra: ExtraDeviceData { document },
}
}
/// Returns the computed line-height for the font in a given computed values instance. /// /// If you pass down an element, then the used line-height is returned. pubfn calc_line_height(
&self,
font: &crate::properties::style_structs::Font,
writing_mode: WritingMode,
element: Option<GeckoElement>,
) -> NonNegativeLength { let pres_context = self.pres_context(); let line_height = font.clone_line_height(); let au = Au(unsafe {
bindings::Gecko_CalcLineHeight(
&line_height,
pres_context.map_or(std::ptr::null(), |pc| pc),
writing_mode.is_text_vertical(),
&**font,
element.map_or(std::ptr::null(), |e| e.0),
)
});
NonNegativeLength::new(au.to_f32_px())
}
/// Whether any animation name may be referenced from the style of any /// element. pubfn animation_name_may_be_referenced(&self, name: &KeyframesName) -> bool { let pc = matchself.pres_context() {
Some(pc) => pc,
None => returnfalse,
};
/// The quirks mode of the document. pubfn quirks_mode(&self) -> QuirksMode { self.document().mCompatMode.into()
}
/// Gets the base size given a generic font family and a language. pubfn base_size_for_generic(&self, language: &Atom, generic: GenericFontFamily) -> Length { unsafe { bindings::Gecko_GetBaseSize(self.document(), language.as_ptr(), generic) }
}
/// Gets the size of the scrollbar in CSS pixels. pubfn scrollbar_inline_size(&self) -> Length { let pc = matchself.pres_context() {
Some(pc) => pc, // XXX: we could have a more reasonable default perhaps.
None => return Length::new(0.0),
};
Length::new(unsafe { bindings::Gecko_GetScrollbarInlineSize(pc) })
}
/// Recreates all the temporary state that the `Device` stores. /// /// This includes the viewport override from `@viewport` rules, and also the /// default computed values. pubfn reset(&mutself) { self.reset_computed_values();
}
/// Returns whether this document is in print preview. pubfn is_print_preview(&self) -> bool { let pc = matchself.pres_context() {
Some(pc) => pc,
None => returnfalse,
};
pc.mType == structs::nsPresContext_nsPresContextType_eContext_PrintPreview
}
/// Returns the current media type of the device. pubfn media_type(&self) -> MediaType { let pc = matchself.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 _
};
// It may make sense to account for @page rule margins here somehow, however // it's not clear how that'd work, see: // https://github.com/w3c/csswg-drafts/issues/5437 fn page_size_minus_default_margin(&self, pc: &structs::nsPresContext) -> Size2D<Au> {
debug_assert!(pc.mIsRootPaginatedDocument() != 0); let area = &pc.mPageSize; let margin = &pc.mDefaultPageMargin; let width = area.width - margin.left - margin.right; let height = area.height - margin.top - margin.bottom;
Size2D::new(Au(cmp::max(width, 0)), Au(cmp::max(height, 0)))
}
/// Returns the current viewport size in app units. pubfn au_viewport_size(&self) -> Size2D<Au> { let pc = matchself.pres_context() {
Some(pc) => pc,
None => return Size2D::new(Au(0), Au(0)),
};
if pc.mIsRootPaginatedDocument() != 0 { returnself.page_size_minus_default_margin(pc);
}
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. pubfn au_viewport_size_for_viewport_unit_resolution(
&self,
variant: ViewportVariant,
) -> Size2D<Au> { self.used_viewport_size.store(true, Ordering::Relaxed); let pc = matchself.pres_context() {
Some(pc) => pc,
None => return Size2D::new(Au(0), Au(0)),
};
if pc.mIsRootPaginatedDocument() != 0 { returnself.page_size_minus_default_margin(pc);
}
match variant {
ViewportVariant::UADefault => { let size = &pc.mSizeForViewportUnits;
Size2D::new(Au(size.width), Au(size.height))
},
ViewportVariant::Small => { let size = &pc.mVisibleArea;
Size2D::new(Au(size.width), Au(size.height))
},
ViewportVariant::Large => { let size = &pc.mVisibleArea; // Looks like IntCoordTyped is treated as if it's u32 in Rust.
debug_assert!( /* pc.mDynamicToolbarMaxHeight >=0 && */
pc.mDynamicToolbarMaxHeight < i32::MAX as u32
);
Size2D::new(
Au(size.width),
Au(size.height
+ pc.mDynamicToolbarMaxHeight as i32 * pc.mCurAppUnitsPerDevPixel),
)
},
ViewportVariant::Dynamic => { self.used_dynamic_viewport_size
.store(true, Ordering::Relaxed); let size = &pc.mVisibleArea; // Looks like IntCoordTyped is treated as if it's u32 in Rust.
debug_assert!( /* pc.mDynamicToolbarHeight >=0 && */
pc.mDynamicToolbarHeight < i32::MAX as u32
);
Size2D::new(
Au(size.width),
Au(size.height
+ (pc.mDynamicToolbarMaxHeight - pc.mDynamicToolbarHeight) as i32
* pc.mCurAppUnitsPerDevPixel),
)
},
}
}
/// Returns the number of app units per device pixel we're using currently. pubfn app_units_per_device_pixel(&self) -> i32 { matchself.pres_context() {
Some(pc) => pc.mCurAppUnitsPerDevPixel,
None => AU_PER_PX,
}
}
/// Returns app units per pixel at 1x full-zoom. fn app_units_per_device_pixel_at_unit_full_zoom(&self) -> i32 { matchself.pres_context() {
Some(pc) => unsafe { (*pc.mDeviceContext.mRawPtr).mAppUnitsPerDevPixelAtUnitFullZoom },
None => AU_PER_PX,
}
}
/// Returns the device pixel ratio, ignoring the full zoom factor. pubfn device_pixel_ratio_ignoring_full_zoom(&self) -> Scale<f32, CSSPixel, DevicePixel> { let au_per_px = AU_PER_PX as f32;
Scale::new(au_per_px / self.app_units_per_device_pixel_at_unit_full_zoom() as f32)
}
/// Returns the device pixel ratio. pubfn device_pixel_ratio(&self) -> Scale<f32, CSSPixel, DevicePixel> { let pc = matchself.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)
}
/// Computes a system color and returns it as an nscolor. pub(crate) fn system_nscolor(
&self,
system_color: SystemColor,
color_scheme: ColorSchemeFlags,
) -> u32 { unsafe { bindings::Gecko_ComputeSystemColor(system_color, self.document(), &color_scheme) }
}
/// Returns whether the used color-scheme for `color-scheme` should be dark. pub(crate) fn is_dark_color_scheme(&self, color_scheme: ColorSchemeFlags) -> bool { unsafe { bindings::Gecko_IsDarkColorScheme(self.document(), &color_scheme) }
}
/// Returns the default background color. /// /// This is only for forced-colors/high-contrast, so looking at light colors /// is ok. pubfn default_background_color(&self) -> AbsoluteColor {
AbsoluteColor::from_nscolor( self.system_nscolor(SystemColor::Canvas, ColorScheme::normal().bits),
)
}
/// Returns the default foreground color. /// /// See above for looking at light colors only. pubfn default_color(&self) -> AbsoluteColor {
AbsoluteColor::from_nscolor( self.system_nscolor(SystemColor::Canvastext, ColorScheme::normal().bits),
)
}
/// Returns the current effective text zoom. #[inline] fn text_zoom(&self) -> f32 { let pc = matchself.pres_context() {
Some(pc) => pc,
None => return1.,
};
pc.mTextZoom
}
/// Applies text zoom to a font-size or line-height value (see nsStyleFont::ZoomText). #[inline] pubfn zoom_text(&self, size: Length) -> Length {
size.scale_by(self.text_zoom())
}
/// Returns safe area insets pubfn safe_area_insets(&self) -> SideOffsets2D<f32, CSSPixel> { let pc = matchself.pres_context() {
Some(pc) => pc,
None => return SideOffsets2D::zero(),
}; letmut top = 0.0; letmut right = 0.0; letmut bottom = 0.0; letmut left = 0.0; unsafe {
bindings::Gecko_GetSafeAreaInsets(pc, &mut top, &mut right, &mut bottom, &mut left)
};
SideOffsets2D::new(top, right, bottom, left)
}
/// Returns true if the given MIME type is supported pubfn is_supported_mime_type(&self, mime_type: &str) -> bool { unsafe {
bindings::Gecko_IsSupportedImageMimeType(mime_type.as_ptr(), mime_type.len() as u32)
}
}
/// Return whether the document is a chrome document. /// /// This check is consistent with how we enable chrome rules for chrome:// and resource:// /// stylesheets (and thus chrome:// documents). #[inline] pubfn chrome_rules_enabled_for_document(&self) -> bool { self.document().mChromeRulesEnabled()
}
}
impl fmt::Debug for Device { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { use nsstring::nsCString;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.