servo: Merge #13740 - Migrated -Z trace-layout to serde_json (from shinglyu:layout_serde); r=jdm
authorShing Lyu <shing.lyu@gmail.com>
Mon, 07 Nov 2016 02:15:03 -0600
changeset 340083 bbb0c815f4132fdaa2aaafdf95a55337ee959ef2
parent 340082 977d4aab5053926f2ae5aa0b5fb5e3f5f4427ff0
child 340084 7bf83aa43a825e1dc4bcc8e3f4731bab6ab3f2af
push id31307
push usergszorc@mozilla.com
push dateSat, 04 Feb 2017 00:59:06 +0000
treeherdermozilla-central@94079d43835f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjdm
servo: Merge #13740 - Migrated -Z trace-layout to serde_json (from shinglyu:layout_serde); r=jdm <!-- Please describe your changes on the following line: --> Migrated the trace-layout code from old `rustc-serialize` to `serde_json`. This will help us iterate faster on the layout viewer (#13432), #13436, #12675 and fix #12936. --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [x] `./mach build -d` does not report any errors - [x] `./mach test-tidy` does not report any errors - [x] These changes fix #12936 (github issue number if applicable). <!-- Either: --> - [ ] There are tests for these changes OR - [x] These changes do not require tests because it's a relatively low risk debug tool <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: https://github.com/servo/servo Source-Revision: 1c26f44cbb23e7da3b9d63f0223c8d5d43eec958
servo/components/layout/Cargo.toml
servo/components/layout/block.rs
servo/components/layout/floats.rs
servo/components/layout/flow.rs
servo/components/layout/flow_list.rs
servo/components/layout/flow_ref.rs
servo/components/layout/fragment.rs
servo/components/layout/inline.rs
servo/components/layout/layout_debug.rs
servo/components/layout/lib.rs
servo/components/layout/model.rs
servo/components/layout/table.rs
servo/components/layout/table_cell.rs
servo/components/layout/table_row.rs
servo/components/layout/table_rowgroup.rs
servo/components/layout/table_wrapper.rs
servo/components/servo/Cargo.lock
servo/components/style/logical_geometry.rs
servo/ports/cef/Cargo.lock
--- a/servo/components/layout/Cargo.toml
+++ b/servo/components/layout/Cargo.toml
@@ -26,21 +26,22 @@ libc = "0.2"
 log = "0.3.5"
 msg = {path = "../msg"}
 net_traits = {path = "../net_traits"}
 ordered-float = "0.2.2"
 parking_lot = {version = "0.3.3", features = ["nightly"]}
 plugins = {path = "../plugins"}
 profile_traits = {path = "../profile_traits"}
 range = {path = "../range"}
-rustc-serialize = "0.3"
 script_layout_interface = {path = "../script_layout_interface"}
 script_traits = {path = "../script_traits"}
 selectors = "0.14"
+serde = "0.8"
 serde_derive = "0.8"
+serde_json = "0.8"
 servo_atoms = {path = "../atoms"}
 smallvec = "0.1"
 style = {path = "../style"}
 style_traits = {path = "../style_traits"}
 unicode-bidi = "0.2"
 unicode-script = {version = "0.1", features = ["harfbuzz"]}
 url = {version = "1.2", features = ["heap_size"]}
 util = {path = "../util"}
--- a/servo/components/layout/block.rs
+++ b/servo/components/layout/block.rs
@@ -43,34 +43,34 @@ use flow_list::FlowList;
 use fragment::{CoordinateSystem, Fragment, FragmentBorderBoxIterator, Overflow};
 use fragment::SpecificFragmentInfo;
 use gfx::display_list::{ClippingRegion, StackingContext};
 use gfx_traits::ScrollRootId;
 use gfx_traits::print_tree::PrintTree;
 use layout_debug;
 use model::{CollapsibleMargins, IntrinsicISizes, MarginCollapseInfo, MaybeAuto};
 use model::{specified, specified_or_none};
-use rustc_serialize::{Encodable, Encoder};
 use script_layout_interface::restyle_damage::{BUBBLE_ISIZES, REFLOW, REFLOW_OUT_OF_FLOW};
 use script_layout_interface::restyle_damage::REPOSITION;
 use sequential;
+use serde::{Serialize, Serializer};
 use std::cmp::{max, min};
 use std::fmt;
 use std::sync::Arc;
 use style::computed_values::{border_collapse, box_sizing, display, float, overflow_x, overflow_y};
 use style::computed_values::{position, text_align};
 use style::context::{SharedStyleContext, StyleContext};
 use style::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize, WritingMode};
 use style::properties::ServoComputedValues;
 use style::values::computed::{LengthOrPercentageOrNone, LengthOrPercentage};
 use style::values::computed::LengthOrPercentageOrAuto;
 use util::clamp;
 
 /// Information specific to floated blocks.
