conrod_core 0.75.0

An easy-to-use, 100% Rust, extensible 2D GUI library.
Documentation
//! Conrod's generic graphics backend.
//!
//! **Note:** Conrod currently uses Piston's generic [graphics
//! crate](https://github.com/PistonDevelopers/graphics) (and specifically the
//! [**Graphics**](http://docs.piston.rs/graphics/graphics/trait.Graphics.html))
//! trait to enable genericity over custom user backends. This dependency may change in the near
//! future in favour of a simplified conrod-specific graphics and character caching backend trait.
//!
//! This is the only module in which the src graphics crate will be used directly.

use color;
use graph::{self, Graph};
use image;
use position::{Align, Dimensions};
use std;
use text;
use theme::Theme;
use widget::triangles::{ColoredPoint, Triangle};
use widget::{self, Widget};
use {Color, FontSize, Point, Rect, Scalar};

/// An iterator-like type that yields a reference to each primitive in order of depth for
/// rendering.
///
/// This type is produced by the `Ui::draw` and `Ui::draw_if_changed` methods.
///
/// This type borrows data from the `Ui` in order to lazily produce each `Primitive`. If you
/// require ownership over the sequence of primitives, consider using the `OwnedPrimitives` type.
/// The `OwnedPrimitives` type can be produced by calling the `Primitives::owned` method.
pub struct Primitives<'a> {
    crop_stack: Vec<(widget::Id, Rect)>,
    depth_order: std::slice::Iter<'a, widget::Id>,
    graph: &'a Graph,
    theme: &'a Theme,
    fonts: &'a text::font::Map,
    window_rect: Rect,
    /// A buffer to use for triangulating polygons and lines for the `Triangles`.
    triangles: Vec<Triangle<Point>>,
}

/// An owned alternative to the `Primitives` type.
///
/// This is particularly useful for sending rendering data across threads.
///
/// Produce an `OwnedPrimitives` instance via the `Primitives::owned` method.
#[derive(Clone)]
pub struct OwnedPrimitives {
    primitives: Vec<OwnedPrimitive>,
    triangles_single_color: Vec<Triangle<Point>>,
    triangles_multi_color: Vec<Triangle<ColoredPoint>>,
    line_infos: Vec<text::line::Info>,
    texts_string: String,
}

/// A trait that allows the user to remain generic over types yielding `Primitive`s.
///
/// This trait is implemented for both the `Primitives` and `WalkOwnedPrimitives` types.
pub trait PrimitiveWalker {
    /// Yield the next `Primitive` in order of depth, bottom to top.
    fn next_primitive(&mut self) -> Option<Primitive>;
}

impl<'a> PrimitiveWalker for Primitives<'a> {
    fn next_primitive(&mut self) -> Option<Primitive> {
        self.next()
    }
}

impl<'a> PrimitiveWalker for WalkOwnedPrimitives<'a> {
    fn next_primitive(&mut self) -> Option<Primitive> {
        self.next()
    }
}

/// Data required for rendering a single primitive widget.
pub struct Primitive<'a> {
    /// The id of the widget within the widget graph.
    pub id: widget::Id,
    /// State and style for this primitive widget.
    pub kind: PrimitiveKind<'a>,
    /// The Rect to which the primitive widget should be cropped.
    ///
    /// Only parts of the widget within this `Rect` should be drawn.
    pub scizzor: Rect,
    /// The bounding rectangle for the `Primitive`.
    pub rect: Rect,
}

