docs: explain Tessera modules and execution flows in Chinese
This commit is contained in:
@@ -1,3 +1,7 @@
|
||||
//! 运行时与窗口线程之间的发布数据契约。NamespaceState 管理提交序号、版本和当前完整文档。
|
||||
//! RenderDocument/Frame 包含绘制命令、Mount 几何、页面标签和相机投影。发布前统一检查数量、坐标、颜色及索引一致性。
|
||||
//! 屏幕命中、逻辑坐标和世界 UI 的射线映射必须与绘制采用同一变换;这里的 ID 是数据身份,不是窗口线程可操作的托管引用。
|
||||
//!
|
||||
use std::collections::HashSet;
|
||||
use std::sync::Arc;
|
||||
|
||||
@@ -13,18 +17,23 @@ use crate::{
|
||||
pub const DEFAULT_NAMESPACE: &str = "app.main";
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
/// HTTP/GUI 共享的最近完整发布状态;submission 决定结果归属,revision 表示实际发布次数。
|
||||
pub struct NamespaceState {
|
||||
pub name: String,
|
||||
pub revision: u64,
|
||||
// 较新完整 PUT/DELETE 会改变提交身份;旧输入即使晚完成也不得覆盖新结果。
|
||||
pub submission: u64,
|
||||
pub document: RenderDocument,
|
||||
// viewport 是主窗口逻辑页面区域;window_viewports 同时记录仍存活的副窗口。
|
||||
pub viewport: Option<crate::layout::Size>,
|
||||
pub window_viewports: std::collections::BTreeMap<u64, crate::layout::Size>,
|
||||
// 原生命令与运行时世代一起发布,防止窗口 ID 在跨 VM 时被误用。
|
||||
pub runtime_session: u64,
|
||||
pub window_commands: Vec<crate::window::Envelope>,
|
||||
}
|
||||
|
||||
impl Default for NamespaceState {
|
||||
/// 建立类型约定的初始值,供尚未发布或尚未交互的状态使用。
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
name: DEFAULT_NAMESPACE.to_owned(),
|
||||
@@ -40,6 +49,7 @@ impl Default for NamespaceState {
|
||||
}
|
||||
|
||||
impl NamespaceState {
|
||||
/// 仅接收当前 session 的纯数据窗口命令,并按种类合并同资源的重复请求。
|
||||
pub fn publish_window_commands(&mut self, session: u64, commands: Vec<crate::window::Command>) {
|
||||
if self.runtime_session != session {
|
||||
self.window_commands.clear();
|
||||
@@ -63,13 +73,16 @@ impl NamespaceState {
|
||||
.sort_by_key(|command| command.command.sequence);
|
||||
}
|
||||
|
||||
/// 计算下一个完整源码提交身份;计数溢出时返回错误而不是复用旧身份。
|
||||
pub fn next_submission(&self) -> Result<u64> {
|
||||
self.submission
|
||||
.checked_add(1)
|
||||
.context("submission counter exhausted")
|
||||
}
|
||||
|
||||
/// 仅当提交身份仍是最新时替换完整文档并递增版本;已被取代的结果不发布。
|
||||
pub fn commit(&mut self, submission: u64, document: RenderDocument) -> Result<Option<u64>> {
|
||||
// 先核对归属,再计算新版本;失败或过时的结果不会替换已显示文档。
|
||||
if submission != self.submission {
|
||||
return Ok(None);
|
||||
}
|
||||
@@ -82,6 +95,7 @@ impl NamespaceState {
|
||||
Ok(Some(revision))
|
||||
}
|
||||
|
||||
/// 清空本对象维护的当前内容或缓存,后续状态由调用方重新建立。
|
||||
pub fn clear(&mut self) -> Result<u64> {
|
||||
let submission = self.next_submission()?;
|
||||
let revision = self
|
||||
@@ -98,6 +112,7 @@ impl NamespaceState {
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
|
||||
/// 可以离开 VM 线程的完整展示值,包含源码投影、根帧和其他窗口的文档。
|
||||
pub struct RenderDocument {
|
||||
#[serde(default, skip_serializing_if = "std::collections::BTreeMap::is_empty")]
|
||||
pub windows: std::collections::BTreeMap<u64, RenderDocument>,
|
||||
@@ -112,6 +127,7 @@ pub struct RenderDocument {
|
||||
}
|
||||
|
||||
impl RenderDocument {
|
||||
/// 检查当前输入或发布值的不变量,调用方据校验结果决定是否继续。
|
||||
pub fn validate(&self) -> Result<()> {
|
||||
let surface = &self.frame.surface;
|
||||
if !surface.zoom.is_finite()
|
||||
@@ -234,6 +250,7 @@ impl RenderDocument {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 校验文档后把逻辑绘制命令转换成给定设备比例的显示列表,应用变换与裁剪。
|
||||
pub fn display_list(&self, scale: f32) -> Result<DisplayList> {
|
||||
let frame = &self.frame;
|
||||
let mut list = DisplayList::default();
|
||||
@@ -321,12 +338,14 @@ impl RenderDocument {
|
||||
Ok(list)
|
||||
}
|
||||
|
||||
/// 从源码投影根按 ID 查找节点,供 Sources 查看与定位使用。
|
||||
pub fn node(&self, id: &str) -> Option<&CodeNode> {
|
||||
self.root.as_ref()?.find(id)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
/// Sources 使用的源码层次节点;ID、名称、种类和行列范围都属于代码投影而不是运行时对象句柄。
|
||||
pub struct CodeNode {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
@@ -340,6 +359,7 @@ pub struct CodeNode {
|
||||
}
|
||||
|
||||
impl CodeNode {
|
||||
/// 检查当前输入或发布值的不变量,调用方据校验结果决定是否继续。
|
||||
fn validate<'a>(&'a self, depth: usize, ids: &mut HashSet<&'a str>) -> Result<()> {
|
||||
if depth > 64 {
|
||||
bail!("architecture tree exceeds 64 levels");
|
||||
@@ -359,6 +379,7 @@ impl CodeNode {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 按请求的代码节点身份或路径查找对应的源码投影。
|
||||
fn find(&self, id: &str) -> Option<&CodeNode> {
|
||||
if self.id == id {
|
||||
return Some(self);
|
||||
@@ -368,7 +389,9 @@ impl CodeNode {
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
/// 一个窗口的一次完整视觉发布:有序命令及其裁剪/变换、出现几何、焦点和版本。平行索引表必须和命令数量一致。
|
||||
pub struct Frame {
|
||||
// 命中索引是可重建的本地优化,不作为序列化协议的一部分保存。
|
||||
#[serde(skip)]
|
||||
pub hit_index: Arc<crate::viewport::spatial::Index>,
|
||||
#[serde(default)]
|
||||
@@ -400,6 +423,7 @@ pub struct Frame {
|
||||
}
|
||||
|
||||
impl Default for Frame {
|
||||
/// 建立类型约定的初始值,供尚未发布或尚未交互的状态使用。
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
hit_index: Arc::default(),
|
||||
@@ -422,6 +446,7 @@ impl Default for Frame {
|
||||
|
||||
/// A position in a published frame. Identifiers are opaque data, never VM handles.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
/// 某次出现的几何与投影元数据。逻辑矩形不被相机直接改写,view/panel 保存通往视图空间的映射。
|
||||
pub struct MountGeometry {
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub panel: Option<Arc<crate::scene3d::panel::Mapping>>,
|
||||
@@ -452,15 +477,18 @@ pub struct MountGeometry {
|
||||
}
|
||||
|
||||
impl MountGeometry {
|
||||
/// 先沿世界 UI 面板逆投影指针,按需要执行可见性和裁剪检查。
|
||||
pub fn view_point(&self, point: Point, clipped: bool) -> Option<Point> {
|
||||
self.panel
|
||||
.as_ref()
|
||||
.map_or(Some(point), |panel| panel.texture_point(point, clipped))
|
||||
}
|
||||
/// 把页面指针转换为该出现的布局坐标,供 hitTest 和局部事件处理使用。
|
||||
pub fn logical_point(&self, point: Point) -> Option<Point> {
|
||||
let point = self.view_point(point, true)?;
|
||||
Some(self.view.unwrap_or_default().inverse(point))
|
||||
}
|
||||
/// 把视图位移换算成目标出现的局部位移,处理缩放与世界 UI 投影差异。
|
||||
pub fn logical_delta(&self, point: Option<[f32; 2]>, delta: [f32; 2]) -> Option<[f32; 2]> {
|
||||
let zoom = self.view.unwrap_or_default().zoom;
|
||||
if self.panel.is_none() {
|
||||
@@ -475,6 +503,7 @@ impl MountGeometry {
|
||||
((previous.y - current.y) / zoom).clamp(-1_000_000., 1_000_000.),
|
||||
])
|
||||
}
|
||||
/// 判断给定点是否位于目标范围;需要相机转换的类型会先转换再判断。
|
||||
pub fn contains(&self, point: Point) -> bool {
|
||||
let Some(point) = self.view_point(point, true) else {
|
||||
return false;
|
||||
@@ -488,6 +517,7 @@ impl MountGeometry {
|
||||
}
|
||||
|
||||
impl Frame {
|
||||
/// 从顶层绘制顺序向后查找可控制的视口,命中与裁剪均成立才接收相机手势。
|
||||
pub fn camera_at(&self, point: Point) -> Option<&MountGeometry> {
|
||||
self.hit_index
|
||||
.candidates(point, self.mounts.len())
|
||||
@@ -503,6 +533,7 @@ impl Frame {
|
||||
})
|
||||
})
|
||||
}
|
||||
/// 在无故障帧中按逆绘制顺序选中可交互的出现,空间索引只缩小候选。
|
||||
pub fn hit_test(&self, point: Point) -> Option<&MountGeometry> {
|
||||
if self.fault.is_some() {
|
||||
return None;
|
||||
@@ -515,16 +546,19 @@ impl Frame {
|
||||
}
|
||||
}
|
||||
|
||||
/// 返回默认主窗口身份,供省略窗口字段的兼容输入使用。
|
||||
fn default_window() -> u64 {
|
||||
crate::window::MAIN_WINDOW
|
||||
}
|
||||
|
||||
/// 提供空帧或未指定背景时的默认页面底色。
|
||||
fn default_background() -> String {
|
||||
"#F7F7F5".to_owned()
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(tag = "type", rename_all = "snake_case")]
|
||||
/// 可校验、可序列化的逻辑绘制命令;转换到设备像素在 display_list 阶段完成。
|
||||
pub enum RenderCommand {
|
||||
Scene3D {
|
||||
x: f32,
|
||||
@@ -566,6 +600,7 @@ pub enum RenderCommand {
|
||||
}
|
||||
|
||||
impl RenderCommand {
|
||||
/// 检查当前输入或发布值的不变量,调用方据校验结果决定是否继续。
|
||||
pub(crate) fn validate(&self) -> Result<()> {
|
||||
match self {
|
||||
Self::Scene3D {
|
||||
@@ -638,6 +673,7 @@ impl RenderCommand {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 把一条已验证的发布命令变成原生绘制原语,缩放几何和文字样式。
|
||||
fn to_draw_command(&self, scale: f32) -> Result<DrawCommand> {
|
||||
Ok(match self {
|
||||
Self::Scene3D {
|
||||
@@ -701,14 +737,17 @@ impl RenderCommand {
|
||||
}
|
||||
}
|
||||
|
||||
/// 提供未指定描边宽度时的兼容默认值。
|
||||
fn default_stroke_width() -> f32 {
|
||||
1.0
|
||||
}
|
||||
|
||||
/// 提供未指定字号时的协议默认值。
|
||||
fn default_text_size() -> u32 {
|
||||
1
|
||||
}
|
||||
|
||||
/// 统一检查有限矩形坐标、尺寸与可选圆角,阻止异常值进入光栅循环。
|
||||
fn validate_rect(x: f32, y: f32, width: f32, height: f32, radius: f32) -> Result<()> {
|
||||
if !x.is_finite() || !y.is_finite() || !width.is_finite() || !height.is_finite() {
|
||||
bail!("rectangle values must be finite");
|
||||
@@ -719,10 +758,12 @@ fn validate_rect(x: f32, y: f32, width: f32, height: f32, radius: f32) -> Result
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 将逻辑矩形转换为设备比例下的矩形,保持位置与尺寸同比缩放。
|
||||
fn scaled_rect(x: f32, y: f32, width: f32, height: f32, scale: f32) -> Rect {
|
||||
Rect::new(x * scale, y * scale, width * scale, height * scale)
|
||||
}
|
||||
|
||||
/// 解析支持的十六进制 RGB/RGBA 文本,拒绝错误长度或非法字符。
|
||||
pub fn parse_color(value: &str) -> Result<Color> {
|
||||
let hex = value
|
||||
.strip_prefix('#')
|
||||
|
||||
Reference in New Issue
Block a user