use api::{
ColorF, ColorU, RasterSpace,
LineOrientation, LineStyle, PremultipliedColorF, Shadow,
};
use api::units::*;
use crate::scene_building::{CreateShadow, IsVisible};
use crate::frame_builder::{FrameBuildingState};
use crate::gpu_cache::GpuDataRequest;
use crate::intern;
use crate::internal_types::LayoutPrimitiveInfo;
use crate::prim_store::{
PrimKey, PrimTemplate, PrimTemplateCommonData,
InternablePrimitive, PrimitiveStore,
};
use crate::prim_store::PrimitiveInstanceKind;
pub const MAX_LINE_DECORATION_RESOLUTION: u32 = 4096;
#[derive(Clone, Debug, Hash, MallocSizeOf, PartialEq, Eq)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct LineDecorationCacheKey {
pub style: LineStyle,
pub orientation: LineOrientation,
pub wavy_line_thickness: Au,
pub size: LayoutSizeAu,
}
#[derive(Clone, Debug, Hash, MallocSizeOf, PartialEq, Eq)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct LineDecoration {
pub cache_key: Option<LineDecorationCacheKey>,
pub color: ColorU,
}
pub type LineDecorationKey = PrimKey<LineDecoration>;
impl LineDecorationKey {
pub fn new(
info: &LayoutPrimitiveInfo,
line_dec: LineDecoration,
) -> Self {
LineDecorationKey {
common: info.into(),
kind: line_dec,
}
}
}
impl intern::InternDebug for LineDecorationKey {}
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(MallocSizeOf)]
pub struct LineDecorationData {
pub cache_key: Option<LineDecorationCacheKey>,
pub color: ColorF,
}
impl LineDecorationData {
pub fn update(
&mut self,
common: &mut PrimTemplateCommonData,
frame_state: &mut FrameBuildingState,
) {
if let Some(ref mut request) = frame_state.gpu_cache.request(&mut common.gpu_cache_handle) {
self.write_prim_gpu_blocks(request);
}
}
fn write_prim_gpu_blocks(
&self,
request: &mut GpuDataRequest
) {
match self.cache_key.as_ref() {
Some(cache_key) => {
request.push(self.color.premultiplied());
request.push(PremultipliedColorF::WHITE);
request.push([
cache_key.size.width.to_f32_px(),
cache_key.size.height.to_f32_px(),
0.0,
0.0,
]);
}
None => {
request.push(self.color.premultiplied());
}
}
}
}
pub type LineDecorationTemplate = PrimTemplate<LineDecorationData>;
impl From<LineDecorationKey> for LineDecorationTemplate {
fn from(line_dec: LineDecorationKey) -> Self {
let common = PrimTemplateCommonData::with_key_common(line_dec.common);
LineDecorationTemplate {
common,
kind: LineDecorationData {
cache_key: line_dec.kind.cache_key,
color: line_dec.kind.color.into(),
}
}
}
}
pub type LineDecorationDataHandle = intern::Handle<LineDecoration>;
impl intern::Internable for LineDecoration {
type Key = LineDecorationKey;
type StoreData = LineDecorationTemplate;
type InternData = ();
const PROFILE_COUNTER: usize = crate::profiler::INTERNED_LINE_DECORATIONS;
}
impl InternablePrimitive for LineDecoration {
fn into_key(
self,
info: &LayoutPrimitiveInfo,
) -> LineDecorationKey {
LineDecorationKey::new(
info,
self,
)
}
fn make_instance_kind(
_key: LineDecorationKey,
data_handle: LineDecorationDataHandle,
_: &mut PrimitiveStore,
) -> PrimitiveInstanceKind {
PrimitiveInstanceKind::LineDecoration {
data_handle,
render_task: None,
}
}
}
impl CreateShadow for LineDecoration {
fn create_shadow(
&self,
shadow: &Shadow,
_: bool,
_: RasterSpace,
) -> Self {
LineDecoration {
color: shadow.color.into(),
cache_key: self.cache_key.clone(),
}
}
}
impl IsVisible for LineDecoration {
fn is_visible(&self) -> bool {
self.color.a > 0
}
}
pub fn get_line_decoration_size(
rect_size: &LayoutSize,
orientation: LineOrientation,
style: LineStyle,
wavy_line_thickness: f32,
) -> Option<LayoutSize> {
let h = match orientation {
LineOrientation::Horizontal => rect_size.height,
LineOrientation::Vertical => rect_size.width,
};
let (parallel, perpendicular) = match style {
LineStyle::Solid => {
return None;
}
LineStyle::Dashed => {
let dash_length = (3.0 * h).min(64.0).max(1.0);
(2.0 * dash_length, 4.0)
}
LineStyle::Dotted => {
let diameter = h.min(64.0).max(1.0);
let period = 2.0 * diameter;
(period, diameter)
}
LineStyle::Wavy => {
let line_thickness = wavy_line_thickness.max(1.0);
let slope_length = h - line_thickness;
let flat_length = ((line_thickness - 1.0) * 2.0).max(1.0);
let approx_period = 2.0 * (slope_length + flat_length);
(approx_period, h)
}
};
Some(match orientation {
LineOrientation::Horizontal => LayoutSize::new(parallel, perpendicular),
LineOrientation::Vertical => LayoutSize::new(perpendicular, parallel),
})
}
#[test]
#[cfg(target_pointer_width = "64")]
fn test_struct_sizes() {
use std::mem;
assert_eq!(mem::size_of::<LineDecoration>(), 20, "LineDecoration size changed");
assert_eq!(mem::size_of::<LineDecorationTemplate>(), 60, "LineDecorationTemplate size changed");
assert_eq!(mem::size_of::<LineDecorationKey>(), 40, "LineDecorationKey size changed");
}