/// The unique kind for each primitive element in the Ui.
pub enum PrimitiveKind<'a> {
    /// A filled `Rectangle`.
    ///
    /// These are produced by the `Rectangle` and `BorderedRectangle` primitive widgets. A `Filled`
    /// `Rectangle` widget produces a single `Rectangle`. The `BorderedRectangle` produces two
    /// `Rectangle`s, the first for the outer border and the second for the inner on top.
    Rectangle {
        /// The fill colour for the rectangle.
        color: Color,
    },

    /// A series of consecutive `Triangles` that are all the same color.
    TrianglesSingleColor {
        /// The color of all triangles.
        color: color::Rgba,
        /// An ordered slice of triangles.
        triangles: &'a [Triangle<Point>],
    },

    /// A series of consecutive `Triangles` with unique colors per vertex.
    ///
    /// This variant is produced by the general purpose `Triangles` primitive widget.
    TrianglesMultiColor {
        /// An ordered slice of multicolored triangles.
        triangles: &'a [Triangle<ColoredPoint>],
    },

    /// A single `Image`, produced by the primitive `Image` widget.
    Image {
        /// The unique identifier of the image that will be drawn.
        image_id: image::Id,
        /// When `Some`, colours the `Image`. When `None`, the `Image` uses its regular colours.
        color: Option<Color>,
        /// The area of the texture that will be drawn to the `Image`'s `Rect`.
        source_rect: Option<Rect>,
    },

    /// A single block of `Text`, produced by the primitive `Text` widget.
    Text {
        /// The colour of the `Text`.
        color: Color,
        /// All glyphs within the `Text` laid out in their correct positions in order from top-left
        /// to bottom right.
        text: Text<'a>,
        /// The unique identifier for the font, useful for the `glyph_cache.rect_for(id, glyph)`
        /// method when using the `conrod::text::GlyphCache` (rusttype's GPU `Cache`).
        font_id: text::font::Id,
    },

    /// An `Other` variant will be yielded for every non-primitive widget in the list.
    ///
    /// Most of the time, this variant can be ignored, however it is useful for users who need to
    /// render widgets in ways that cannot be covered by the other `PrimitiveKind` variants.
    ///
    /// For example, a `Shader` widget might be required for updating uniforms in user rendering
    /// code. In order to access the unique state of this widget, the user can check `Other`
    /// variants for a container whose `kind` field matches the unique kind of the `Shader` widget.
    /// They can then retrieve the unique state of the widget and cast it to its actual type using
    /// either of the `Container::state_and_style` or `Container::unique_widget_state` methods.
    Other(&'a graph::Container),
}

/// A type used for producing a `PositionedGlyph` iterator.
///
/// We produce this type rather than the `&[PositionedGlyph]`s directly so that we can properly
/// handle "HiDPI" scales when caching glyphs.
pub struct Text<'a> {
    window_dim: Dimensions,
    text: &'a str,
    line_infos: &'a [text::line::Info],
    font: &'a text::Font,
    font_size: FontSize,
    rect: Rect,
    justify: text::Justify,
    y_align: Align,
    line_spacing: Scalar,
}

#[derive(Clone)]
struct OwnedPrimitive {
    id: widget::Id,
    kind: OwnedPrimitiveKind,
    scizzor: Rect,
    rect: Rect,
}

#[derive(Clone)]
enum OwnedPrimitiveKind {
    Rectangle {
        color: Color,
    },
    TrianglesSingleColor {
        color: color::Rgba,
        triangle_range: std::ops::Range<usize>,
    },
    TrianglesMultiColor {
        triangle_range: std::ops::Range<usize>,
    },
    Image {
        image_id: image::Id,
        color: Option<Color>,
        source_rect: Option<Rect>,
    },
    Text {
        color: Color,
        font_id: text::font::Id,
        text: OwnedText,
    },
}

#[derive(Clone)]
struct OwnedText {
    str_byte_range: std::ops::Range<usize>,
    line_infos_range: std::ops::Range<usize>,
    window_dim: Dimensions,
    font: text::Font,
    font_size: FontSize,
    rect: Rect,
    justify: text::Justify,
    y_align: Align,
    line_spacing: Scalar,
}

/// An iterator-like type for yielding `Primitive`s from an `OwnedPrimitives`.
pub struct WalkOwnedPrimitives<'a> {
    primitives: std::slice::Iter<'a, OwnedPrimitive>,
    triangles_single_color: &'a [Triangle<Point>],
    triangles_multi_color: &'a [Triangle<ColoredPoint>],
    line_infos: &'a [text::line::Info],
    texts_str: &'a str,
}