-#[derive(Clone, RustcEncodable)]
+#[derive(Clone, Serialize)]
 pub struct FloatedBlockInfo {
     /// The amount of inline size that is available for the float.
     pub containing_inline_size: Au,
 
     /// The float ceiling, relative to `BaseFlow::position::cur_b` (i.e. the top part of the border
     /// box).
     pub float_ceiling: Au,
 
@@ -497,17 +497,17 @@ pub enum MarginsMayCollapseFlag {
 #[derive(PartialEq)]
 pub enum FormattingContextType {
     None,
     Block,
     Other,
 }
 
 // A block formatting context.
-#[derive(RustcEncodable)]
+#[derive(Serialize)]
 pub struct BlockFlow {
     /// Data common to all flows.
     pub base: BaseFlow,
 
     /// The associated fragment.
     pub fragment: Fragment,
 
     /// Additional floating flow members.
@@ -521,19 +521,19 @@ bitflags! {
     flags BlockFlowFlags: u8 {
         #[doc = "If this is set, then this block flow is the root flow."]
         const IS_ROOT = 0b0000_0001,
         #[doc = "Whether this block flow is a child of a flex container."]
         const IS_FLEX = 0b0001_0000,
     }
 }
 
-impl Encodable for BlockFlowFlags {
-    fn encode<S: Encoder>(&self, e: &mut S) -> Result<(), S::Error> {
-        self.bits().encode(e)
+impl Serialize for BlockFlowFlags {
+    fn serialize<S: Serializer>(&self, serializer: &mut S) -> Result<(), S::Error> {
+        self.bits().serialize(serializer)
     }
 }
 
 impl BlockFlow {
     pub fn from_fragment(fragment: Fragment) -> BlockFlow {
         BlockFlow::from_fragment_and_float_kind(fragment, None)
     }
 
--- a/servo/components/layout/floats.rs
+++ b/servo/components/layout/floats.rs
@@ -9,17 +9,17 @@ use persistent_list::PersistentList;
 use std::cmp::{max, min};
 use std::fmt;
 use std::i32;
 use style::computed_values::float;
 use style::logical_geometry::{LogicalRect, LogicalSize, WritingMode};
 use style::values::computed::LengthOrPercentageOrAuto;
 
 /// The kind of float: left or right.
-#[derive(Clone, RustcEncodable, Debug, Copy)]
+#[derive(Clone, Serialize, Debug, Copy)]
 pub enum FloatKind {
     Left,
     Right
 }
 
 impl FloatKind {
     pub fn from_property(property: float::T) -> Option<FloatKind> {
         match property {
--- a/servo/components/layout/flow.rs
+++ b/servo/components/layout/flow.rs
@@ -36,19 +36,19 @@ use flow_ref::{FlowRef, WeakFlowRef};
 use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
 use gfx::display_list::{ClippingRegion, StackingContext};
 use gfx_traits::{ScrollRootId, StackingContextId};
 use gfx_traits::print_tree::PrintTree;
 use inline::InlineFlow;
 use model::{CollapsibleMargins, IntrinsicISizes, MarginCollapseInfo};
 use multicol::MulticolFlow;
 use parallel::FlowParallelInfo;
-use rustc_serialize::{Encodable, Encoder};
 use script_layout_interface::restyle_damage::{RECONSTRUCT_FLOW, REFLOW, REFLOW_OUT_OF_FLOW};
 use script_layout_interface::restyle_damage::{REPAINT, REPOSITION, RestyleDamage};
+use serde::{Serialize, Serializer};
 use std::{fmt, mem, raw};
 use std::iter::Zip;
 use std::slice::IterMut;
 use std::sync::Arc;
 use std::sync::atomic::Ordering;
 use style::computed_values::{clear, float, overflow_x, position, text_align};
 use style::context::SharedStyleContext;
 use style::dom::TRestyleDamage;
@@ -546,17 +546,17 @@ pub trait MutableOwnedFlowUtils {
     ///         <span style="position: relative">
     ///             <span style="position: absolute; ..."></span>
     ///         </span>
     ///     </div>
     fn take_applicable_absolute_descendants(&mut self,
                                             absolute_descendants: &mut AbsoluteDescendants);
 }
 
-#[derive(Copy, Clone, RustcEncodable, PartialEq, Debug)]
+#[derive(Copy, Clone, Serialize, PartialEq, Debug)]
 pub enum FlowClass {
     Block,
     Inline,
     ListItem,
     TableWrapper,
     Table,
     TableColGroup,
     TableRowGroup,
@@ -816,17 +816,17 @@ impl EarlyAbsolutePositionInfo {
             relative_containing_block_size: LogicalSize::zero(writing_mode),
             relative_containing_block_mode: writing_mode,
         }
     }
 }
 
 /// Information needed to compute absolute (i.e. viewport-relative) flow positions (not to be
 /// confused with absolutely-positioned flows) that is computed during final position assignment.
-#[derive(RustcEncodable, Copy, Clone)]
+#[derive(Serialize, Copy, Clone)]
 pub struct LateAbsolutePositionInfo {
     /// The position of the absolute containing block relative to the nearest ancestor stacking
     /// context. If the absolute containing block establishes the stacking context for this flow,
     /// and this flow is not itself absolutely-positioned, then this is (0, 0).
     pub stacking_relative_position_of_absolute_containing_block: Point2D<Au>,
 }
 
 impl LateAbsolutePositionInfo {
@@ -973,54 +973,27 @@ impl fmt::Debug for BaseFlow {
                self.speculated_float_placement_out,
                self.overflow,
                child_count_string,
                absolute_descendants_string,
                damage_string)
     }
 }
 
-impl Encodable for BaseFlow {
-    fn encode<S: Encoder>(&self, e: &mut S) -> Result<(), S::Error> {
-        e.emit_struct("base", 5, |e| {
-            try!(e.emit_struct_field("id", 0, |e| self.debug_id().encode(e)));
-            try!(e.emit_struct_field("stacking_relative_position",
-                                     1,
-                                     |e| self.stacking_relative_position.encode(e)));
-            try!(e.emit_struct_field("intrinsic_inline_sizes",
-                                     2,
-                                     |e| self.intrinsic_inline_sizes.encode(e)));
-            try!(e.emit_struct_field("position", 3, |e| self.position.encode(e)));
-            e.emit_struct_field("children", 4, |e| {
-                e.emit_seq(self.children.len(), |e| {
-                    for (i, c) in self.children.iter().enumerate() {
-                        try!(e.emit_seq_elt(i, |e| {
-                            try!(e.emit_struct("flow", 2, |e| {
-                                try!(e.emit_struct_field("class", 0, |e| c.class().encode(e)));
-                                e.emit_struct_field("data", 1, |e| {
-                                    match c.class() {
-                                        FlowClass::Block => c.as_block().encode(e),
-                                        FlowClass::Inline => c.as_inline().encode(e),
-                                        FlowClass::Table => c.as_table().encode(e),
-                                        FlowClass::TableWrapper => c.as_table_wrapper().encode(e),
-                                        FlowClass::TableRowGroup => c.as_table_rowgroup().encode(e),
-                                        FlowClass::TableRow => c.as_table_row().encode(e),
-                                        FlowClass::TableCell => c.as_table_cell().encode(e),
-                                        _ => { Ok(()) }     // TODO: Support captions
-                                    }
-                                })
-                            }));
-                            Ok(())
-                        }));
-                    }
-                    Ok(())
-                })
-
-            })
-        })
+impl Serialize for BaseFlow {
+    fn serialize<S: Serializer>(&self, serializer: &mut S) -> Result<(), S::Error> {
+        let mut state = try!(serializer.serialize_struct("base", 5));
+        try!(serializer.serialize_struct_elt(&mut state, "id", self.debug_id()));
+        try!(serializer.serialize_struct_elt(&mut state, "stacking_relative_position",
+                                             &self.stacking_relative_position));
+        try!(serializer.serialize_struct_elt(&mut state, "intrinsic_inline_sizes",
+                                             &self.intrinsic_inline_sizes));
+        try!(serializer.serialize_struct_elt(&mut state, "position", &self.position));
+        try!(serializer.serialize_struct_elt(&mut state, "children", &self.children));
+        serializer.serialize_struct_end(state)
     }
 }
 
 /// Whether a base flow should be forced to be nonfloated. This can affect e.g. `TableFlow`, which
 /// is never floated because the table wrapper flow is the floated one.
 #[derive(Clone, PartialEq)]
 pub enum ForceNonfloatedFlag {
     /// The flow should be floated if the node has a `float` property.
--- a/servo/components/layout/flow_list.rs
+++ b/servo/components/layout/flow_list.rs
@@ -1,30 +1,60 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-use flow::Flow;
+use flow::{Flow, FlowClass};
 use flow_ref::FlowRef;
+use serde::{Serialize, Serializer};
+use serde_json::{to_value, Value};
+use serde_json::builder::ObjectBuilder;
 use std::collections::{LinkedList, linked_list};
 use std::sync::Arc;
 
 /// This needs to be reworked now that we have dynamically-sized types in Rust.
 /// Until then, it's just a wrapper around LinkedList.
 ///
 /// SECURITY-NOTE(pcwalton): It is very important that `FlowRef` values not leak directly to
 /// layout. Layout code must only interact with `&Flow` or `&mut Flow` values. Otherwise, layout
 /// could stash `FlowRef` values in random places unknown to the system and thereby cause data
 /// races. Those data races can lead to memory safety problems, potentially including arbitrary
 /// remote code execution! In general, do not add new methods to this file (e.g. new ways of
 /// iterating over flows) unless you are *very* sure of what you are doing.
 pub struct FlowList {
     flows: LinkedList<FlowRef>,
 }
 
+impl Serialize for FlowList {
+    fn serialize<S: Serializer>(&self, serializer: &mut S) -> Result<(), S::Error> {
+        let mut state = try!(serializer.serialize_seq(Some(self.len())));
+        for f in self.iter() {
+            let flow_val = ObjectBuilder::new()
+                .insert("class", f.class())
+                .insert("data", match f.class() {
+                    FlowClass::Block => to_value(f.as_block()),
+                    FlowClass::Inline => to_value(f.as_inline()),
+                    FlowClass::Table => to_value(f.as_table()),
+                    FlowClass::TableWrapper => to_value(f.as_table_wrapper()),
+                    FlowClass::TableRowGroup => to_value(f.as_table_rowgroup()),
+                    FlowClass::TableRow => to_value(f.as_table_row()),
+                    FlowClass::TableCell => to_value(f.as_table_cell()),
+                    FlowClass::ListItem | FlowClass::TableColGroup | FlowClass::TableCaption |
+                    FlowClass::Multicol | FlowClass::MulticolColumn | FlowClass::Flex => {
+                        Value::Null // Not implemented yet
+                    }
+                })
+                .build();
+
+            try!(serializer.serialize_seq_elt(&mut state, flow_val));
+        }
+        serializer.serialize_seq_end(state)
+    }
+}
+
 pub struct MutFlowListIterator<'a> {
     it: linked_list::IterMut<'a, FlowRef>,
 }
 
 impl FlowList {
     /// Add an element last in the list
     ///
     /// O(1)
--- a/servo/components/layout/flow_ref.rs
+++ b/servo/components/layout/flow_ref.rs
@@ -58,8 +58,9 @@ impl FlowRef {
 #[derive(Clone,Debug)]
 pub struct WeakFlowRef(Weak<Flow>);
 
 impl WeakFlowRef {
     pub fn upgrade(&self) -> Option<FlowRef> {
         self.0.upgrade().map(FlowRef)
     }
 }
+
--- a/servo/components/layout/fragment.rs
+++ b/servo/components/layout/fragment.rs
@@ -23,21 +23,21 @@ use inline::{InlineMetrics, LAST_FRAGMEN
 use ipc_channel::ipc::IpcSender;
 #[cfg(debug_assertions)]
 use layout_debug;
 use model::{self, Direction, IntrinsicISizes, IntrinsicISizesContribution, MaybeAuto};
 use msg::constellation_msg::PipelineId;
 use net_traits::image::base::{Image, ImageMetadata};
 use net_traits::image_cache_thread::{ImageOrMetadataAvailable, UsePlaceholder};
 use range::*;
-use rustc_serialize::{Encodable, Encoder};
 use script_layout_interface::HTMLCanvasData;
 use script_layout_interface::SVGSVGData;
 use script_layout_interface::restyle_damage::{RECONSTRUCT_FLOW, RestyleDamage};
 use script_layout_interface::wrapper_traits::{PseudoElementType, ThreadSafeLayoutElement, ThreadSafeLayoutNode};
+use serde::{Serialize, Serializer};
 use std::borrow::ToOwned;
 use std::cmp::{max, min};
 use std::collections::LinkedList;
 use std::fmt;
 use std::sync::{Arc, Mutex};
 use style::arc_ptr_eq;
 use style::computed_values::{border_collapse, box_sizing, clear, color, display, mix_blend_mode};
 use style::computed_values::{overflow_wrap, overflow_x, position, text_decoration};
@@ -128,23 +128,23 @@ pub struct Fragment {
     debug_id: DebugId,
 
     /// The ID of the StackingContext that contains this fragment. This is initialized
     /// to 0, but it assigned during the collect_stacking_contexts phase of display
     /// list construction.
     pub stacking_context_id: StackingContextId,
 }
 
-impl Encodable for Fragment {
-    fn encode<S: Encoder>(&self, e: &mut S) -> Result<(), S::Error> {
-        e.emit_struct("fragment", 3, |e| {
-            try!(e.emit_struct_field("id", 0, |e| self.debug_id.encode(e)));
-            try!(e.emit_struct_field("border_box", 1, |e| self.border_box.encode(e)));
-            e.emit_struct_field("margin", 2, |e| self.margin.encode(e))
-        })
+impl Serialize for Fragment {
+    fn serialize<S: Serializer>(&self, serializer: &mut S) -> Result<(), S::Error> {
+        let mut state = try!(serializer.serialize_struct("fragment", 3));
+        try!(serializer.serialize_struct_elt(&mut state, "id", &self.debug_id));
+        try!(serializer.serialize_struct_elt(&mut state, "border_box", &self.border_box));
+        try!(serializer.serialize_struct_elt(&mut state, "margin", &self.margin));
+        serializer.serialize_struct_end(state)
     }
 }
 
 /// Info specific to the kind of fragment.
 ///
 /// Keep this enum small. As in, no more than one word. Or pcwalton will yell at you.
 #[derive(Clone)]
 pub enum SpecificFragmentInfo {
@@ -498,17 +498,17 @@ impl ImageFragmentInfo {
         // Per the spec, if the space available is not enough for two images, just tile as
         // normal but only display a single tile.
         if image_size * 2 >= *size {
             ImageFragmentInfo::tile_image(position,
                                           size,
                                           absolute_anchor_origin,
                                           image_size);
             *tile_spacing = Au(0);
-            *size = image_size;;
+            *size = image_size;
             return;
         }
 
         // Take the box size, remove room for two tiles on the edges, and then calculate how many
         // other tiles fit in between them.
         let size_remaining = *size - (image_size * 2);
         let num_middle_tiles = (size_remaining.to_f32_px() / image_size.to_f32_px()).floor() as i32;
 
@@ -3157,21 +3157,20 @@ impl fmt::Display for DebugId {
 #[cfg(debug_assertions)]
 impl fmt::Display for DebugId {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "{}", self.0)
     }
 }
 
 #[cfg(not(debug_assertions))]
-impl Encodable for DebugId {
-    fn encode<S: Encoder>(&self, e: &mut S) -> Result<(), S::Error> {
-        e.emit_str(&format!("{:p}", &self))
+impl Serialize for DebugId {
+    fn serialize<S: Serializer>(&self, serializer: &mut S) -> Result<(), S::Error> {
+        serializer.serialize_str(&format!("{:p}", &self))
     }
 }
 
 #[cfg(debug_assertions)]
-impl Encodable for DebugId {
-    fn encode<S: Encoder>(&self, e: &mut S) -> Result<(), S::Error> {
-        e.emit_u16(self.0)
+impl Serialize for DebugId {
+    fn serialize<S: Serializer>(&self, serializer: &mut S) -> Result<(), S::Error> {
+        serializer.serialize_u16(self.0)
     }
 }
-
--- a/servo/components/layout/inline.rs
+++ b/servo/components/layout/inline.rs
@@ -60,17 +60,17 @@ use unicode_bidi;
 /// serve as the starting point, but the current design doesn't make it
 /// hard to try out that alternative.
 ///
 /// Line fragments also contain some metadata used during line breaking. The
 /// green zone is the area that the line can expand to before it collides
 /// with a float or a horizontal wall of the containing block. The block-start
 /// inline-start corner of the green zone is the same as that of the line, but
 /// the green zone can be taller and wider than the line itself.
-#[derive(RustcEncodable, Debug, Clone)]
+#[derive(Serialize, Debug, Clone)]
 pub struct Line {
     /// A range of line indices that describe line breaks.
     ///
     /// For example, consider the following HTML and rendered element with
     /// linebreaks:
     ///
     /// ~~~html
     /// <span>I <span>like truffles, <img></span> yes I do.</span>
@@ -202,17 +202,17 @@ impl Line {
         } else {
             new_line_metrics.space_needed()
         };
         max(self.bounds.size.block, new_block_size)
     }
 }
 
 int_range_index! {
-    #[derive(RustcEncodable)]
+    #[derive(Serialize)]
     #[doc = "The index of a fragment in a flattened vector of DOM elements."]
     struct FragmentIndex(isize)
 }
 
 /// Arranges fragments into lines, splitting them up as necessary.
 struct LineBreaker {
     /// The floats we need to flow around.
     floats: Floats,
@@ -786,17 +786,17 @@ impl LineBreaker {
 
     /// Returns true if the pending line is empty and false otherwise.
     fn pending_line_is_empty(&self) -> bool {
         self.pending_line.range.length() == FragmentIndex(0)
     }
 }
 
 /// Represents a list of inline fragments, including element ranges.
-#[derive(RustcEncodable, Clone)]
+#[derive(Serialize, Clone)]
 pub struct InlineFragments {
     /// The fragments themselves.
     pub fragments: Vec<Fragment>,
 }
 
 impl InlineFragments {
     /// Creates an empty set of inline fragments.
     pub fn new() -> InlineFragments {
@@ -823,17 +823,17 @@ impl InlineFragments {
 
     /// A convenience function to return a mutable reference to the fragment at a given index.
     pub fn get_mut(&mut self, index: usize) -> &mut Fragment {
         &mut self.fragments[index]
     }
 }
 
 /// Flows for inline layout.
-#[derive(RustcEncodable)]
+#[derive(Serialize)]
 pub struct InlineFlow {
     /// Data common to all flows.
     pub base: BaseFlow,
 
     /// A vector of all inline fragments. Several fragments may correspond to one node/element.
     pub fragments: InlineFragments,
 
     /// A vector of ranges into fragments that represents line positions. These ranges are disjoint
@@ -1775,17 +1775,17 @@ fn inline_contexts_are_equal(inline_cont
         (&Some(_), &None) | (&None, &Some(_)) => false,
     }
 }
 
 /// Ascent and space needed above and below the baseline for a fragment. See CSS 2.1 § 10.8.1.
 ///
 /// Descent is not included in this structure because it can be computed from the fragment's
 /// border/content box and the ascent.
-#[derive(Clone, Copy, Debug, RustcEncodable)]
+#[derive(Clone, Copy, Debug, Serialize)]
 pub struct InlineMetrics {
     /// The amount of space above the baseline needed for this fragment.
     pub space_above_baseline: Au,
     /// The amount of space below the baseline needed for this fragment.
     pub space_below_baseline: Au,
     /// The distance from the baseline to the top of this fragment. This can differ from
     /// `block_size_above_baseline` if the fragment needs some empty space above it due to
     /// line-height, etc.
@@ -1826,17 +1826,17 @@ impl InlineMetrics {
 }
 
 #[derive(Copy, Clone, PartialEq)]
 enum LineFlushMode {
     No,
     Flush,
 }
 
-#[derive(Copy, Clone, Debug, RustcEncodable)]
+#[derive(Copy, Clone, Debug, Serialize)]
 pub struct LineMetrics {
     pub space_above_baseline: Au,
     pub space_below_baseline: Au,
 }
 
 impl LineMetrics {
     pub fn new(space_above_baseline: Au, space_below_baseline: Au) -> LineMetrics {
         LineMetrics {
--- a/servo/components/layout/layout_debug.rs
+++ b/servo/components/layout/layout_debug.rs
@@ -5,17 +5,17 @@
 //! Supports writing a trace file created during each layout scope
 //! that can be viewed by an external tool to make layout debugging easier.
 
 // for thread_local
 #![allow(unsafe_code)]
 
 use flow;
 use flow_ref::FlowRef;
-use rustc_serialize::json;
+use serde_json::{to_string, to_value, Value};
 use std::borrow::ToOwned;
 use std::cell::RefCell;
 use std::fs::File;
 use std::io::Write;
 #[cfg(debug_assertions)]
 use std::sync::atomic::{ATOMIC_USIZE_INIT, AtomicUsize, Ordering};
 
 thread_local!(static STATE_KEY: RefCell<Option<State>> = RefCell::new(None));
@@ -31,30 +31,30 @@ macro_rules! layout_debug_scope(
         if cfg!(debug_assertions) {
             layout_debug::Scope::new(format!($($arg)*))
         } else {
             layout_debug::Scope
         }
     )
 );
 
-#[derive(RustcEncodable)]
+#[derive(Serialize)]
 struct ScopeData {
     name: String,
-    pre: String,
-    post: String,
+    pre: Value,
+    post: Value,
     children: Vec<Box<ScopeData>>,
 }
 
 impl ScopeData {
-    fn new(name: String, pre: String) -> ScopeData {
+    fn new(name: String, pre: Value) -> ScopeData {
         ScopeData {
             name: name,
             pre: pre,
-            post: String::new(),
+            post: Value::Null,
             children: vec!(),
         }
     }
 }
 
 struct State {
     flow_root: FlowRef,
     scope_stack: Vec<Box<ScopeData>>,
@@ -62,17 +62,17 @@ struct State {
 
 /// A layout debugging scope. The entire state of the flow tree
 /// will be output at the beginning and end of this scope.
 impl Scope {
     pub fn new(name: String) -> Scope {
         STATE_KEY.with(|ref r| {
             match *r.borrow_mut() {
                 Some(ref mut state) => {
-                    let flow_trace = json::encode(&flow::base(&*state.flow_root)).unwrap();
+                    let flow_trace = to_value(&flow::base(&*state.flow_root));
                     let data = box ScopeData::new(name.clone(), flow_trace);
                     state.scope_stack.push(data);
                 }
                 None => {}
             }
         });
         Scope
     }
@@ -80,17 +80,17 @@ impl Scope {
 
 #[cfg(debug_assertions)]
 impl Drop for Scope {
     fn drop(&mut self) {
         STATE_KEY.with(|ref r| {
             match *r.borrow_mut() {
                  Some(ref mut state) => {
                     let mut current_scope = state.scope_stack.pop().unwrap();
-                    current_scope.post = json::encode(&flow::base(&*state.flow_root)).unwrap();
+                    current_scope.post = to_value(&flow::base(&*state.flow_root));
                     let previous_scope = state.scope_stack.last_mut().unwrap();
                     previous_scope.children.push(current_scope);
                 }
                 None => {}
             }
         });
     }
 }
@@ -104,30 +104,30 @@ pub fn generate_unique_debug_id() -> u16
 }
 
 /// Begin a layout debug trace. If this has not been called,
 /// creating debug scopes has no effect.
 pub fn begin_trace(flow_root: FlowRef) {
     assert!(STATE_KEY.with(|ref r| r.borrow().is_none()));
 
     STATE_KEY.with(|ref r| {
-        let flow_trace = json::encode(&flow::base(&*flow_root)).unwrap();
+        let flow_trace = to_value(&flow::base(&*flow_root));
         let state = State {
             scope_stack: vec![box ScopeData::new("root".to_owned(), flow_trace)],
             flow_root: flow_root.clone(),
         };
         *r.borrow_mut() = Some(state);
     });
 }
 
 /// End the debug layout trace. This will write the layout
 /// trace to disk in the current directory. The output
 /// file can then be viewed with an external tool.
 pub fn end_trace(generation: u32) {
     let mut thread_state = STATE_KEY.with(|ref r| r.borrow_mut().take().unwrap());
     assert!(thread_state.scope_stack.len() == 1);
     let mut root_scope = thread_state.scope_stack.pop().unwrap();
-    root_scope.post = json::encode(&flow::base(&*thread_state.flow_root)).unwrap();
+    root_scope.post = to_value(&flow::base(&*thread_state.flow_root));
 
-    let result = json::encode(&root_scope).unwrap();
+    let result = to_string(&root_scope).unwrap();
     let mut file = File::create(format!("layout_trace-{}.json", generation)).unwrap();
     file.write_all(result.as_bytes()).unwrap();
 }
--- a/servo/components/layout/lib.rs
+++ b/servo/components/layout/lib.rs
@@ -39,19 +39,22 @@ extern crate ordered_float;
 extern crate parking_lot;
 #[macro_use]
 #[no_link]
 extern crate plugins as servo_plugins;
 #[macro_use]
 extern crate profile_traits;
 #[macro_use]
 extern crate range;
-extern crate rustc_serialize;
 extern crate script_layout_interface;
 extern crate script_traits;
+extern crate serde;
+#[macro_use]
+extern crate serde_derive;
+extern crate serde_json;
 #[macro_use] extern crate servo_atoms;
 extern crate smallvec;
 extern crate style;
 extern crate style_traits;
 extern crate unicode_bidi;
 extern crate unicode_script;
 extern crate url;
 extern crate util;
--- a/servo/components/layout/model.rs
+++ b/servo/components/layout/model.rs
@@ -296,17 +296,17 @@ impl MarginCollapseInfo {
 pub enum MarginCollapseState {
     /// We are accumulating margin on the logical top of this flow.
     AccumulatingCollapsibleTopMargin,
     /// We are accumulating margin between two blocks.
     AccumulatingMarginIn,
 }
 
 /// Intrinsic inline-sizes, which consist of minimum and preferred.
-#[derive(RustcEncodable, Copy, Clone)]
+#[derive(Serialize, Copy, Clone)]
 pub struct IntrinsicISizes {
     /// The *minimum inline-size* of the content.
     pub minimum_inline_size: Au,
     /// The *preferred inline-size* of the content.
     pub preferred_inline_size: Au,
 }
 
 impl fmt::Debug for IntrinsicISizes {
--- a/servo/components/layout/table.rs
+++ b/servo/components/layout/table.rs
@@ -33,17 +33,17 @@ use style::values::CSSFloat;
 use style::values::computed::LengthOrPercentageOrAuto;
 use table_row::{self, CellIntrinsicInlineSize, CollapsedBorder, CollapsedBorderProvenance};
 use table_row::TableRowFlow;
 use table_wrapper::TableLayout;
 
 /// A table flow corresponded to the table's internal table fragment under a table wrapper flow.
 /// The properties `position`, `float`, and `margin-*` are used on the table wrapper fragment,
 /// not table fragment per CSS 2.1 § 10.5.
-#[derive(RustcEncodable)]
+#[derive(Serialize)]
 pub struct TableFlow {
     pub block_flow: BlockFlow,
 
     /// Information about the intrinsic inline-sizes of each column, computed bottom-up during
     /// intrinsic inline-size bubbling.
     pub column_intrinsic_inline_sizes: Vec<ColumnIntrinsicInlineSize>,
 
     /// Information about the actual inline sizes of each column, computed top-down during actual
@@ -573,17 +573,17 @@ impl ISizeAndMarginsComputer for Interna
 /// specific width constraint. For instance, one cell might say that it wants to be 100 pixels wide
 /// in the inline direction and another cell might say that it wants to take up 20% of the inline-
 /// size of the table. Now because we bubble up these constraints during the bubble-inline-sizes
 /// phase of layout, we don't know yet how wide the table is ultimately going to be in the inline
 /// direction. As we need to pick the maximum width of all cells for a column (in this case, the
 /// maximum of 100 pixels and 20% of the table), the preceding constraint means that we must
 /// potentially store both a specified width *and* a specified percentage, so that the inline-size
 /// assignment phase of layout will know which one to pick.
-#[derive(Clone, RustcEncodable, Debug, Copy)]
+#[derive(Clone, Serialize, Debug, Copy)]
 pub struct ColumnIntrinsicInlineSize {
     /// The preferred intrinsic inline size.
     pub preferred: Au,
     /// The largest specified size of this column as a length.
     pub minimum_length: Au,
     /// The largest specified size of this column as a percentage (`width` property).
     pub percentage: CSSFloat,
     /// Whether the column inline size is *constrained* per INTRINSIC § 4.1.
@@ -610,17 +610,17 @@ impl ColumnIntrinsicInlineSize {
         }
     }
 }
 
 /// The actual inline size for each column.
 ///
 /// TODO(pcwalton): There will probably be some `border-collapse`-related info in here too
 /// eventually.
-#[derive(RustcEncodable, Clone, Copy, Debug)]
+#[derive(Serialize, Clone, Copy, Debug)]
 pub struct ColumnComputedInlineSize {
     /// The computed size of this inline column.
     pub size: Au,
 }
 
 pub trait VecExt<T> {
     fn push_or_set(&mut self, index: usize, value: T) -> &mut T;
     fn get_mut_or_push(&mut self, index: usize, zero: T) -> &mut T;
--- a/servo/components/layout/table_cell.rs
+++ b/servo/components/layout/table_cell.rs
@@ -25,17 +25,17 @@ use std::sync::Arc;
 use style::computed_values::{border_collapse, border_top_style, vertical_align};
 use style::context::SharedStyleContext;
 use style::logical_geometry::{LogicalMargin, LogicalRect, LogicalSize, WritingMode};
 use style::properties::ServoComputedValues;
 use table::InternalTable;
 use table_row::{CollapsedBorder, CollapsedBorderProvenance};
 
 /// A table formatting context.
-#[derive(RustcEncodable)]
+#[derive(Serialize)]
 pub struct TableCellFlow {
     /// Data common to all block flows.
     pub block_flow: BlockFlow,
 
     /// Border collapse information for the cell.
     pub collapsed_borders: CollapsedBordersForCell,
 
     /// The column span of this cell.
@@ -292,17 +292,17 @@ impl Flow for TableCellFlow {
 }
 
 impl fmt::Debug for TableCellFlow {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "TableCellFlow: {:?}", self.block_flow)
     }
 }
 
-#[derive(Copy, Clone, Debug, RustcEncodable)]
+#[derive(Copy, Clone, Debug, Serialize)]
 pub struct CollapsedBordersForCell {
     pub inline_start_border: CollapsedBorder,
     pub inline_end_border: CollapsedBorder,
     pub block_start_border: CollapsedBorder,
     pub block_end_border: CollapsedBorder,
     pub inline_start_width: Au,
     pub inline_end_width: Au,
     pub block_start_width: Au,
--- a/servo/components/layout/table_row.rs
+++ b/servo/components/layout/table_row.rs
@@ -15,18 +15,18 @@ use euclid::Point2D;
 use flow::{self, EarlyAbsolutePositionInfo, Flow, FlowClass, ImmutableFlowUtils, OpaqueFlow};
 use flow_list::MutFlowListIterator;
 use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
 use gfx::display_list::StackingContext;
 use gfx_traits::ScrollRootId;
 use gfx_traits::print_tree::PrintTree;
 use layout_debug;
 use model::MaybeAuto;
-use rustc_serialize::{Encodable, Encoder};
 use script_layout_interface::restyle_damage::{REFLOW, REFLOW_OUT_OF_FLOW};
+use serde::{Serialize, Serializer};
 use std::cmp::max;
 use std::fmt;
 use std::iter::{Enumerate, IntoIterator, Peekable};
 use std::sync::Arc;
 use style::computed_values::{border_collapse, border_spacing, border_top_style};
 use style::context::SharedStyleContext;
 use style::logical_geometry::{LogicalSize, PhysicalSide, WritingMode};
 use style::properties::ServoComputedValues;
@@ -60,24 +60,24 @@ pub struct TableRowFlow {
     /// Information about the borders for each cell, post-collapse. This is only computed if
     /// `border-collapse` is `collapse`.
     pub final_collapsed_borders: CollapsedBordersForRow,
 
     /// The computed cell spacing widths post-collapse.
     pub collapsed_border_spacing: CollapsedBorderSpacingForRow,
 }
 
-impl Encodable for TableRowFlow {
-    fn encode<S: Encoder>(&self, e: &mut S) -> Result<(), S::Error> {
-        self.block_flow.encode(e)
+impl Serialize for TableRowFlow {
+    fn serialize<S: Serializer>(&self, serializer: &mut S) -> Result<(), S::Error> {
+        self.block_flow.serialize(serializer)
     }
 }
 
 /// Information about the column inline size and span for each cell.
-#[derive(RustcEncodable, Copy, Clone)]
+#[derive(Serialize, Copy, Clone)]
 pub struct CellIntrinsicInlineSize {
     /// Inline sizes that this cell contributes to the column.
     pub column_size: ColumnIntrinsicInlineSize,
     /// The column span of this cell.
     pub column_span: u32,
 }
 
 
@@ -554,30 +554,30 @@ pub struct CollapsedBorder {
     /// The width of the border.
     pub width: Au,
     /// The color of the border.
     pub color: Color,
     /// The type of item that this border comes from.
     pub provenance: CollapsedBorderProvenance,
 }
 
-impl Encodable for CollapsedBorder {
-    fn encode<S: Encoder>(&self, _: &mut S) -> Result<(), S::Error> {
+impl Serialize for CollapsedBorder {
+    fn serialize<S: Serializer>(&self, _: &mut S) -> Result<(), S::Error> {
         Ok(())
     }
 }
 
 /// Where a border style comes from.
 ///
 /// The integer values here correspond to the border conflict resolution rules in CSS 2.1 §
 /// 17.6.2.1. Higher values override lower values.
 // FIXME(#8586): FromTableRow, FromTableRowGroup, FromTableColumn,
 // FromTableColumnGroup are unused
 #[allow(dead_code)]
-#[derive(Copy, Clone, Debug, PartialEq, RustcEncodable)]
+#[derive(Copy, Clone, Debug, PartialEq, Serialize)]
 pub enum CollapsedBorderProvenance {
     FromPreviousTableCell = 6,
     FromNextTableCell = 5,
     FromTableRow = 4,
     FromTableRowGroup = 3,
     FromTableColumn = 2,
     FromTableColumnGroup = 1,
     FromTable = 0,
--- a/servo/components/layout/table_rowgroup.rs
+++ b/servo/components/layout/table_rowgroup.rs
@@ -12,17 +12,17 @@ use context::{LayoutContext, SharedLayou
 use display_list_builder::DisplayListBuildState;
 use euclid::Point2D;
 use flow::{Flow, FlowClass, OpaqueFlow};
 use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
 use gfx::display_list::StackingContext;
 use gfx_traits::ScrollRootId;
 use gfx_traits::print_tree::PrintTree;
 use layout_debug;
-use rustc_serialize::{Encodable, Encoder};
+use serde::{Serialize, Serializer};
 use std::fmt;
 use std::iter::{IntoIterator, Iterator, Peekable};
 use std::sync::Arc;
 use style::computed_values::{border_collapse, border_spacing};
 use style::context::SharedStyleContext;
 use style::logical_geometry::{LogicalSize, WritingMode};
 use style::properties::ServoComputedValues;
 use table::{ColumnComputedInlineSize, ColumnIntrinsicInlineSize, InternalTable, TableLikeFlow};
@@ -50,19 +50,19 @@ pub struct TableRowGroupFlow {
     /// entire table and pushed down into each row during inline size computation.
     pub collapsed_inline_direction_border_widths_for_table: Vec<Au>,
 
     /// The final width of the borders in the block direction for each cell, computed by the
     /// entire table and pushed down into each row during inline size computation.
     pub collapsed_block_direction_border_widths_for_table: Vec<Au>,
 }
 
-impl Encodable for TableRowGroupFlow {
-    fn encode<S: Encoder>(&self, e: &mut S) -> Result<(), S::Error> {
-        self.block_flow.encode(e)
+impl Serialize for TableRowGroupFlow {
+    fn serialize<S: Serializer>(&self, serializer: &mut S) -> Result<(), S::Error> {
+        self.block_flow.serialize(serializer)
     }
 }
 
 impl TableRowGroupFlow {
     pub fn from_fragment(fragment: Fragment) -> TableRowGroupFlow {
         let writing_mode = fragment.style().writing_mode;
         TableRowGroupFlow {
             block_flow: BlockFlow::from_fragment(fragment),
--- a/servo/components/layout/table_wrapper.rs
+++ b/servo/components/layout/table_wrapper.rs
@@ -34,24 +34,24 @@ use style::computed_values::{border_coll
 use style::context::SharedStyleContext;
 use style::logical_geometry::{LogicalRect, LogicalSize};
 use style::properties::ServoComputedValues;
 use style::values::CSSFloat;
 use style::values::computed::LengthOrPercentageOrAuto;
 use table::{ColumnComputedInlineSize, ColumnIntrinsicInlineSize};
 use table_row;
 
-#[derive(Copy, Clone, RustcEncodable, Debug)]
+#[derive(Copy, Clone, Serialize, Debug)]
 pub enum TableLayout {
     Fixed,
     Auto
 }
 
 /// A table wrapper flow based on a block formatting context.
-#[derive(RustcEncodable)]
+#[derive(Serialize)]
 pub struct TableWrapperFlow {
     pub block_flow: BlockFlow,
 
     /// Intrinsic column inline sizes according to INTRINSIC § 4.1
     pub column_intrinsic_inline_sizes: Vec<ColumnIntrinsicInlineSize>,
 
     /// Table-layout property
     pub table_layout: TableLayout,
--- a/servo/components/servo/Cargo.lock
+++ b/servo/components/servo/Cargo.lock
@@ -1208,21 +1208,22 @@ dependencies = [
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "net_traits 0.0.1",
  "ordered-float 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "plugins 0.0.1",
  "profile_traits 0.0.1",
  "range 0.0.1",
- "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
  "script_layout_interface 0.0.1",
  "script_traits 0.0.1",
  "selectors 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo_atoms 0.0.1",
  "smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "style 0.0.1",
  "style_traits 0.0.1",
  "unicode-bidi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "unicode-script 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "util 0.0.1",
--- a/servo/components/style/logical_geometry.rs
+++ b/servo/components/style/logical_geometry.rs
@@ -17,19 +17,19 @@ pub enum BlockFlowDirection {
     LeftToRight
 }
 
 pub enum InlineBaseDirection {
     LeftToRight,
     RightToLeft
 }
 
+// TODO: improve the readability of the WritingMode serialization, refer to the Debug:fmt()
 bitflags!(
-    #[derive(RustcEncodable)]
-    #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+    #[cfg_attr(feature = "servo", derive(HeapSizeOf, Serialize))]
     pub flags WritingMode: u8 {
         const FLAG_RTL = 1 << 0,
         const FLAG_VERTICAL = 1 << 1,
         const FLAG_VERTICAL_LR = 1 << 2,
         const FLAG_SIDEWAYS_LEFT = 1 << 3
     }
 );
 
@@ -152,21 +152,23 @@ impl fmt::Display for WritingMode {
 
 /// Wherever logical geometry is used, the writing mode is known based on context:
 /// every method takes a `mode` parameter.
 /// However, this context is easy to get wrong.
 /// In debug builds only, logical geometry objects store their writing mode
 /// (in addition to taking it as a parameter to methods) and check it.
 /// In non-debug builds, make this storage zero-size and the checks no-ops.
 #[cfg(not(debug_assertions))]
-#[derive(RustcEncodable, PartialEq, Eq, Clone, Copy)]
+#[derive(PartialEq, Eq, Clone, Copy)]
+#[cfg_attr(feature = "servo", derive(Serialize))]
 struct DebugWritingMode;
 
 #[cfg(debug_assertions)]
-#[derive(RustcEncodable, PartialEq, Eq, Clone, Copy)]
+#[derive(PartialEq, Eq, Clone, Copy)]
+#[cfg_attr(feature = "servo", derive(Serialize))]
 struct DebugWritingMode {
     mode: WritingMode
 }
 
 #[cfg(not(debug_assertions))]
 impl DebugWritingMode {
     #[inline]
     fn check(&self, _other: WritingMode) {}
@@ -207,17 +209,18 @@ impl Debug for DebugWritingMode {
     #[cfg(debug_assertions)]
     fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> {
         write!(formatter, "{}", self.mode)
     }
 }
 
 
 /// A 2D size in flow-relative dimensions
-#[derive(RustcEncodable, PartialEq, Eq, Clone, Copy)]
+#[derive(PartialEq, Eq, Clone, Copy)]
+#[cfg_attr(feature = "servo", derive(Serialize))]
 pub struct LogicalSize<T> {
     pub inline: T,  // inline-size, a.k.a. logical width, a.k.a. measure
     pub block: T,  // block-size, a.k.a. logical height, a.k.a. extent
     debug_writing_mode: DebugWritingMode,
 }
 
 impl<T: Debug> Debug for LogicalSize<T> {
     fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> {
@@ -343,17 +346,18 @@ impl<T: Sub<T, Output=T>> Sub for Logica
             inline: self.inline - other.inline,
             block: self.block - other.block,
         }
     }
 }
 
 
 /// A 2D point in flow-relative dimensions
-#[derive(PartialEq, RustcEncodable, Eq, Clone, Copy)]
+#[derive(PartialEq, Eq, Clone, Copy)]
+#[cfg_attr(feature = "servo", derive(Serialize))]
 pub struct LogicalPoint<T> {
     /// inline-axis coordinate
     pub i: T,
     /// block-axis coordinate
     pub b: T,
     debug_writing_mode: DebugWritingMode,
 }
 
@@ -515,17 +519,18 @@ impl<T: Copy + Sub<T, Output=T>> Sub<Log
     }
 }
 
 
 /// A "margin" in flow-relative dimensions
 /// Represents the four sides of the margins, borders, or padding of a CSS box,
 /// or a combination of those.
 /// A positive "margin" can be added to a rectangle to obtain a bigger rectangle.
-#[derive(RustcEncodable, PartialEq, Eq, Clone, Copy)]
+#[derive(PartialEq, Eq, Clone, Copy)]
+#[cfg_attr(feature = "servo", derive(Serialize))]
 pub struct LogicalMargin<T> {
     pub block_start: T,
     pub inline_end: T,
     pub block_end: T,
     pub inline_start: T,
     debug_writing_mode: DebugWritingMode,
 }
 
@@ -808,17 +813,18 @@ impl<T: Sub<T, Output=T>> Sub for Logica
             block_end: self.block_end - other.block_end,
             inline_start: self.inline_start - other.inline_start,
         }
     }
 }
 
 
 /// A rectangle in flow-relative dimensions
-#[derive(RustcEncodable, PartialEq, Eq, Clone, Copy)]
+#[derive(PartialEq, Eq, Clone, Copy)]
+#[cfg_attr(feature = "servo", derive(Serialize))]
 pub struct LogicalRect<T> {
     pub start: LogicalPoint<T>,
     pub size: LogicalSize<T>,
     debug_writing_mode: DebugWritingMode,
 }
 
 impl<T: Debug> Debug for LogicalRect<T> {
     fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> {
--- a/servo/ports/cef/Cargo.lock
+++ b/servo/ports/cef/Cargo.lock
@@ -1113,21 +1113,22 @@ dependencies = [
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "net_traits 0.0.1",
  "ordered-float 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "plugins 0.0.1",
  "profile_traits 0.0.1",
  "range 0.0.1",
- "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
  "script_layout_interface 0.0.1",
  "script_traits 0.0.1",
  "selectors 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo_atoms 0.0.1",
  "smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "style 0.0.1",
  "style_traits 0.0.1",
  "unicode-bidi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "unicode-script 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "util 0.0.1",