Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Layout viewer for layout 2020 #25803

Merged
merged 10 commits into from Feb 24, 2020

Add fragment debug id

  • Loading branch information
ferjm committed Feb 21, 2020
commit 67706f9c0b7fdb07c6ba12bf7ce6de557a4e81de
@@ -7,7 +7,7 @@ use crate::flow::float::FloatBox;
use crate::flow::FlowLayout;
use crate::formatting_contexts::IndependentFormattingContext;
use crate::fragments::CollapsedBlockMargins;
use crate::fragments::{AnonymousFragment, BoxFragment, Fragment, TextFragment};
use crate::fragments::{AnonymousFragment, BoxFragment, DebugId, Fragment, TextFragment};
use crate::geom::flow_relative::{Rect, Sides, Vec2};
use crate::positioned::{relative_adjustement, AbsolutelyPositionedBox, PositioningContext};
use crate::sizing::ContentSizes;
@@ -713,6 +713,7 @@ impl TextRun {
.fragments_so_far
.push(Fragment::Text(TextFragment {
tag: self.tag,
debug_id: DebugId::new(),
parent_style: self.parent_style.clone(),
rect,
ascent: font_ascent.into(),
@@ -8,8 +8,9 @@ use crate::context::LayoutContext;
use crate::flow::float::{FloatBox, FloatContext};
use crate::flow::inline::InlineFormattingContext;
use crate::formatting_contexts::{IndependentFormattingContext, IndependentLayout, NonReplacedIFC};
use crate::fragments::{AnonymousFragment, BoxFragment, Fragment};
use crate::fragments::{AnonymousFragment, BoxFragment};
use crate::fragments::{CollapsedBlockMargins, CollapsedMargin};
use crate::fragments::{DebugId, Fragment};
use crate::geom::flow_relative::{Rect, Sides, Vec2};
use crate::positioned::{AbsolutelyPositionedBox, PositioningContext};
use crate::replaced::ReplacedContent;
@@ -4,6 +4,7 @@

use crate::geom::flow_relative::{Rect, Sides, Vec2};
use crate::geom::{PhysicalPoint, PhysicalRect};
use crate::layout_debug;
use gfx::text::glyph::GlyphStore;
use gfx_traits::print_tree::PrintTree;
use serde::ser::{Serialize, SerializeStruct, Serializer};
@@ -27,6 +28,7 @@ pub(crate) enum Fragment {

pub(crate) struct BoxFragment {
pub tag: OpaqueNode,
pub debug_id: DebugId,
pub style: ServoArc<ComputedValues>,
pub children: Vec<Fragment>,

@@ -61,6 +63,7 @@ pub(crate) struct CollapsedMargin {
/// Can contain child fragments with relative coordinates, but does not contribute to painting itself.
#[derive(Serialize)]
pub(crate) struct AnonymousFragment {
pub debug_id: DebugId,
pub rect: Rect<Length>,
pub children: Vec<Fragment>,
pub mode: WritingMode,
@@ -70,6 +73,7 @@ pub(crate) struct AnonymousFragment {
}

pub(crate) struct TextFragment {
pub debug_id: DebugId,
pub tag: OpaqueNode,
pub parent_style: ServoArc<ComputedValues>,
pub rect: Rect<Length>,
@@ -79,6 +83,7 @@ pub(crate) struct TextFragment {
}

pub(crate) struct ImageFragment {
pub debug_id: DebugId,
pub style: ServoArc<ComputedValues>,
pub rect: Rect<Length>,
pub image_key: ImageKey,
@@ -123,6 +128,7 @@ impl Fragment {
impl AnonymousFragment {
pub fn no_op(mode: WritingMode) -> Self {
Self {
debug_id: DebugId::new(),
children: vec![],
rect: Rect::zero(),
mode,
@@ -140,6 +146,7 @@ impl AnonymousFragment {
)
});
AnonymousFragment {
debug_id: DebugId::new(),
rect,
children,
mode,
@@ -179,6 +186,7 @@ impl BoxFragment {
});
BoxFragment {
tag,
debug_id: DebugId::new(),
style,
children,
content_rect,
@@ -349,7 +357,8 @@ impl CollapsedMargin {

impl Serialize for BoxFragment {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut serializer = serializer.serialize_struct("BoxFragment", 6)?;
let mut serializer = serializer.serialize_struct("BoxFragment", 7)?;
serializer.serialize_field("debug_id", &self.debug_id)?;
serializer.serialize_field("content_rect", &self.content_rect)?;
serializer.serialize_field("padding", &self.padding)?;
serializer.serialize_field("border", &self.border)?;
@@ -365,7 +374,8 @@ impl Serialize for BoxFragment {

impl Serialize for TextFragment {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut serializer = serializer.serialize_struct("TextFragment", 3)?;
let mut serializer = serializer.serialize_struct("TextFragment", 4)?;
serializer.serialize_field("debug_id", &self.debug_id)?;
serializer.serialize_field("rect", &self.rect)?;
serializer.serialize_field("ascent", &self.ascent)?;
serializer.serialize_field("glyphs", &self.glyphs)?;
@@ -375,8 +385,45 @@ impl Serialize for TextFragment {

impl Serialize for ImageFragment {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut serializer = serializer.serialize_struct("ImageFragment", 1)?;
let mut serializer = serializer.serialize_struct("ImageFragment", 2)?;
serializer.serialize_field("debug_id", &self.debug_id)?;
serializer.serialize_field("rect", &self.rect)?;
serializer.end()
}
}

#[cfg(not(debug_assertions))]
#[derive(Clone)]
pub struct DebugId;

#[cfg(debug_assertions)]
#[derive(Clone)]
pub struct DebugId(u16);

#[cfg(not(debug_assertions))]
impl DebugId {
pub fn new() -> DebugId {
DebugId
}
}

#[cfg(debug_assertions)]
impl DebugId {
pub fn new() -> DebugId {
DebugId(layout_debug::generate_unique_debug_id())
}
}

#[cfg(not(debug_assertions))]
impl Serialize for DebugId {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_str(&format!("{:p}", &self))
}
}
This conversation was marked as resolved by SimonSapin

This comment has been minimized.

Copy link
@SimonSapin

SimonSapin Feb 20, 2020

Member

For these three impls: why are they not derived? Could they be derived with some attributes from https://serde.rs/field-attrs.html ?

This comment has been minimized.

Copy link
@ferjm

ferjm Feb 21, 2020

Author Member

I think I learnt about #[serde(skip_serializing)] after implementing the serializers. Fixed.


#[cfg(debug_assertions)]
impl Serialize for DebugId {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_u16(self.0)

This comment has been minimized.

Copy link
@SimonSapin

SimonSapin Feb 20, 2020

Member

This impl can be derived with #[serde(transparent)]

This comment has been minimized.

Copy link
@ferjm

ferjm Feb 21, 2020

Author Member

I just learnt about this. Thanks!

}
}
@@ -10,10 +10,15 @@ use serde_json::{to_string, to_value, Value};
use std::cell::RefCell;
use std::fs::File;
use std::io::Write;
#[cfg(debug_assertions)]
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;

thread_local!(static STATE_KEY: RefCell<Option<State>> = RefCell::new(None));

#[cfg(debug_assertions)]
static DEBUG_ID_COUNTER: AtomicUsize = AtomicUsize::new(0);

pub struct Scope;

#[macro_export]
@@ -80,6 +85,12 @@ impl Drop for Scope {
}
}

/// Generate a unique ID for Fragments.
#[cfg(debug_assertions)]
pub fn generate_unique_debug_id() -> u16 {
DEBUG_ID_COUNTER.fetch_add(1, Ordering::SeqCst) as u16
}

/// Begin a layout debug trace. If this has not been called,
/// creating debug scopes has no effect.
pub fn begin_trace(root: Arc<FragmentTreeRoot>) {
@@ -5,7 +5,7 @@
use crate::context::LayoutContext;
use crate::dom_traversal::{Contents, NodeExt};
use crate::formatting_contexts::IndependentFormattingContext;
use crate::fragments::{AnonymousFragment, BoxFragment, CollapsedBlockMargins, Fragment};
use crate::fragments::{AnonymousFragment, BoxFragment, CollapsedBlockMargins, DebugId, Fragment};
use crate::geom::flow_relative::{Rect, Sides, Vec2};
use crate::sizing::ContentSizesRequest;
use crate::style_ext::{ComputedValuesExt, DisplayInside};
@@ -3,7 +3,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use crate::dom_traversal::NodeExt;
use crate::fragments::{Fragment, ImageFragment};
use crate::fragments::{DebugId, Fragment, ImageFragment};
use crate::geom::flow_relative::{Rect, Vec2};
use crate::geom::PhysicalSize;
use crate::sizing::ContentSizes;
@@ -113,6 +113,7 @@ impl ReplacedContent {
.and_then(|image| image.id)
.map(|image_key| {
Fragment::Image(ImageFragment {
debug_id: DebugId::new(),
style: style.clone(),
rect: Rect {
start_corner: Vec2::zero(),
@@ -57,8 +57,8 @@ <h1> Servo Layout Viewer </h1>
<div class="row">
<div class="col-sm-12">
<div class='panel panel-default'>
<div class='panel-heading'>Flow Tree</div>
<div class='panel-body' id="flow-tree"></div>
<div class='panel-heading'>Fragment Tree</div>
<div class='panel-body' id="fragment-tree"></div>
</div>
</div>
<div class="col-sm-12">
@@ -90,28 +90,19 @@ <h1> Servo Layout Viewer </h1>
<script src="js/formatters.min.js"></script>

<script>
function get_base(trace_node) {
if (typeof(trace_node.data.base) == "undefined" && typeof(trace_node.data.block_flow) != "undefined") {
return trace_node.data.block_flow.base;
}
else {
return trace_node.data.base;
}
}

function create_flow_tree(trace_node) {
function create_fragment_tree(trace_node) {
var fragment = Object.values(trace_node)[0];
var node = {
text: Object.keys(trace_node)[0],
// id: base.id,
// icon: "dummy",
// href: "#diff-" + base.id
id: fragment.id,
icon: "dummy",
href: "#diff-" + fragment.id
};

var fragment = Object.values(trace_node)[0];
if (fragment.children) {
var children = [];
for (var i=0 ; i < fragment.children.length ; ++i) {
children.push(create_flow_tree(fragment.children[i]));
children.push(create_fragment_tree(fragment.children[i]));
}

if (children.length > 0) {
@@ -134,25 +125,25 @@ <h1> Servo Layout Viewer </h1>
}

function flatten_trace(trace_node) {
var flow_tree = create_flow_tree(Object.values(trace_node)[0]);
var fragment_tree = create_fragment_tree(Object.values(trace_node)[0]);

//var flow_hash = {};
//create_flow_hash(trace_node[0], flow_hash);

return {
tree: flow_tree,
tree: fragment_tree,
//flows: flow_hash,
}
}

function create_tree_node(trace_node) {
function create_trace_tree_node(trace_node) {
var pre_trace = flatten_trace(trace_node.pre);
var post_trace = flatten_trace(trace_node.post);

var tree_node = {
text: Object.keys(trace_node)[0],
text: trace_node.name,
icon: "dummy",
flow_tree: pre_trace.tree, // assume pre/post trace always have same tree!
fragment_tree: pre_trace.tree, // assume pre/post trace always have same tree!
//pre: pre_trace.flows,
//post: post_trace.flows,
};
@@ -161,7 +152,7 @@ <h1> Servo Layout Viewer </h1>
if (trace_node.children) {
var children = [];
for (var i=0 ; i < trace_node.children.length ; ++i) {
children.push(create_tree_node(trace_node.children[i]));
children.push(create_trace_tree_node(trace_node.children[i]));
}

if (children.length > 0) {
@@ -172,11 +163,11 @@ <h1> Servo Layout Viewer </h1>
return tree_node;
}

function update_flow_tree_bgcolor(flow_tree_node, node_color_hash) {
flow_tree_node.backColor = node_color_hash[flow_tree_node.id];
if (flow_tree_node.nodes !== undefined) {
for (var i=0 ; i < flow_tree_node.nodes.length ; ++i) {
update_flow_tree_bgcolor(flow_tree_node.nodes[i], node_color_hash)
function update_fragment_tree_bgcolor(fragment_tree_node, node_color_hash) {
fragment_tree_node.backColor = node_color_hash[fragment_tree_node.id];
if (fragment_tree_node.nodes !== undefined) {
for (var i=0 ; i < fragment_tree_node.nodes.length ; ++i) {
update_fragment_tree_bgcolor(fragment_tree_node.nodes[i], node_color_hash)
}
}
}
@@ -185,7 +176,7 @@ <h1> Servo Layout Viewer </h1>
jsondiffpatch.formatters.html.hideUnchanged();

var node_color_hash = {};
var tree = [ create_tree_node(data) ];
var tree = [ create_trace_tree_node(data) ];
$('#trace-tree').treeview({data: tree, levels: 3});
$('#trace-tree').on('nodeSelected', function(event, node) {
$("#flow-diffs").empty();
@@ -228,8 +219,8 @@ <h1> Servo Layout Viewer </h1>
}
}

update_flow_tree_bgcolor(node.flow_tree, node_color_hash);
$('#flow-tree').treeview({data: [node.flow_tree], levels: 100, enableLinks: true, emptyIcon: "glyphicon glyphicon-unchecked hidden-glyphicon"});
update_fragment_tree_bgcolor(node.fragment_tree, node_color_hash);
$('#fragment-tree').treeview({data: [node.fragment_tree], levels: 100, enableLinks: true, emptyIcon: "glyphicon glyphicon-unchecked hidden-glyphicon"});
});

$('#trace-tree').treeview(true).selectNode(0);
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.