impl<'a> Text<'a> {
    /// Produces a list of `PositionedGlyph`s which may be used to cache and render the text.
    ///
    /// `dpi_factor`, aka "dots per inch factor" is a multiplier representing the density of
    /// the display's pixels. The `Scale` of the font will be multiplied by this factor in order to
    /// ensure that each `PositionedGlyph`'s `pixel_bounding_box` is accurate and that the GPU
    /// cache receives glyphs of a size that will display correctly on displays regardless of DPI.
    ///
    /// Note that conrod does not require this factor when instantiating `Text` widgets and laying
    /// out text. This is because conrod positioning uses a "pixel-agnostic" `Scalar` value
    /// representing *perceived* distances for its positioning and layout, rather than pixel
    /// values. During rendering however, the pixel density must be known
    pub fn positioned_glyphs(
        self,
        dpi_factor: f32,
    ) -> impl 'a + Iterator<Item = rusttype::PositionedGlyph<'static>> {
        let Text {
            window_dim,
            text,
            line_infos,
            font,
            font_size,
            rect,
            justify,
            y_align,
            line_spacing,
            ..
        } = self;

        // Convert conrod coordinates to pixel coordinates.
        let trans_x = move |x: Scalar| (x + window_dim[0] / 2.0) * dpi_factor as Scalar;
        let trans_y = move |y: Scalar| ((-y) + window_dim[1] / 2.0) * dpi_factor as Scalar;

        // Produce the text layout iterators.
        let line_infos = line_infos.iter().cloned();
        let lines = line_infos.clone().map(move |info| &text[info.byte_range()]);
        let line_rects =
            text::line::rects(line_infos, font_size, rect, justify, y_align, line_spacing);

        // Clear the existing glyphs and fill the buffer with glyphs for this Text.
        let scale = text::f32_pt_to_scale(font_size as f32 * dpi_factor);
        lines.zip(line_rects).flat_map(move |(line, line_rect)| {
            let (x, y) = (
                trans_x(line_rect.left()) as f32,
                trans_y(line_rect.bottom()) as f32,
            );
            let point = text::rt::Point { x: x, y: y };
            font.layout(line, scale, point)
        })
    }
}

impl<'a> Primitives<'a> {
    /// Constructor for the `Primitives` iterator.
    pub fn new(
        graph: &'a Graph,
        depth_order: &'a [widget::Id],
        theme: &'a Theme,
        fonts: &'a text::font::Map,
        window_dim: Dimensions,
    ) -> Self {
        Primitives {
            crop_stack: Vec::new(),
            depth_order: depth_order.iter(),
            graph: graph,
            theme: theme,
            fonts: fonts,
            window_rect: Rect::from_xy_dim([0.0, 0.0], window_dim),
            triangles: Vec::new(),
        }
    }

