extern crate serde_bytes;
use app_units::Au;
use channel::{self, MsgSender, Payload, PayloadSender, PayloadSenderHelperMethods};
use std::cell::Cell;
use std::fmt;
use std::marker::PhantomData;
use std::os::raw::c_void;
use std::path::PathBuf;
use std::sync::Arc;
use std::u32;
use {display_item as di, font};
use color::ColorF;
use display_list::{BuiltDisplayList, BuiltDisplayListDescriptor};
use image::{BlobImageData, BlobImageKey, ImageData, ImageDescriptor, ImageKey};
use units::*;
pub type TileSize = u16;
pub type DocumentLayer = i8;
#[derive(Clone, Deserialize, Serialize)]
pub enum ResourceUpdate {
AddImage(AddImage),
UpdateImage(UpdateImage),
AddBlobImage(AddBlobImage),
UpdateBlobImage(UpdateBlobImage),
DeleteImage(ImageKey),
SetBlobImageVisibleArea(BlobImageKey, DeviceIntRect),
AddFont(AddFont),
DeleteFont(font::FontKey),
AddFontInstance(AddFontInstance),
DeleteFontInstance(font::FontInstanceKey),
}
pub struct Transaction {
scene_ops: Vec<SceneMsg>,
frame_ops: Vec<FrameMsg>,
payloads: Vec<Payload>,
notifications: Vec<NotificationRequest>,
pub resource_updates: Vec<ResourceUpdate>,
use_scene_builder_thread: bool,
generate_frame: bool,
invalidate_rendered_frame: bool,
low_priority: bool,
}
impl Transaction {
pub fn new() -> Self {
Transaction {
scene_ops: Vec::new(),
frame_ops: Vec::new(),
resource_updates: Vec::new(),
payloads: Vec::new(),
notifications: Vec::new(),
use_scene_builder_thread: true,
generate_frame: false,
invalidate_rendered_frame: false,
low_priority: false,
}
}
pub fn skip_scene_builder(&mut self) {
self.use_scene_builder_thread = false;
}
pub fn use_scene_builder_thread(&mut self) {
self.use_scene_builder_thread = true;
}
pub fn is_empty(&self) -> bool {
!self.generate_frame &&
!self.invalidate_rendered_frame &&
self.scene_ops.is_empty() &&
self.frame_ops.is_empty() &&
self.resource_updates.is_empty() &&
self.notifications.is_empty()
}
pub fn update_epoch(&mut self, pipeline_id: PipelineId, epoch: Epoch) {
self.scene_ops.push(SceneMsg::UpdateEpoch(pipeline_id, epoch));
self.frame_ops.push(FrameMsg::UpdateEpoch(pipeline_id, epoch));
}
pub fn set_root_pipeline(&mut self, pipeline_id: PipelineId) {
self.scene_ops.push(SceneMsg::SetRootPipeline(pipeline_id));
}
pub fn remove_pipeline(&mut self, pipeline_id: PipelineId) {
self.scene_ops.push(SceneMsg::RemovePipeline(pipeline_id));
}
pub fn set_display_list(
&mut self,
epoch: Epoch,
background: Option<ColorF>,
viewport_size: LayoutSize,
(pipeline_id, content_size, display_list): (PipelineId, LayoutSize, BuiltDisplayList),
preserve_frame_state: bool,
) {
let (display_list_data, list_descriptor) = display_list.into_data();
self.scene_ops.push(
SceneMsg::SetDisplayList {
epoch,
pipeline_id,
background,
viewport_size,
content_size,
list_descriptor,
preserve_frame_state,
}
);
self.payloads.push(Payload { epoch, pipeline_id, display_list_data });
}
pub fn update_resources(&mut self, resources: Vec<ResourceUpdate>) {
self.merge(resources);
}
pub fn notify(&mut self, event: NotificationRequest) {
self.notifications.push(event);
}
pub fn set_window_parameters(
&mut self,
window_size: DeviceIntSize,
inner_rect: DeviceIntRect,
device_pixel_ratio: f32,
) {
self.scene_ops.push(
SceneMsg::SetWindowParameters {
window_size,
inner_rect,
device_pixel_ratio,
},
);
}
pub fn scroll(&mut self, scroll_location: ScrollLocation, cursor: WorldPoint) {
self.frame_ops.push(FrameMsg::Scroll(scroll_location, cursor));
}
pub fn scroll_node_with_id(
&mut self,
origin: LayoutPoint,
id: di::ExternalScrollId,
clamp: ScrollClamping,
) {
self.frame_ops.push(FrameMsg::ScrollNodeWithId(origin, id, clamp));
}
pub fn set_page_zoom(&mut self, page_zoom: ZoomFactor) {
self.scene_ops.push(SceneMsg::SetPageZoom(page_zoom));
}
pub fn set_pinch_zoom(&mut self, pinch_zoom: ZoomFactor) {
self.frame_ops.push(FrameMsg::SetPinchZoom(pinch_zoom));
}
pub fn set_pan(&mut self, pan: DeviceIntPoint) {
self.frame_ops.push(FrameMsg::SetPan(pan));
}
pub fn generate_frame(&mut self) {
self.generate_frame = true;
}
pub fn invalidate_rendered_frame(&mut self) {
self.invalidate_rendered_frame = true;
}
pub fn update_dynamic_properties(&mut self, properties: DynamicProperties) {
self.frame_ops.push(FrameMsg::UpdateDynamicProperties(properties));
}
pub fn append_dynamic_properties(&mut self, properties: DynamicProperties) {
self.frame_ops.push(FrameMsg::AppendDynamicProperties(properties));
}
pub fn enable_frame_output(&mut self, pipeline_id: PipelineId, enable: bool) {
self.frame_ops.push(FrameMsg::EnableFrameOutput(pipeline_id, enable));
}
pub fn get_frame_ops(self) -> Vec<FrameMsg> {
self.frame_ops
}
fn finalize(self) -> (TransactionMsg, Vec<Payload>) {
(
TransactionMsg {
scene_ops: self.scene_ops,
frame_ops: self.frame_ops,
resource_updates: self.resource_updates,
notifications: self.notifications,
use_scene_builder_thread: self.use_scene_builder_thread,
generate_frame: self.generate_frame,
invalidate_rendered_frame: self.invalidate_rendered_frame,
low_priority: self.low_priority,
},
self.payloads,
)
}
pub fn add_image(
&mut self,
key: ImageKey,
descriptor: ImageDescriptor,
data: ImageData,
tiling: Option<TileSize>,
) {
self.resource_updates.push(ResourceUpdate::AddImage(AddImage {
key,
descriptor,
data,
tiling,
}));
}
pub fn update_image(
&mut self,
key: ImageKey,
descriptor: ImageDescriptor,
data: ImageData,
dirty_rect: &ImageDirtyRect,
) {
self.resource_updates.push(ResourceUpdate::UpdateImage(UpdateImage {
key,
descriptor,
data,
dirty_rect: *dirty_rect,
}));
}
pub fn delete_image(&mut self, key: ImageKey) {
self.resource_updates.push(ResourceUpdate::DeleteImage(key));
}
pub fn add_blob_image(
&mut self,
key: BlobImageKey,
descriptor: ImageDescriptor,
data: Arc<BlobImageData>,
tiling: Option<TileSize>,
) {
self.resource_updates.push(
ResourceUpdate::AddBlobImage(AddBlobImage {
key,
descriptor,
data,
tiling,
})
);
}
pub fn update_blob_image(
&mut self,
key: BlobImageKey,
descriptor: ImageDescriptor,
data: Arc<BlobImageData>,
dirty_rect: &BlobDirtyRect,
) {
self.resource_updates.push(
ResourceUpdate::UpdateBlobImage(UpdateBlobImage {
key,
descriptor,
data,
dirty_rect: *dirty_rect,
})
);
}
pub fn delete_blob_image(&mut self, key: BlobImageKey) {
self.resource_updates.push(ResourceUpdate::DeleteImage(key.as_image()));
}
pub fn set_blob_image_visible_area(&mut self, key: BlobImageKey, area: DeviceIntRect) {
self.resource_updates.push(ResourceUpdate::SetBlobImageVisibleArea(key, area))
}
pub fn add_raw_font(&mut self, key: font::FontKey, bytes: Vec<u8>, index: u32) {
self.resource_updates
.push(ResourceUpdate::AddFont(AddFont::Raw(key, bytes, index)));
}
pub fn add_native_font(&mut self, key: font::FontKey, native_handle: font::NativeFontHandle) {
self.resource_updates
.push(ResourceUpdate::AddFont(AddFont::Native(key, native_handle)));
}
pub fn delete_font(&mut self, key: font::FontKey) {
self.resource_updates.push(ResourceUpdate::DeleteFont(key));
}
pub fn add_font_instance(
&mut self,
key: font::FontInstanceKey,
font_key: font::FontKey,
glyph_size: Au,
options: Option<font::FontInstanceOptions>,
platform_options: Option<font::FontInstancePlatformOptions>,
variations: Vec<font::FontVariation>,
) {
self.resource_updates
.push(ResourceUpdate::AddFontInstance(AddFontInstance {
key,
font_key,
glyph_size,
options,
platform_options,
variations,
}));
}
pub fn delete_font_instance(&mut self, key: font::FontInstanceKey) {
self.resource_updates.push(ResourceUpdate::DeleteFontInstance(key));
}
pub fn set_low_priority(&mut self, low_priority: bool) {
self.low_priority = low_priority;
}
pub fn is_low_priority(&self) -> bool {
self.low_priority
}
pub fn merge(&mut self, mut other: Vec<ResourceUpdate>) {
self.resource_updates.append(&mut other);
}
pub fn clear(&mut self) {
self.resource_updates.clear()
}
}
#[derive(Clone, Deserialize, Serialize)]
pub struct TransactionMsg {
pub scene_ops: Vec<SceneMsg>,
pub frame_ops: Vec<FrameMsg>,
pub resource_updates: Vec<ResourceUpdate>,
pub generate_frame: bool,
pub invalidate_rendered_frame: bool,
pub use_scene_builder_thread: bool,
pub low_priority: bool,
#[serde(skip)]
pub notifications: Vec<NotificationRequest>,
}
impl TransactionMsg {
pub fn is_empty(&self) -> bool {
!self.generate_frame &&
!self.invalidate_rendered_frame &&
self.scene_ops.is_empty() &&
self.frame_ops.is_empty() &&
self.resource_updates.is_empty() &&
self.notifications.is_empty()
}
pub fn frame_message(msg: FrameMsg) -> Self {
TransactionMsg {
scene_ops: Vec::new(),
frame_ops: vec![msg],
resource_updates: Vec::new(),
notifications: Vec::new(),
generate_frame: false,
invalidate_rendered_frame: false,
use_scene_builder_thread: false,
low_priority: false,
}
}
pub fn scene_message(msg: SceneMsg) -> Self {
TransactionMsg {
scene_ops: vec![msg],
frame_ops: Vec::new(),
resource_updates: Vec::new(),
notifications: Vec::new(),
generate_frame: false,
invalidate_rendered_frame: false,
use_scene_builder_thread: false,
low_priority: false,
}
}
}
#[derive(Clone, Deserialize, Serialize)]
pub struct AddImage {
pub key: ImageKey,
pub descriptor: ImageDescriptor,
pub data: ImageData,
pub tiling: Option<TileSize>,
}
#[derive(Clone, Deserialize, Serialize)]
pub struct UpdateImage {
pub key: ImageKey,
pub descriptor: ImageDescriptor,
pub data: ImageData,
pub dirty_rect: ImageDirtyRect,
}
#[derive(Clone, Deserialize, Serialize)]
pub struct AddBlobImage {
pub key: BlobImageKey,
pub descriptor: ImageDescriptor,
pub data: Arc<BlobImageData>,
pub tiling: Option<TileSize>,
}
#[derive(Clone, Deserialize, Serialize)]
pub struct UpdateBlobImage {
pub key: BlobImageKey,
pub descriptor: ImageDescriptor,
pub data: Arc<BlobImageData>,
pub dirty_rect: BlobDirtyRect,
}
#[derive(Clone, Deserialize, Serialize)]
pub enum AddFont {
Raw(
font::FontKey,
#[serde(with = "serde_bytes")] Vec<u8>,
u32
),
Native(font::FontKey, font::NativeFontHandle),
}
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub struct HitTestItem {
pub pipeline: PipelineId,
pub tag: di::ItemTag,
pub point_in_viewport: LayoutPoint,
pub point_relative_to_item: LayoutPoint,
}
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct HitTestResult {
pub items: Vec<HitTestItem>,
}
bitflags! {
#[derive(Deserialize, MallocSizeOf, Serialize)]
pub struct HitTestFlags: u8 {
const FIND_ALL = 0b00000001;
const POINT_RELATIVE_TO_PIPELINE_VIEWPORT = 0b00000010;
}
}
#[derive(Clone, Deserialize, Serialize)]
pub struct AddFontInstance {
pub key: font::FontInstanceKey,
pub font_key: font::FontKey,
pub glyph_size: Au,
pub options: Option<font::FontInstanceOptions>,
pub platform_options: Option<font::FontInstancePlatformOptions>,
pub variations: Vec<font::FontVariation>,
}
#[derive(Clone, Deserialize, Serialize)]
pub enum SceneMsg {
UpdateEpoch(PipelineId, Epoch),
SetPageZoom(ZoomFactor),
SetRootPipeline(PipelineId),
RemovePipeline(PipelineId),
SetDisplayList {
list_descriptor: BuiltDisplayListDescriptor,
epoch: Epoch,
pipeline_id: PipelineId,
background: Option<ColorF>,
viewport_size: LayoutSize,
content_size: LayoutSize,
preserve_frame_state: bool,
},
SetWindowParameters {
window_size: DeviceIntSize,
inner_rect: DeviceIntRect,
device_pixel_ratio: f32,
},
}
#[derive(Clone, Deserialize, Serialize)]
pub enum FrameMsg {
UpdateEpoch(PipelineId, Epoch),
HitTest(Option<PipelineId>, WorldPoint, HitTestFlags, MsgSender<HitTestResult>),
SetPan(DeviceIntPoint),
EnableFrameOutput(PipelineId, bool),
Scroll(ScrollLocation, WorldPoint),
ScrollNodeWithId(LayoutPoint, di::ExternalScrollId, ScrollClamping),
GetScrollNodeState(MsgSender<Vec<ScrollNodeState>>),
UpdateDynamicProperties(DynamicProperties),
AppendDynamicProperties(DynamicProperties),
SetPinchZoom(ZoomFactor),
}
impl fmt::Debug for SceneMsg {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(match *self {
SceneMsg::UpdateEpoch(..) => "SceneMsg::UpdateEpoch",
SceneMsg::SetDisplayList { .. } => "SceneMsg::SetDisplayList",
SceneMsg::SetPageZoom(..) => "SceneMsg::SetPageZoom",
SceneMsg::RemovePipeline(..) => "SceneMsg::RemovePipeline",
SceneMsg::SetWindowParameters { .. } => "SceneMsg::SetWindowParameters",
SceneMsg::SetRootPipeline(..) => "SceneMsg::SetRootPipeline",
})
}
}
impl fmt::Debug for FrameMsg {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(match *self {
FrameMsg::UpdateEpoch(..) => "FrameMsg::UpdateEpoch",
FrameMsg::HitTest(..) => "FrameMsg::HitTest",
FrameMsg::SetPan(..) => "FrameMsg::SetPan",
FrameMsg::Scroll(..) => "FrameMsg::Scroll",
FrameMsg::ScrollNodeWithId(..) => "FrameMsg::ScrollNodeWithId",
FrameMsg::GetScrollNodeState(..) => "FrameMsg::GetScrollNodeState",
FrameMsg::EnableFrameOutput(..) => "FrameMsg::EnableFrameOutput",
FrameMsg::UpdateDynamicProperties(..) => "FrameMsg::UpdateDynamicProperties",
FrameMsg::AppendDynamicProperties(..) => "FrameMsg::AppendDynamicProperties",
FrameMsg::SetPinchZoom(..) => "FrameMsg::SetPinchZoom",
})
}
}
bitflags!{
#[derive(Deserialize, Serialize)]
pub struct CaptureBits: u8 {
const SCENE = 0x1;
const FRAME = 0x2;
}
}
bitflags!{
#[derive(Deserialize, Serialize)]
pub struct ClearCache: u8 {
const IMAGES = 0b1;
const GLYPHS = 0b01;
const GLYPH_DIMENSIONS = 0b001;
const RENDER_TASKS = 0b0001;
const TEXTURE_CACHE = 0b00001;
const RASTERIZED_BLOBS = 0b000001;
}
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct CapturedDocument {
pub document_id: DocumentId,
pub root_pipeline_id: Option<PipelineId>,
pub window_size: DeviceIntSize,
}
#[derive(Clone, Deserialize, Serialize)]
pub enum DebugCommand {
SetFlags(DebugFlags),
EnableDualSourceBlending(bool),
FetchDocuments,
FetchPasses,
FetchClipScrollTree,
FetchRenderTasks,
FetchScreenshot,
SaveCapture(PathBuf, CaptureBits),
LoadCapture(PathBuf, MsgSender<CapturedDocument>),
ClearCaches(ClearCache),
InvalidateGpuCache,
SimulateLongSceneBuild(u32),
SimulateLongLowPrioritySceneBuild(u32),
}
#[derive(Clone, Deserialize, Serialize)]
pub enum ApiMsg {
UpdateResources(Vec<ResourceUpdate>),
GetGlyphDimensions(
font::FontInstanceKey,
Vec<font::GlyphIndex>,
MsgSender<Vec<Option<font::GlyphDimensions>>>,
),
GetGlyphIndices(font::FontKey, String, MsgSender<Vec<Option<u32>>>),
CloneApi(MsgSender<IdNamespace>),
CloneApiByClient(IdNamespace),
AddDocument(DocumentId, DeviceIntSize, DocumentLayer),
UpdateDocument(DocumentId, TransactionMsg),
DeleteDocument(DocumentId),
ExternalEvent(ExternalEvent),
ClearNamespace(IdNamespace),
MemoryPressure,
ReportMemory(MsgSender<MemoryReport>),
DebugCommand(DebugCommand),
WakeUp,
WakeSceneBuilder,
FlushSceneBuilder(MsgSender<()>),
ShutDown,
}
impl fmt::Debug for ApiMsg {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(match *self {
ApiMsg::UpdateResources(..) => "ApiMsg::UpdateResources",
ApiMsg::GetGlyphDimensions(..) => "ApiMsg::GetGlyphDimensions",
ApiMsg::GetGlyphIndices(..) => "ApiMsg::GetGlyphIndices",
ApiMsg::CloneApi(..) => "ApiMsg::CloneApi",
ApiMsg::CloneApiByClient(..) => "ApiMsg::CloneApiByClient",
ApiMsg::AddDocument(..) => "ApiMsg::AddDocument",
ApiMsg::UpdateDocument(..) => "ApiMsg::UpdateDocument",
ApiMsg::DeleteDocument(..) => "ApiMsg::DeleteDocument",
ApiMsg::ExternalEvent(..) => "ApiMsg::ExternalEvent",
ApiMsg::ClearNamespace(..) => "ApiMsg::ClearNamespace",
ApiMsg::MemoryPressure => "ApiMsg::MemoryPressure",
ApiMsg::ReportMemory(..) => "ApiMsg::ReportMemory",
ApiMsg::DebugCommand(..) => "ApiMsg::DebugCommand",
ApiMsg::ShutDown => "ApiMsg::ShutDown",
ApiMsg::WakeUp => "ApiMsg::WakeUp",
ApiMsg::WakeSceneBuilder => "ApiMsg::WakeSceneBuilder",
ApiMsg::FlushSceneBuilder(..) => "ApiMsg::FlushSceneBuilder",
})
}
}
#[repr(C)]
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
pub struct Epoch(pub u32);
impl Epoch {
pub fn invalid() -> Epoch {
Epoch(u32::MAX)
}
}
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize)]
pub struct IdNamespace(pub u32);
#[repr(C)]
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
pub struct DocumentId(pub IdNamespace, pub u32);
impl DocumentId {
pub const INVALID: DocumentId = DocumentId(IdNamespace(0), 0);
}
pub type PipelineSourceId = u32;
#[repr(C)]
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
pub struct PipelineId(pub PipelineSourceId, pub u32);
impl PipelineId {
pub fn dummy() -> Self {
PipelineId(0, 0)
}
}
#[macro_export]
macro_rules! enumerate_interners {
($macro_name: ident) => {
$macro_name! {
clip,
prim,
normal_border,
image_border,
image,
yuv_image,
line_decoration,
linear_grad,
radial_grad,
picture,
text_run,
}
}
}
macro_rules! declare_interning_memory_report {
( $( $name: ident, )+ ) => {
#[repr(C)]
#[derive(AddAssign, Clone, Debug, Default, Deserialize, Serialize)]
pub struct InternerSubReport {
$(
pub $name: usize,
)+
}
}
}
enumerate_interners!(declare_interning_memory_report);
#[repr(C)]
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct InterningMemoryReport {
pub interners: InternerSubReport,
pub data_stores: InternerSubReport,
}
impl ::std::ops::AddAssign for InterningMemoryReport {
fn add_assign(&mut self, other: InterningMemoryReport) {
self.interners += other.interners;
self.data_stores += other.data_stores;
}
}
#[repr(C)]
#[derive(AddAssign, Clone, Debug, Default, Deserialize, Serialize)]
pub struct MemoryReport {
pub clip_stores: usize,
pub gpu_cache_metadata: usize,
pub gpu_cache_cpu_mirror: usize,
pub render_tasks: usize,
pub hit_testers: usize,
pub fonts: usize,
pub images: usize,
pub rasterized_blobs: usize,
pub shader_cache: usize,
pub interning: InterningMemoryReport,
pub gpu_cache_textures: usize,
pub vertex_data_textures: usize,
pub render_target_textures: usize,
pub texture_cache_textures: usize,
pub depth_target_textures: usize,
pub swap_chain: usize,
}
pub type VoidPtrToSizeFn = unsafe extern "C" fn(ptr: *const c_void) -> usize;
#[repr(C)]
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct ResourceId(pub u32);
#[repr(C)]
#[derive(Clone, Deserialize, Serialize)]
pub struct ExternalEvent {
raw: usize,
}
unsafe impl Send for ExternalEvent {}
impl ExternalEvent {
pub fn from_raw(raw: usize) -> Self {
ExternalEvent { raw }
}
pub fn unwrap(self) -> usize {
self.raw
}
}
#[derive(Clone, Deserialize, Serialize)]
pub enum ScrollClamping {
ToContentBounds,
NoClamping,
}
#[derive(Clone, Deserialize, Serialize)]
pub struct RenderApiSender {
api_sender: MsgSender<ApiMsg>,
payload_sender: PayloadSender,
}
impl RenderApiSender {
pub fn new(api_sender: MsgSender<ApiMsg>, payload_sender: PayloadSender) -> Self {
RenderApiSender {
api_sender,
payload_sender,
}
}
pub fn create_api(&self) -> RenderApi {
let (sync_tx, sync_rx) =
channel::msg_channel().expect("Failed to create channel");
let msg = ApiMsg::CloneApi(sync_tx);
self.api_sender.send(msg).expect("Failed to send CloneApi message");
let namespace_id = match sync_rx.recv() {
Ok(id) => id,
Err(e) => {
let webrender_is_alive = self.api_sender.send(ApiMsg::WakeUp);
if webrender_is_alive.is_err() {
panic!("Webrender was shut down before processing CloneApi: {}", e);
} else {
panic!("CloneApi message response was dropped while Webrender was still alive: {}", e);
}
}
};
RenderApi {
api_sender: self.api_sender.clone(),
payload_sender: self.payload_sender.clone(),
namespace_id,
next_id: Cell::new(ResourceId(0)),
}
}
pub fn create_api_by_client(&self, namespace_id: IdNamespace) -> RenderApi {
let msg = ApiMsg::CloneApiByClient(namespace_id);
self.api_sender.send(msg).expect("Failed to send CloneApiByClient message");
RenderApi {
api_sender: self.api_sender.clone(),
payload_sender: self.payload_sender.clone(),
namespace_id,
next_id: Cell::new(ResourceId(0)),
}
}
}
bitflags! {
#[derive(Default, Deserialize, MallocSizeOf, Serialize)]
pub struct DebugFlags: u32 {
const PROFILER_DBG = 1 << 0;
const RENDER_TARGET_DBG = 1 << 1;
const TEXTURE_CACHE_DBG = 1 << 2;
const GPU_TIME_QUERIES = 1 << 3;
const GPU_SAMPLE_QUERIES = 1 << 4;
const DISABLE_BATCHING = 1 << 5;
const EPOCHS = 1 << 6;
const COMPACT_PROFILER = 1 << 7;
const ECHO_DRIVER_MESSAGES = 1 << 8;
const NEW_FRAME_INDICATOR = 1 << 9;
const NEW_SCENE_INDICATOR = 1 << 10;
const SHOW_OVERDRAW = 1 << 11;
const GPU_CACHE_DBG = 1 << 12;
const SLOW_FRAME_INDICATOR = 1 << 13;
const TEXTURE_CACHE_DBG_CLEAR_EVICTED = 1 << 14;
const PICTURE_CACHING_DBG = 1 << 15;
const TEXTURE_CACHE_DBG_DISABLE_SHRINK = 1 << 16;
const PRIMITIVE_DBG = 1 << 17;
const ZOOM_DBG = 1 << 18;
}
}
pub struct RenderApi {
api_sender: MsgSender<ApiMsg>,
payload_sender: PayloadSender,
namespace_id: IdNamespace,
next_id: Cell<ResourceId>,
}
impl RenderApi {
pub fn get_namespace_id(&self) -> IdNamespace {
self.namespace_id
}
pub fn clone_sender(&self) -> RenderApiSender {
RenderApiSender::new(self.api_sender.clone(), self.payload_sender.clone())
}
pub fn add_document(&self, initial_size: DeviceIntSize, layer: DocumentLayer) -> DocumentId {
let new_id = self.next_unique_id();
let document_id = DocumentId(self.namespace_id, new_id);
let msg = ApiMsg::AddDocument(document_id, initial_size, layer);
self.api_sender.send(msg).unwrap();
document_id
}
pub fn delete_document(&self, document_id: DocumentId) {
let msg = ApiMsg::DeleteDocument(document_id);
self.api_sender.send(msg).unwrap();
}
pub fn generate_font_key(&self) -> font::FontKey {
let new_id = self.next_unique_id();
font::FontKey::new(self.namespace_id, new_id)
}
pub fn generate_font_instance_key(&self) -> font::FontInstanceKey {
let new_id = self.next_unique_id();
font::FontInstanceKey::new(self.namespace_id, new_id)
}
pub fn get_glyph_dimensions(
&self,
font: font::FontInstanceKey,
glyph_indices: Vec<font::GlyphIndex>,
) -> Vec<Option<font::GlyphDimensions>> {
let (tx, rx) = channel::msg_channel().unwrap();
let msg = ApiMsg::GetGlyphDimensions(font, glyph_indices, tx);
self.api_sender.send(msg).unwrap();
rx.recv().unwrap()
}
pub fn get_glyph_indices(&self, font_key: font::FontKey, text: &str) -> Vec<Option<u32>> {
let (tx, rx) = channel::msg_channel().unwrap();
let msg = ApiMsg::GetGlyphIndices(font_key, text.to_string(), tx);
self.api_sender.send(msg).unwrap();
rx.recv().unwrap()
}
pub fn generate_image_key(&self) -> ImageKey {
let new_id = self.next_unique_id();
ImageKey::new(self.namespace_id, new_id)
}
pub fn generate_blob_image_key(&self) -> BlobImageKey {
BlobImageKey(self.generate_image_key())
}
pub fn update_resources(&self, resources: Vec<ResourceUpdate>) {
if resources.is_empty() {
return;
}
self.api_sender
.send(ApiMsg::UpdateResources(resources))
.unwrap();
}
pub fn send_external_event(&self, evt: ExternalEvent) {
let msg = ApiMsg::ExternalEvent(evt);
self.api_sender.send(msg).unwrap();
}
pub fn notify_memory_pressure(&self) {
self.api_sender.send(ApiMsg::MemoryPressure).unwrap();
}
pub fn report_memory(&self) -> MemoryReport {
let (tx, rx) = channel::msg_channel().unwrap();
self.api_sender.send(ApiMsg::ReportMemory(tx)).unwrap();
rx.recv().unwrap()
}
pub fn set_debug_flags(&self, flags: DebugFlags) {
let cmd = DebugCommand::SetFlags(flags);
self.api_sender.send(ApiMsg::DebugCommand(cmd)).unwrap();
}
pub fn shut_down(&self) {
self.api_sender.send(ApiMsg::ShutDown).unwrap();
}
pub fn generate_property_binding_key<T: Copy>(&self) -> PropertyBindingKey<T> {
let new_id = self.next_unique_id();
PropertyBindingKey {
id: PropertyBindingId {
namespace: self.namespace_id,
uid: new_id,
},
_phantom: PhantomData,
}
}
#[inline]
fn next_unique_id(&self) -> u32 {
let ResourceId(id) = self.next_id.get();
self.next_id.set(ResourceId(id + 1));
id
}
#[doc(hidden)]
pub fn send_message(&self, msg: ApiMsg) {
self.api_sender.send(msg).unwrap();
}
#[doc(hidden)]
pub fn send_payload(&self, data: &[u8]) {
self.payload_sender
.send_payload(Payload::from_data(data))
.unwrap();
}
fn send_scene_msg(&self, document_id: DocumentId, msg: SceneMsg) {
self.api_sender
.send(ApiMsg::UpdateDocument(document_id, TransactionMsg::scene_message(msg)))
.unwrap()
}
fn send_frame_msg(&self, document_id: DocumentId, msg: FrameMsg) {
self.api_sender
.send(ApiMsg::UpdateDocument(document_id, TransactionMsg::frame_message(msg)))
.unwrap()
}
pub fn send_transaction(&self, document_id: DocumentId, transaction: Transaction) {
let (msg, payloads) = transaction.finalize();
for payload in payloads {
self.payload_sender.send_payload(payload).unwrap();
}
self.api_sender.send(ApiMsg::UpdateDocument(document_id, msg)).unwrap();
}
pub fn hit_test(&self,
document_id: DocumentId,
pipeline_id: Option<PipelineId>,
point: WorldPoint,
flags: HitTestFlags)
-> HitTestResult {
let (tx, rx) = channel::msg_channel().unwrap();
self.send_frame_msg(
document_id,
FrameMsg::HitTest(pipeline_id, point, flags, tx)
);
rx.recv().unwrap()
}
pub fn set_window_parameters(
&self,
document_id: DocumentId,
window_size: DeviceIntSize,
inner_rect: DeviceIntRect,
device_pixel_ratio: f32,
) {
self.send_scene_msg(
document_id,
SceneMsg::SetWindowParameters { window_size, inner_rect, device_pixel_ratio, },
);
}
pub fn get_scroll_node_state(&self, document_id: DocumentId) -> Vec<ScrollNodeState> {
let (tx, rx) = channel::msg_channel().unwrap();
self.send_frame_msg(document_id, FrameMsg::GetScrollNodeState(tx));
rx.recv().unwrap()
}
pub fn wake_scene_builder(&self) {
self.send_message(ApiMsg::WakeSceneBuilder);
}
pub fn flush_scene_builder(&self) {
let (tx, rx) = channel::msg_channel().unwrap();
self.send_message(ApiMsg::FlushSceneBuilder(tx));
rx.recv().unwrap();
}
pub fn save_capture(&self, path: PathBuf, bits: CaptureBits) {
let msg = ApiMsg::DebugCommand(DebugCommand::SaveCapture(path, bits));
self.send_message(msg);
}
pub fn load_capture(&self, path: PathBuf) -> Vec<CapturedDocument> {
self.flush_scene_builder();
let (tx, rx) = channel::msg_channel().unwrap();
let msg = ApiMsg::DebugCommand(DebugCommand::LoadCapture(path, tx));
self.send_message(msg);
let mut documents = Vec::new();
while let Ok(captured_doc) = rx.recv() {
documents.push(captured_doc);
}
documents
}
pub fn send_debug_cmd(&self, cmd: DebugCommand) {
let msg = ApiMsg::DebugCommand(cmd);
self.send_message(msg);
}
}
impl Drop for RenderApi {
fn drop(&mut self) {
let msg = ApiMsg::ClearNamespace(self.namespace_id);
let _ = self.api_sender.send(msg);
}
}
#[derive(Clone, Deserialize, Serialize)]
pub struct ScrollNodeState {
pub id: di::ExternalScrollId,
pub scroll_offset: LayoutVector2D,
}
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub enum ScrollLocation {
Delta(LayoutVector2D),
Start,
End,
}
#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
pub struct ZoomFactor(f32);
impl ZoomFactor {
pub fn new(scale: f32) -> Self {
ZoomFactor(scale)
}
pub fn get(&self) -> f32 {
self.0
}
}
#[repr(C)]
#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, Eq, Hash)]
pub struct PropertyBindingId {
namespace: IdNamespace,
uid: u32,
}
impl PropertyBindingId {
pub fn new(value: u64) -> Self {
PropertyBindingId {
namespace: IdNamespace((value >> 32) as u32),
uid: value as u32,
}
}
}
#[repr(C)]
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
pub struct PropertyBindingKey<T> {
pub id: PropertyBindingId,
_phantom: PhantomData<T>,
}
impl<T: Copy> PropertyBindingKey<T> {
pub fn with(&self, value: T) -> PropertyValue<T> {
PropertyValue { key: *self, value }
}
}
impl<T> PropertyBindingKey<T> {
pub fn new(value: u64) -> Self {
PropertyBindingKey {
id: PropertyBindingId::new(value),
_phantom: PhantomData,
}
}
}
#[repr(C)]
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
pub enum PropertyBinding<T> {
Value(T),
Binding(PropertyBindingKey<T>, T),
}
impl<T> From<T> for PropertyBinding<T> {
fn from(value: T) -> PropertyBinding<T> {
PropertyBinding::Value(value)
}
}
#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq)]
pub struct PropertyValue<T> {
pub key: PropertyBindingKey<T>,
pub value: T,
}
#[derive(Clone, Deserialize, Serialize, Debug, PartialEq, Default)]
pub struct DynamicProperties {
pub transforms: Vec<PropertyValue<LayoutTransform>>,
pub floats: Vec<PropertyValue<f32>>,
}
pub trait RenderNotifier: Send {
fn clone(&self) -> Box<RenderNotifier>;
fn wake_up(&self);
fn new_frame_ready(&self, DocumentId, scrolled: bool, composite_needed: bool, render_time_ns: Option<u64>);
fn external_event(&self, _evt: ExternalEvent) {
unimplemented!()
}
fn shut_down(&self) {}
}
#[repr(u32)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum Checkpoint {
SceneBuilt,
FrameBuilt,
FrameTexturesUpdated,
FrameRendered,
TransactionDropped,
}
pub trait NotificationHandler : Send + Sync {
fn notify(&self, when: Checkpoint);
}
pub struct NotificationRequest {
handler: Option<Box<NotificationHandler>>,
when: Checkpoint,
}
impl NotificationRequest {
pub fn new(when: Checkpoint, handler: Box<NotificationHandler>) -> Self {
NotificationRequest {
handler: Some(handler),
when,
}
}
pub fn when(&self) -> Checkpoint { self.when }
pub fn notify(mut self) {
if let Some(handler) = self.handler.take() {
handler.notify(self.when);
}
}
}
impl Drop for NotificationRequest {
fn drop(&mut self) {
if let Some(ref mut handler) = self.handler {
handler.notify(Checkpoint::TransactionDropped);
}
}
}
impl Clone for NotificationRequest {
fn clone(&self) -> Self {
NotificationRequest {
when: self.when,
handler: None,
}
}
}