    /// Yield the next `Primitive` for rendering.
    pub fn next(&mut self) -> Option<Primitive> {
        let Primitives {
            ref mut crop_stack,
            ref mut depth_order,
            ref mut triangles,
            graph,
            theme,
            fonts,
            window_rect,
        } = *self;

        while let Some(widget) = next_widget(depth_order, graph, crop_stack, window_rect) {
            use widget::primitive::point_path::{State as PointPathState, Style as PointPathStyle};
            use widget::primitive::shape::polygon::State as PolygonState;
            use widget::primitive::shape::Style as ShapeStyle;

            type TrianglesSingleColorState =
                widget::triangles::State<Vec<widget::triangles::Triangle<Point>>>;
            type TrianglesMultiColorState =
                widget::triangles::State<Vec<widget::triangles::Triangle<(Point, color::Rgba)>>>;

            let (id, scizzor, container) = widget;
            let rect = container.rect;

            fn state_type_id<W>() -> std::any::TypeId
            where
                W: Widget,
            {
                std::any::TypeId::of::<W::State>()
            }

            // Extract the unique state and style from the container.
            if container.type_id == state_type_id::<widget::Rectangle>() {
                if let Some(rectangle) = container.unique_widget_state::<widget::Rectangle>() {
                    let graph::UniqueWidgetState { ref style, .. } = *rectangle;
                    let color = style.get_color(theme);
                    match *style {
                        ShapeStyle::Fill(_) => {
                            let kind = PrimitiveKind::Rectangle { color: color };
                            return Some(new_primitive(id, kind, scizzor, rect));
                        }
                        ShapeStyle::Outline(ref line_style) => {
                            let (l, r, b, t) = rect.l_r_b_t();
                            let array = [[l, b], [l, t], [r, t], [r, b], [l, b]];
                            let cap = line_style.get_cap(theme);
                            let thickness = line_style.get_thickness(theme);
                            let points = array.iter().cloned();
                            let triangles =
                                match widget::point_path::triangles(points, cap, thickness) {
                                    None => &[],
                                    Some(iter) => {
                                        triangles.extend(iter);
                                        &triangles[..]
                                    }
                                };
                            let kind = PrimitiveKind::TrianglesSingleColor {
                                color: color.to_rgb(),
                                triangles: &triangles,
                            };
                            return Some(new_primitive(id, kind, scizzor, rect));
                        }
                    }
                }
            } else if container.type_id == std::any::TypeId::of::<TrianglesSingleColorState>() {
                type Style = widget::triangles::SingleColor;
                if let Some(tris) = container.state_and_style::<TrianglesSingleColorState, Style>()
                {
                    let graph::UniqueWidgetState {
                        ref state,
                        ref style,
                    } = *tris;
                    let widget::triangles::SingleColor(color) = *style;
                    let kind = PrimitiveKind::TrianglesSingleColor {
                        color: color,
                        triangles: &state.triangles,
                    };
                    return Some(new_primitive(id, kind, scizzor, rect));
                }
            } else if container.type_id == std::any::TypeId::of::<TrianglesMultiColorState>() {
                type Style = widget::triangles::MultiColor;
                if let Some(tris) = container.state_and_style::<TrianglesMultiColorState, Style>() {
                    let graph::UniqueWidgetState { ref state, .. } = *tris;
                    let kind = PrimitiveKind::TrianglesMultiColor {
                        triangles: &state.triangles,
                    };
                    return Some(new_primitive(id, kind, scizzor, rect));
                }
            } else if container.type_id == state_type_id::<widget::Oval<widget::oval::Full>>() {
                if let Some(oval) =
                    container.unique_widget_state::<widget::Oval<widget::oval::Full>>()
                {
                    let graph::UniqueWidgetState {
                        ref style,
                        ref state,
                    } = *oval;
                    triangles.clear();
                    let points = widget::oval::circumference(rect, state.resolution);
                    let color = style.get_color(theme);
                    match *style {
                        ShapeStyle::Fill(_) => {
                            let triangles = {
                                triangles.extend(points.triangles());
                                &triangles[..]
                            };
                            let kind = PrimitiveKind::TrianglesSingleColor {
                                color: color.to_rgb(),
                                triangles: &triangles,
                            };
                            return Some(new_primitive(id, kind, scizzor, rect));
                        }

                        ShapeStyle::Outline(ref line_style) => {
                            let cap = line_style.get_cap(theme);
                            let thickness = line_style.get_thickness(theme);
                            let triangles =
                                match widget::point_path::triangles(points, cap, thickness) {
                                    None => &[],
                                    Some(iter) => {
                                        triangles.extend(iter);
                                        &triangles[..]
                                    }
                                };
                            let kind = PrimitiveKind::TrianglesSingleColor {
                                color: color.to_rgb(),
                                triangles: &triangles,
                            };
                            return Some(new_primitive(id, kind, scizzor, rect));
                        }
                    }
                }

            // Oval subsection.
            } else if container.type_id == state_type_id::<widget::Oval<widget::oval::Section>>() {
                if let Some(oval) =
                    container.unique_widget_state::<widget::Oval<widget::oval::Section>>()
                {
                    let graph::UniqueWidgetState {
                        ref style,
                        ref state,
                    } = *oval;
                    triangles.clear();
                    let points = widget::oval::circumference(rect, state.resolution)
                        .section(state.section.radians)
                        .offset_radians(state.section.offset_radians);
                    let color = style.get_color(theme);
                    match *style {
                        ShapeStyle::Fill(_) => {
                            let triangles = {
                                triangles.extend(points.triangles());
                                &triangles[..]
                            };
                            let kind = PrimitiveKind::TrianglesSingleColor {
                                color: color.to_rgb(),
                                triangles: &triangles,
                            };
                            return Some(new_primitive(id, kind, scizzor, rect));
                        }

                        ShapeStyle::Outline(ref line_style) => {
                            use std::iter::once;
                            let cap = line_style.get_cap(theme);
                            let thickness = line_style.get_thickness(theme);
                            let middle = rect.xy();
                            let points = once(middle).chain(points).chain(once(middle));
                            let triangles =
                                match widget::point_path::triangles(points, cap, thickness) {
                                    None => &[],
                                    Some(iter) => {
                                        triangles.extend(iter);
                                        &triangles[..]
                                    }
                                };
                            let kind = PrimitiveKind::TrianglesSingleColor {
                                color: color.to_rgb(),
                                triangles: &triangles,
                            };
                            return Some(new_primitive(id, kind, scizzor, rect));
                        }
                    }
                }
            } else if container.type_id == std::any::TypeId::of::<PolygonState>() {
                use widget::primitive::shape::Style;
                if let Some(polygon) = container.state_and_style::<PolygonState, Style>() {
                    let graph::UniqueWidgetState {
                        ref state,
                        ref style,
                    } = *polygon;
                    triangles.clear();

                    let color = style.get_color(theme);
                    let points = state.points.iter().cloned();
                    match *style {
                        ShapeStyle::Fill(_) => {
                            let triangles = match widget::polygon::triangles(points) {
                                None => &[],
                                Some(iter) => {
                                    triangles.extend(iter);
                                    &triangles[..]
                                }
                            };
                            let kind = PrimitiveKind::TrianglesSingleColor {
                                color: color.to_rgb(),
                                triangles: &triangles,
                            };
                            return Some(new_primitive(id, kind, scizzor, rect));
                        }

                        ShapeStyle::Outline(ref line_style) => {
                            let cap = line_style.get_cap(theme);
                            let thickness = line_style.get_thickness(theme);
                            let triangles =
                                match widget::point_path::triangles(points, cap, thickness) {
                                    None => &[],
                                    Some(iter) => {
                                        triangles.extend(iter);
                                        &triangles[..]
                                    }
                                };
                            let kind = PrimitiveKind::TrianglesSingleColor {
                                color: color.to_rgb(),
                                triangles: &triangles,
                            };
                            return Some(new_primitive(id, kind, scizzor, rect));
                        }
                    }
                }
            } else if container.type_id == state_type_id::<widget::Line>() {
                if let Some(line) = container.unique_widget_state::<widget::Line>() {
                    let graph::UniqueWidgetState {
                        ref state,
                        ref style,
                    } = *line;
                    triangles.clear();
                    let color = style.get_color(theme);
                    let cap = style.get_cap(theme);
                    let thickness = style.get_thickness(theme);
                    let points = std::iter::once(state.start).chain(std::iter::once(state.end));
                    let triangles = match widget::point_path::triangles(points, cap, thickness) {
                        None => &[],
                        Some(iter) => {
                            triangles.extend(iter);
                            &triangles[..]
                        }
                    };
                    let kind = PrimitiveKind::TrianglesSingleColor {
                        color: color.to_rgb(),
                        triangles: triangles,
                    };
                    return Some(new_primitive(id, kind, scizzor, rect));
                }
            } else if container.type_id == std::any::TypeId::of::<PointPathState>() {
                if let Some(point_path) =
                    container.state_and_style::<PointPathState, PointPathStyle>()
                {
                    let graph::UniqueWidgetState {
                        ref state,
                        ref style,
                    } = *point_path;
                    triangles.clear();
                    let color = style.get_color(theme);
                    let cap = style.get_cap(theme);
                    let thickness = style.get_thickness(theme);
                    let points = state.points.iter().map(|&t| t);
                    let triangles = match widget::point_path::triangles(points, cap, thickness) {
                        None => &[],
                        Some(iter) => {
                            triangles.extend(iter);
                            &triangles[..]
                        }
                    };
                    let kind = PrimitiveKind::TrianglesSingleColor {
                        color: color.to_rgb(),
                        triangles: triangles,
                    };
                    return Some(new_primitive(id, kind, scizzor, rect));
                }
            } else if container.type_id == state_type_id::<widget::Text>() {
                if let Some(text) = container.unique_widget_state::<widget::Text>() {
                    let graph::UniqueWidgetState {
                        ref state,
                        ref style,
                    } = *text;
                    let font_id = match style.font_id(theme).or_else(|| fonts.ids().next()) {
                        Some(id) => id,
                        None => continue,
                    };
                    let font = match fonts.get(font_id) {
                        Some(font) => font,
                        None => continue,
                    };

                    // Retrieve styling.
                    let color = style.color(theme);
                    let font_size = style.font_size(theme);
                    let line_spacing = style.line_spacing(theme);
                    let justify = style.justify(theme);
                    let y_align = Align::End;

                    let text = Text {
                        window_dim: window_rect.dim(),
                        text: &state.string,
                        line_infos: &state.line_infos,
                        font: font,
                        font_size: font_size,
                        rect: rect,
                        justify: justify,
                        y_align: y_align,
                        line_spacing: line_spacing,
                    };

                    let kind = PrimitiveKind::Text {
                        color: color,
                        text: text,
                        font_id: font_id,
                    };
                    return Some(new_primitive(id, kind, scizzor, rect));
                }
            } else if container.type_id == state_type_id::<widget::Image>() {
                use widget::primitive::image::{State, Style};
                if let Some(image) = container.state_and_style::<State, Style>() {
                    let graph::UniqueWidgetState {
                        ref state,
                        ref style,
                    } = *image;
                    let color = style.maybe_color(theme);
                    let kind = PrimitiveKind::Image {
                        color: color,
                        image_id: state.image_id,
                        source_rect: state.src_rect,
                    };
                    return Some(new_primitive(id, kind, scizzor, rect));
                }

            // Return an `Other` variant for all non-primitive widgets.
            } else {
                let kind = PrimitiveKind::Other(container);
                return Some(new_primitive(id, kind, scizzor, rect));
            }
        }

        None
    }

    /// Collect the `Primitives` list into an owned collection.
    ///
    /// This is useful for sending `Ui` rendering data across threads in an efficient manner.
    pub fn owned(mut self) -> OwnedPrimitives {
        let mut primitives = Vec::with_capacity(self.depth_order.len());
        let mut primitive_triangles_multi_color = Vec::new();
        let mut primitive_triangles_single_color = Vec::new();
        let mut primitive_line_infos = Vec::new();
        let mut texts_string = String::new();

        while let Some(Primitive {
            id,
            rect,
            scizzor,
            kind,
        }) = self.next()
        {
            let new = |kind| OwnedPrimitive {
                id: id,
                rect: rect,
                scizzor: scizzor,
                kind: kind,
            };

            match kind {
                PrimitiveKind::Rectangle { color } => {
                    let kind = OwnedPrimitiveKind::Rectangle { color: color };
                    primitives.push(new(kind));
                }

                PrimitiveKind::TrianglesSingleColor { color, triangles } => {
                    let start = primitive_triangles_single_color.len();
                    primitive_triangles_single_color.extend(triangles.iter().cloned());
                    let end = primitive_triangles_single_color.len();
                    let kind = OwnedPrimitiveKind::TrianglesSingleColor {
                        color: color,
                        triangle_range: start..end,
                    };
                    primitives.push(new(kind));
                }

                PrimitiveKind::TrianglesMultiColor { triangles } => {
                    let start = primitive_triangles_multi_color.len();
                    primitive_triangles_multi_color.extend(triangles.iter().cloned());
                    let end = primitive_triangles_multi_color.len();
                    let kind = OwnedPrimitiveKind::TrianglesMultiColor {
                        triangle_range: start..end,
                    };
                    primitives.push(new(kind));
                }

                PrimitiveKind::Image {
                    image_id,
                    color,
                    source_rect,
                } => {
                    let kind = OwnedPrimitiveKind::Image {
                        image_id: image_id,
                        color: color,
                        source_rect: source_rect,
                    };
                    primitives.push(new(kind));
                }

                PrimitiveKind::Text {
                    color,
                    font_id,
                    text,
                } => {
                    let Text {
                        window_dim,
                        text,
                        line_infos,
                        font,
                        font_size,
                        rect,
                        justify,
                        y_align,
                        line_spacing,
                        ..
                    } = text;

                    // Pack the `texts_string`.
                    let start_str_byte = texts_string.len();
                    texts_string.push_str(text);
                    let end_str_byte = texts_string.len();

                    // Pack the `line_infos`.
                    let start_line_info_idx = primitive_line_infos.len();
                    primitive_line_infos.extend(line_infos.iter().cloned());
                    let end_line_info_idx = primitive_line_infos.len();

                    let owned_text = OwnedText {
                        str_byte_range: start_str_byte..end_str_byte,
                        line_infos_range: start_line_info_idx..end_line_info_idx,
                        window_dim: window_dim,
                        font: font.clone(),
                        font_size: font_size,
                        rect: rect,
                        justify: justify,
                        y_align: y_align,
                        line_spacing: line_spacing,
                    };

                    let kind = OwnedPrimitiveKind::Text {
                        color: color,
                        font_id: font_id,
                        text: owned_text,
                    };
                    primitives.push(new(kind));
                }

                // TODO: Not sure how we should handle this yet.
                PrimitiveKind::Other(_) => (),
            }
        }

        OwnedPrimitives {
            primitives: primitives,
            triangles_single_color: primitive_triangles_single_color,
            triangles_multi_color: primitive_triangles_multi_color,
            line_infos: primitive_line_infos,
            texts_string: texts_string,
        }
    }
}

impl OwnedPrimitives {
    /// Produce an iterator-like type for yielding `Primitive`s.
    pub fn walk(&self) -> WalkOwnedPrimitives {
        let OwnedPrimitives {
            ref primitives,
            ref triangles_single_color,
            ref triangles_multi_color,
            ref line_infos,
            ref texts_string,
        } = *self;
        WalkOwnedPrimitives {
            primitives: primitives.iter(),
            triangles_single_color: triangles_single_color,
            triangles_multi_color: triangles_multi_color,
            line_infos: line_infos,
            texts_str: texts_string,
        }
    }
}

impl<'a> WalkOwnedPrimitives<'a> {
    /// Yield the next `Primitive` in order or rendering depth, bottom to top.
    pub fn next(&mut self) -> Option<Primitive> {
        let WalkOwnedPrimitives {
            ref mut primitives,
            triangles_single_color,
            triangles_multi_color,
            line_infos,
            texts_str,
        } = *self;

        primitives.next().map(
            move |&OwnedPrimitive {
                      id,
                      rect,
                      scizzor,
                      ref kind,
                  }| {
                let new = |kind| Primitive {
                    id: id,
                    rect: rect,
                    scizzor: scizzor,
                    kind: kind,
                };

                match *kind {
                    OwnedPrimitiveKind::Rectangle { color } => {
                        let kind = PrimitiveKind::Rectangle { color: color };
                        new(kind)
                    }

                    OwnedPrimitiveKind::TrianglesSingleColor {
                        color,
                        ref triangle_range,
                    } => {
                        let kind = PrimitiveKind::TrianglesSingleColor {
                            color: color,
                            triangles: &triangles_single_color[triangle_range.clone()],
                        };
                        new(kind)
                    }

                    OwnedPrimitiveKind::TrianglesMultiColor { ref triangle_range } => {
                        let kind = PrimitiveKind::TrianglesMultiColor {
                            triangles: &triangles_multi_color[triangle_range.clone()],
                        };
                        new(kind)
                    }

                    OwnedPrimitiveKind::Text {
                        color,
                        font_id,
                        ref text,
                    } => {
                        let OwnedText {
                            ref str_byte_range,
                            ref line_infos_range,
                            ref font,
                            window_dim,
                            font_size,
                            rect,
                            justify,
                            y_align,
                            line_spacing,
                        } = *text;

                        let text_str = &texts_str[str_byte_range.clone()];
                        let line_infos = &line_infos[line_infos_range.clone()];

                        let text = Text {
                            window_dim: window_dim,
                            text: text_str,
                            line_infos: line_infos,
                            font: font,
                            font_size: font_size,
                            rect: rect,
                            justify: justify,
                            y_align: y_align,
                            line_spacing: line_spacing,
                        };

                        let kind = PrimitiveKind::Text {
                            color: color,
                            font_id: font_id,
                            text: text,
                        };
                        new(kind)
                    }

                    OwnedPrimitiveKind::Image {
                        image_id,
                        color,
                        source_rect,
                    } => {
                        let kind = PrimitiveKind::Image {
                            image_id: image_id,
                            color: color,
                            source_rect: source_rect,
                        };
                        new(kind)
                    }
                }
            },
        )
    }
}

/// Simplify the constructor for a `Primitive`.
fn new_primitive(id: widget::Id, kind: PrimitiveKind, scizzor: Rect, rect: Rect) -> Primitive {
    Primitive {
        id: id,
        kind: kind,
        scizzor: scizzor,
        rect: rect,
    }
}

/// Retrieves the next visible widget from the `depth_order`, updating the `crop_stack` as
/// necessary.
fn next_widget<'a>(
    depth_order: &mut std::slice::Iter<widget::Id>,
    graph: &'a Graph,
    crop_stack: &mut Vec<(widget::Id, Rect)>,
    window_rect: Rect,
) -> Option<(widget::Id, Rect, &'a graph::Container)> {
    while let Some(&id) = depth_order.next() {
        let container = match graph.widget(id) {
            Some(container) => container,
            None => continue,
        };

        // If we're currently using a cropped context and the current `crop_parent_idx` is
        // *not* a depth-wise parent of the widget at the current `idx`, we should pop that
        // cropped context from the stack as we are done with it.
        while let Some(&(crop_parent_idx, _)) = crop_stack.last() {
            if graph.does_recursive_depth_edge_exist(crop_parent_idx, id) {
                break;
            } else {
                crop_stack.pop();
            }
        }

        // Check the stack for the current Context.
        let scizzor = crop_stack
            .last()
            .map(|&(_, scizzor)| scizzor)
            .unwrap_or(window_rect);

        // If the current widget should crop its children, we need to add a rect for it to
        // the top of the crop stack.
        if container.crop_kids {
            let scizzor_rect = container
                .kid_area
                .rect
                .overlap(scizzor)
                .unwrap_or_else(|| Rect::from_xy_dim([0.0, 0.0], [0.0, 0.0]));
            crop_stack.push((id, scizzor_rect));
        }

        // We only want to return primitives that are actually visible.
        let is_visible = container.rect.overlap(scizzor).is_some()
            && graph::algo::cropped_area_of_widget(graph, id).is_some();
        if !is_visible {
            continue;
        }

        return Some((id, scizzor, container));
    }

    None
}