node.rs

   1use log::warn;
   2
   3use crate::{
   4    color::Color,
   5    fonts::HighlightStyle,
   6    geometry::{
   7        rect::RectF,
   8        vector::{vec2f, Vector2F},
   9    },
  10    json::{json, ToJson},
  11    scene,
  12    serde_json::Value,
  13    text_layout::{Line, ShapedBoundary},
  14    AnyElement, AppContext, Element, LayoutContext, Quad, SceneBuilder, SizeConstraint, View,
  15    ViewContext,
  16};
  17
  18use std::{any::Any, borrow::Cow, f32, ops::Range};
  19
  20use self::length::Length;
  21
  22use super::layout_highlighted_chunks;
  23
  24pub struct Node<V: View> {
  25    style: NodeStyle,
  26    content: Vec<AnyElement<V>>,
  27}
  28
  29pub fn column<V: View>() -> Node<V> {
  30    Node::default()
  31}
  32
  33pub fn row<V: View>() -> Node<V> {
  34    Node {
  35        style: NodeStyle {
  36            axis: Axis3d::X,
  37            ..Default::default()
  38        },
  39        content: Default::default(),
  40    }
  41}
  42
  43pub fn stack<V: View>() -> Node<V> {
  44    Node {
  45        style: NodeStyle {
  46            axis: Axis3d::Z,
  47            ..Default::default()
  48        },
  49        content: Default::default(),
  50    }
  51}
  52
  53impl<V: View> Default for Node<V> {
  54    fn default() -> Self {
  55        Self {
  56            style: Default::default(),
  57            content: Default::default(),
  58        }
  59    }
  60}
  61
  62impl<V: View> Node<V> {
  63    pub fn child(mut self, child: impl Element<V>) -> Self {
  64        self.content.push(child.into_any());
  65        self
  66    }
  67
  68    pub fn children<I, E>(mut self, children: I) -> Self
  69    where
  70        I: IntoIterator<Item = E>,
  71        E: Element<V>,
  72    {
  73        self.content
  74            .extend(children.into_iter().map(|child| child.into_any()));
  75        self
  76    }
  77
  78    pub fn width(mut self, width: impl Into<Length>) -> Self {
  79        self.style.width = width.into();
  80        self
  81    }
  82
  83    pub fn height(mut self, height: impl Into<Length>) -> Self {
  84        self.style.height = height.into();
  85        self
  86    }
  87
  88    pub fn fill(mut self, fill: impl Into<Fill>) -> Self {
  89        self.style.fill = fill.into();
  90        self
  91    }
  92
  93    pub fn row(mut self) -> Self {
  94        self.style.axis = Axis3d::X;
  95        self
  96    }
  97
  98    pub fn stack(mut self) -> Self {
  99        self.style.axis = Axis3d::Z;
 100        self
 101    }
 102
 103    fn layout_2d_children(
 104        &mut self,
 105        axis: Axis2d,
 106        size: Vector2F,
 107        view: &mut V,
 108        cx: &mut LayoutContext<V>,
 109    ) -> Vector2F {
 110        let mut total_flex: Option<f32> = None;
 111        let mut total_size = 0.0;
 112        let mut cross_axis_max: f32 = 0.0;
 113
 114        // First pass: Layout non-flex children only
 115        for child in &mut self.content {
 116            let child_flex = child.metadata::<NodeStyle>().and_then(|style| match axis {
 117                Axis2d::X => style.width.flex(),
 118                Axis2d::Y => style.height.flex(),
 119            });
 120
 121            if let Some(child_flex) = child_flex {
 122                *total_flex.get_or_insert(0.) += child_flex;
 123            } else {
 124                match axis {
 125                    Axis2d::X => {
 126                        let child_constraint =
 127                            SizeConstraint::new(Vector2F::zero(), vec2f(f32::INFINITY, size.y()));
 128                        let child_size = child.layout(child_constraint, view, cx);
 129                        cross_axis_max = cross_axis_max.max(child_size.y());
 130                        total_size += child_size.x();
 131                    }
 132                    Axis2d::Y => {
 133                        let child_constraint =
 134                            SizeConstraint::new(Vector2F::zero(), vec2f(size.x(), f32::INFINITY));
 135                        let child_size = child.layout(child_constraint, view, cx);
 136                        cross_axis_max = cross_axis_max.max(child_size.x());
 137                        total_size += child_size.y();
 138                    }
 139                }
 140            }
 141        }
 142
 143        let remaining_space = match axis {
 144            Axis2d::X => size.x() - total_size,
 145            Axis2d::Y => size.y() - total_size,
 146        };
 147
 148        // Second pass: Layout flexible children
 149        if let Some(total_flex) = total_flex {
 150            if total_flex > 0. {
 151                let space_per_flex = remaining_space.max(0.) / total_flex;
 152
 153                for child in &mut self.content {
 154                    let child_flex = child.metadata::<NodeStyle>().and_then(|style| match axis {
 155                        Axis2d::X => style.width.flex(),
 156                        Axis2d::Y => style.height.flex(),
 157                    });
 158                    if let Some(child_flex) = child_flex {
 159                        let child_max = space_per_flex * child_flex;
 160                        let mut child_constraint = SizeConstraint::new(Vector2F::zero(), size);
 161                        match axis {
 162                            Axis2d::X => {
 163                                child_constraint.min.set_x(0.0);
 164                                child_constraint.max.set_x(child_max);
 165                            }
 166                            Axis2d::Y => {
 167                                child_constraint.min.set_y(0.0);
 168                                child_constraint.max.set_y(child_max);
 169                            }
 170                        }
 171
 172                        let child_size = child.layout(child_constraint, view, cx);
 173                        cross_axis_max = match axis {
 174                            Axis2d::X => {
 175                                total_size += child_size.x();
 176                                cross_axis_max.max(child_size.y())
 177                            }
 178                            Axis2d::Y => {
 179                                total_size += child_size.y();
 180                                cross_axis_max.max(child_size.x())
 181                            }
 182                        };
 183                    }
 184                }
 185            }
 186        }
 187
 188        let size = match axis {
 189            Axis2d::X => vec2f(total_size, cross_axis_max),
 190            Axis2d::Y => vec2f(cross_axis_max, total_size),
 191        };
 192        size
 193    }
 194
 195    fn paint_2d_children(
 196        &mut self,
 197        scene: &mut SceneBuilder,
 198        axis: Axis2d,
 199        bounds: RectF,
 200        visible_bounds: RectF,
 201        size_of_children: &mut Vector2F,
 202        view: &mut V,
 203        cx: &mut ViewContext<V>,
 204    ) {
 205        let parent_size = bounds.size();
 206        let mut child_origin = bounds.origin();
 207
 208        // Align all children together along the primary axis
 209        let mut align_horizontally = false;
 210        let mut align_vertically = false;
 211        match axis {
 212            Axis2d::X => align_horizontally = true,
 213            Axis2d::Y => align_vertically = true,
 214        }
 215        align_child(
 216            &mut child_origin,
 217            parent_size,
 218            *size_of_children,
 219            self.style.align.0,
 220            align_horizontally,
 221            align_vertically,
 222        );
 223
 224        for child in &mut self.content {
 225            // Align each child along the cross axis
 226            align_horizontally = !align_horizontally;
 227            align_vertically = !align_vertically;
 228            align_child(
 229                &mut child_origin,
 230                parent_size,
 231                child.size(),
 232                self.style.align.0,
 233                align_horizontally,
 234                align_vertically,
 235            );
 236
 237            child.paint(scene, child_origin, visible_bounds, view, cx);
 238
 239            // Advance along the primary axis by the size of this child
 240            match axis {
 241                Axis2d::X => child_origin.set_x(child_origin.x() + child.size().x()),
 242                Axis2d::Y => child_origin.set_y(child_origin.y() + child.size().y()),
 243            }
 244        }
 245    }
 246
 247    // fn layout_stacked_children(
 248    //     &mut self,
 249    //     constraint: SizeConstraint,
 250    //     view: &mut V,
 251    //     cx: &mut LayoutContext<V>,
 252    // ) -> Vector2F {
 253    //     let mut size = Vector2F::zero();
 254
 255    //     for child in &mut self.children {
 256    //         let child_size = child.layout(constraint, view, cx);
 257    //         size.set_x(size.x().max(child_size.x()));
 258    //         size.set_y(size.y().max(child_size.y()));
 259    //     }
 260
 261    //     size
 262    // }
 263
 264    fn inset_size(&self) -> Vector2F {
 265        self.padding_size() + self.border_size() + self.margin_size()
 266    }
 267
 268    fn margin_size(&self) -> Vector2F {
 269        vec2f(
 270            self.style.margin.left + self.style.margin.right,
 271            self.style.margin.top + self.style.margin.bottom,
 272        )
 273    }
 274
 275    fn padding_size(&self) -> Vector2F {
 276        vec2f(
 277            self.style.padding.left + self.style.padding.right,
 278            self.style.padding.top + self.style.padding.bottom,
 279        )
 280    }
 281
 282    fn border_size(&self) -> Vector2F {
 283        let mut x = 0.0;
 284        if self.style.border.left {
 285            x += self.style.border.width;
 286        }
 287        if self.style.border.right {
 288            x += self.style.border.width;
 289        }
 290
 291        let mut y = 0.0;
 292        if self.style.border.top {
 293            y += self.style.border.width;
 294        }
 295        if self.style.border.bottom {
 296            y += self.style.border.width;
 297        }
 298
 299        vec2f(x, y)
 300    }
 301}
 302
 303impl<V: View> Element<V> for Node<V> {
 304    type LayoutState = Vector2F; // Content size
 305    type PaintState = ();
 306
 307    fn layout(
 308        &mut self,
 309        constraint: SizeConstraint,
 310        view: &mut V,
 311        cx: &mut LayoutContext<V>,
 312    ) -> (Vector2F, Self::LayoutState) {
 313        dbg!(constraint.max);
 314
 315        let mut size = Vector2F::zero();
 316        let margin_size = self.margin_size();
 317        match self.style.width {
 318            Length::Hug => size.set_x(f32::INFINITY),
 319            Length::Fixed(width) => size.set_x(width + margin_size.x()),
 320            Length::Auto { min, max, .. } => size.set_x(constraint.max.x().max(min).min(max)),
 321        }
 322        match self.style.height {
 323            Length::Hug => size.set_y(f32::INFINITY),
 324            Length::Fixed(height) => size.set_y(height + margin_size.y()),
 325            Length::Auto { min, max, .. } => size.set_y(constraint.max.y().max(min).min(max)),
 326        }
 327
 328        // Impose horizontal constraints
 329        if constraint.min.x().is_finite() {
 330            size.set_x(size.x().max(constraint.min.x()));
 331        }
 332        size.set_x(size.x().min(constraint.max.x()));
 333
 334        // Impose vertical constraints
 335        if constraint.min.y().is_finite() {
 336            size.set_y(size.y().max(constraint.min.y()));
 337        }
 338        size.set_y(size.y().min(constraint.max.y()));
 339
 340        let inset_size = self.inset_size();
 341        let inner_size = size - inset_size;
 342        let size_of_children = match self.style.axis {
 343            Axis3d::X => self.layout_2d_children(Axis2d::X, inner_size, view, cx),
 344            Axis3d::Y => self.layout_2d_children(Axis2d::Y, inner_size, view, cx),
 345            Axis3d::Z => todo!(), // self.layout_stacked_children(inner_constraint, view, cx),
 346        };
 347
 348        if matches!(self.style.width, Length::Hug) {
 349            size.set_x(size_of_children.x() + inset_size.x());
 350        }
 351        if matches!(self.style.height, Length::Hug) {
 352            size.set_y(size_of_children.y() + inset_size.y());
 353        }
 354
 355        (size, size_of_children)
 356    }
 357
 358    fn paint(
 359        &mut self,
 360        scene: &mut SceneBuilder,
 361        bounds: RectF,
 362        visible_bounds: RectF,
 363        size_of_children: &mut Vector2F,
 364        view: &mut V,
 365        cx: &mut ViewContext<V>,
 366    ) -> Self::PaintState {
 367        let margin = &self.style.margin;
 368
 369        // Account for margins
 370        let content_bounds = RectF::from_points(
 371            bounds.origin() + vec2f(margin.left, margin.top),
 372            bounds.lower_right() - vec2f(margin.right, margin.bottom),
 373        );
 374
 375        // Paint drop shadow
 376        for shadow in &self.style.shadows {
 377            scene.push_shadow(scene::Shadow {
 378                bounds: content_bounds + shadow.offset,
 379                corner_radius: self.style.corner_radius,
 380                sigma: shadow.blur,
 381                color: shadow.color,
 382            });
 383        }
 384
 385        // // Paint cursor style
 386        // if let Some(hit_bounds) = content_bounds.intersection(visible_bounds) {
 387        //     if let Some(style) = self.style.cursor {
 388        //         scene.push_cursor_region(CursorRegion {
 389        //             bounds: hit_bounds,
 390        //             style,
 391        //         });
 392        //     }
 393        // }
 394
 395        // Render the background and/or the border (if it not an overlay border).
 396        let Fill::Color(fill_color) = self.style.fill;
 397        let is_fill_visible = !fill_color.is_fully_transparent();
 398        if is_fill_visible || self.style.border.is_visible() {
 399            scene.push_quad(Quad {
 400                bounds: content_bounds,
 401                background: is_fill_visible.then_some(fill_color),
 402                border: scene::Border {
 403                    width: self.style.border.width,
 404                    color: self.style.border.color,
 405                    overlay: false,
 406                    top: self.style.border.top,
 407                    right: self.style.border.right,
 408                    bottom: self.style.border.bottom,
 409                    left: self.style.border.left,
 410                },
 411                corner_radius: self.style.corner_radius,
 412            });
 413        }
 414
 415        if !self.content.is_empty() {
 416            // Account for padding first.
 417            let padding = &self.style.padding;
 418            let padded_bounds = RectF::from_points(
 419                content_bounds.origin() + vec2f(padding.left, padding.top),
 420                content_bounds.lower_right() - vec2f(padding.right, padding.top),
 421            );
 422
 423            match self.style.axis {
 424                Axis3d::X => self.paint_2d_children(
 425                    scene,
 426                    Axis2d::X,
 427                    padded_bounds,
 428                    visible_bounds,
 429                    size_of_children,
 430                    view,
 431                    cx,
 432                ),
 433                Axis3d::Y => self.paint_2d_children(
 434                    scene,
 435                    Axis2d::Y,
 436                    padded_bounds,
 437                    visible_bounds,
 438                    size_of_children,
 439                    view,
 440                    cx,
 441                ),
 442                Axis3d::Z => todo!(),
 443            }
 444        }
 445    }
 446
 447    fn rect_for_text_range(
 448        &self,
 449        range_utf16: Range<usize>,
 450        _: RectF,
 451        _: RectF,
 452        _: &Self::LayoutState,
 453        _: &Self::PaintState,
 454        view: &V,
 455        cx: &ViewContext<V>,
 456    ) -> Option<RectF> {
 457        self.content
 458            .iter()
 459            .find_map(|child| child.rect_for_text_range(range_utf16.clone(), view, cx))
 460    }
 461
 462    fn debug(
 463        &self,
 464        bounds: RectF,
 465        _: &Self::LayoutState,
 466        _: &Self::PaintState,
 467        view: &V,
 468        cx: &ViewContext<V>,
 469    ) -> Value {
 470        json!({
 471            "type": "Node",
 472            "bounds": bounds.to_json(),
 473            // TODO!
 474            // "children": self.content.iter().map(|child| child.debug(view, cx)).collect::<Vec<Value>>()
 475        })
 476    }
 477
 478    fn metadata(&self) -> Option<&dyn Any> {
 479        Some(&self.style)
 480    }
 481}
 482
 483fn align_child(
 484    child_origin: &mut Vector2F,
 485    parent_size: Vector2F,
 486    child_size: Vector2F,
 487    alignment: Vector2F,
 488    horizontal: bool,
 489    vertical: bool,
 490) {
 491    let parent_center = parent_size / 2.;
 492    let parent_target = parent_center + parent_center * alignment;
 493    let child_center = child_size / 2.;
 494    let child_target = child_center + child_center * alignment;
 495
 496    if horizontal {
 497        child_origin.set_x(child_origin.x() + parent_target.x() - child_target.x())
 498    }
 499    if vertical {
 500        child_origin.set_y(child_origin.y() + parent_target.y() - child_target.y());
 501    }
 502}
 503
 504struct Interactive<Style> {
 505    default: Style,
 506    hovered: Style,
 507    active: Style,
 508    disabled: Style,
 509}
 510
 511#[derive(Clone, Default)]
 512pub struct NodeStyle {
 513    axis: Axis3d,
 514    wrap: bool,
 515    align: Align,
 516    overflow_x: Overflow,
 517    overflow_y: Overflow,
 518    gap_x: Gap,
 519    gap_y: Gap,
 520
 521    width: Length,
 522    height: Length,
 523    margin: Edges<f32>,
 524    padding: Edges<f32>,
 525
 526    text_color: Option<Color>,
 527    font_size: Option<f32>,
 528    font_style: Option<FontStyle>,
 529    font_weight: Option<FontWeight>,
 530
 531    opacity: f32,
 532    fill: Fill,
 533    border: Border,
 534    corner_radius: f32, // corner radius matches swift!
 535    shadows: Vec<Shadow>,
 536}
 537
 538// Sides?
 539#[derive(Clone, Default)]
 540struct Edges<T> {
 541    top: T,
 542    bottom: T,
 543    left: T,
 544    right: T,
 545}
 546
 547#[derive(Clone, Default)]
 548struct CornerRadii {
 549    top_left: f32,
 550    top_right: f32,
 551    bottom_right: f32,
 552    bottom_left: f32,
 553}
 554
 555#[derive(Clone)]
 556pub enum Fill {
 557    Color(Color),
 558}
 559
 560impl From<Color> for Fill {
 561    fn from(value: Color) -> Self {
 562        Fill::Color(value)
 563    }
 564}
 565
 566impl Default for Fill {
 567    fn default() -> Self {
 568        Fill::Color(Color::default())
 569    }
 570}
 571
 572#[derive(Clone, Default)]
 573struct Border {
 574    color: Color,
 575    width: f32,
 576    top: bool,
 577    bottom: bool,
 578    left: bool,
 579    right: bool,
 580}
 581
 582impl Border {
 583    fn is_visible(&self) -> bool {
 584        self.width > 0.
 585            && !self.color.is_fully_transparent()
 586            && (self.top || self.bottom || self.left || self.right)
 587    }
 588}
 589
 590pub mod length {
 591    #[derive(Clone, Copy, Default)]
 592    pub enum Length {
 593        #[default]
 594        Hug,
 595        Fixed(f32),
 596        Auto {
 597            flex: f32,
 598            min: f32,
 599            max: f32,
 600        },
 601    }
 602
 603    impl From<f32> for Length {
 604        fn from(value: f32) -> Self {
 605            Length::Fixed(value)
 606        }
 607    }
 608
 609    pub fn auto() -> Length {
 610        flex(1.)
 611    }
 612
 613    pub fn flex(flex: f32) -> Length {
 614        Length::Auto {
 615            flex,
 616            min: 0.,
 617            max: f32::INFINITY,
 618        }
 619    }
 620
 621    pub fn constrained(flex: f32, min: Option<f32>, max: Option<f32>) -> Length {
 622        Length::Auto {
 623            flex,
 624            min: min.unwrap_or(0.),
 625            max: max.unwrap_or(f32::INFINITY),
 626        }
 627    }
 628
 629    impl Length {
 630        pub fn flex(&self) -> Option<f32> {
 631            match self {
 632                Length::Auto { flex, .. } => Some(*flex),
 633                _ => None,
 634            }
 635        }
 636    }
 637}
 638
 639#[derive(Clone)]
 640struct Align(Vector2F);
 641
 642impl Default for Align {
 643    fn default() -> Self {
 644        Self(vec2f(-1., -1.))
 645    }
 646}
 647
 648#[derive(Clone, Copy, Default)]
 649enum Axis3d {
 650    X,
 651    #[default]
 652    Y,
 653    Z,
 654}
 655
 656impl Axis3d {
 657    fn to_2d(self) -> Option<Axis2d> {
 658        match self {
 659            Axis3d::X => Some(Axis2d::X),
 660            Axis3d::Y => Some(Axis2d::Y),
 661            Axis3d::Z => None,
 662        }
 663    }
 664}
 665
 666#[derive(Clone, Copy, Default)]
 667enum Axis2d {
 668    X,
 669    #[default]
 670    Y,
 671}
 672
 673#[derive(Clone, Copy, Default)]
 674enum Overflow {
 675    #[default]
 676    Visible,
 677    Hidden,
 678    Auto,
 679}
 680
 681#[derive(Clone, Copy)]
 682enum Gap {
 683    Fixed(f32),
 684    Around,
 685    Between,
 686    Even,
 687}
 688
 689impl Default for Gap {
 690    fn default() -> Self {
 691        Gap::Fixed(0.)
 692    }
 693}
 694
 695#[derive(Clone, Copy, Default)]
 696struct Shadow {
 697    offset: Vector2F,
 698    blur: f32,
 699    color: Color,
 700}
 701
 702#[derive(Clone, Copy, Default)]
 703enum FontStyle {
 704    #[default]
 705    Normal,
 706    Italic,
 707    Oblique,
 708}
 709
 710#[derive(Clone, Copy, Default)]
 711enum FontWeight {
 712    Thin,
 713    ExtraLight,
 714    Light,
 715    #[default]
 716    Normal,
 717    Medium,
 718    Semibold,
 719    Bold,
 720    ExtraBold,
 721    Black,
 722}
 723
 724pub struct Text {
 725    text: Cow<'static, str>,
 726    highlights: Option<Box<[(Range<usize>, HighlightStyle)]>>,
 727    custom_runs: Option<(
 728        Box<[Range<usize>]>,
 729        Box<dyn FnMut(usize, RectF, &mut SceneBuilder, &mut AppContext)>,
 730    )>,
 731}
 732
 733pub struct TextLayout {
 734    shaped_lines: Vec<Line>,
 735    wrap_boundaries: Vec<Vec<ShapedBoundary>>,
 736    line_height: f32,
 737}
 738
 739impl<V: View> Element<V> for Text {
 740    type LayoutState = TextLayout;
 741    type PaintState = ();
 742
 743    fn layout(
 744        &mut self,
 745        constraint: SizeConstraint,
 746        _: &mut V,
 747        cx: &mut LayoutContext<V>,
 748    ) -> (Vector2F, Self::LayoutState) {
 749        // Convert the string and highlight ranges into an iterator of highlighted chunks.
 750
 751        let mut offset = 0;
 752        let mut highlight_ranges = self
 753            .highlights
 754            .as_ref()
 755            .map_or(Default::default(), AsRef::as_ref)
 756            .iter()
 757            .peekable();
 758        let chunks = std::iter::from_fn(|| {
 759            let result;
 760            if let Some((range, highlight_style)) = highlight_ranges.peek() {
 761                if offset < range.start {
 762                    result = Some((&self.text[offset..range.start], None));
 763                    offset = range.start;
 764                } else if range.end <= self.text.len() {
 765                    result = Some((&self.text[range.clone()], Some(*highlight_style)));
 766                    highlight_ranges.next();
 767                    offset = range.end;
 768                } else {
 769                    warn!(
 770                        "Highlight out of text range. Text len: {}, Highlight range: {}..{}",
 771                        self.text.len(),
 772                        range.start,
 773                        range.end
 774                    );
 775                    result = None;
 776                }
 777            } else if offset < self.text.len() {
 778                result = Some((&self.text[offset..], None));
 779                offset = self.text.len();
 780            } else {
 781                result = None;
 782            }
 783            result
 784        });
 785
 786        let style = cx.text_style();
 787
 788        // Perform shaping on these highlighted chunks
 789        let shaped_lines = layout_highlighted_chunks(
 790            chunks,
 791            &style,
 792            cx.text_layout_cache(),
 793            &cx.font_cache,
 794            usize::MAX,
 795            self.text.matches('\n').count() + 1,
 796        );
 797
 798        // If line wrapping is enabled, wrap each of the shaped lines.
 799        let font_id = style.font_id;
 800        let mut line_count = 0;
 801        let mut max_line_width = 0_f32;
 802        let mut wrap_boundaries = Vec::new();
 803        let mut wrapper = cx.font_cache.line_wrapper(font_id, style.font_size);
 804        for (line, shaped_line) in self.text.split('\n').zip(&shaped_lines) {
 805            if style.soft_wrap {
 806                let boundaries = wrapper
 807                    .wrap_shaped_line(line, shaped_line, constraint.max.x())
 808                    .collect::<Vec<_>>();
 809                line_count += boundaries.len() + 1;
 810                wrap_boundaries.push(boundaries);
 811            } else {
 812                line_count += 1;
 813            }
 814            max_line_width = max_line_width.max(shaped_line.width());
 815        }
 816
 817        let line_height = cx.font_cache.line_height(style.font_size);
 818        let size = vec2f(
 819            max_line_width
 820                .ceil()
 821                .max(constraint.min.x())
 822                .min(constraint.max.x()),
 823            (line_height * line_count as f32).ceil(),
 824        );
 825        (
 826            size,
 827            TextLayout {
 828                shaped_lines,
 829                wrap_boundaries,
 830                line_height,
 831            },
 832        )
 833    }
 834
 835    fn paint(
 836        &mut self,
 837        scene: &mut SceneBuilder,
 838        bounds: RectF,
 839        visible_bounds: RectF,
 840        layout: &mut Self::LayoutState,
 841        _: &mut V,
 842        cx: &mut ViewContext<V>,
 843    ) -> Self::PaintState {
 844        let mut origin = bounds.origin();
 845        let empty = Vec::new();
 846        let mut callback = |_, _, _: &mut SceneBuilder, _: &mut AppContext| {};
 847
 848        let mouse_runs;
 849        let custom_run_callback;
 850        if let Some((runs, build_region)) = &mut self.custom_runs {
 851            mouse_runs = runs.iter();
 852            custom_run_callback = build_region.as_mut();
 853        } else {
 854            mouse_runs = [].iter();
 855            custom_run_callback = &mut callback;
 856        }
 857        let mut custom_runs = mouse_runs.enumerate().peekable();
 858
 859        let mut offset = 0;
 860        for (ix, line) in layout.shaped_lines.iter().enumerate() {
 861            let wrap_boundaries = layout.wrap_boundaries.get(ix).unwrap_or(&empty);
 862            let boundaries = RectF::new(
 863                origin,
 864                vec2f(
 865                    bounds.width(),
 866                    (wrap_boundaries.len() + 1) as f32 * layout.line_height,
 867                ),
 868            );
 869
 870            let style = cx.text_style();
 871            if boundaries.intersects(visible_bounds) {
 872                if style.soft_wrap {
 873                    line.paint_wrapped(
 874                        scene,
 875                        origin,
 876                        visible_bounds,
 877                        layout.line_height,
 878                        wrap_boundaries,
 879                        cx,
 880                    );
 881                } else {
 882                    line.paint(scene, origin, visible_bounds, layout.line_height, cx);
 883                }
 884            }
 885
 886            // Paint any custom runs that intersect this line.
 887            let end_offset = offset + line.len();
 888            if let Some((custom_run_ix, custom_run_range)) = custom_runs.peek().cloned() {
 889                if custom_run_range.start < end_offset {
 890                    let mut current_custom_run = None;
 891                    if custom_run_range.start <= offset {
 892                        current_custom_run = Some((custom_run_ix, custom_run_range.end, origin));
 893                    }
 894
 895                    let mut glyph_origin = origin;
 896                    let mut prev_position = 0.;
 897                    let mut wrap_boundaries = wrap_boundaries.iter().copied().peekable();
 898                    for (run_ix, glyph_ix, glyph) in
 899                        line.runs().iter().enumerate().flat_map(|(run_ix, run)| {
 900                            run.glyphs()
 901                                .iter()
 902                                .enumerate()
 903                                .map(move |(ix, glyph)| (run_ix, ix, glyph))
 904                        })
 905                    {
 906                        glyph_origin.set_x(glyph_origin.x() + glyph.position.x() - prev_position);
 907                        prev_position = glyph.position.x();
 908
 909                        // If we've reached a soft wrap position, move down one line. If there
 910                        // is a custom run in-progress, paint it.
 911                        if wrap_boundaries
 912                            .peek()
 913                            .map_or(false, |b| b.run_ix == run_ix && b.glyph_ix == glyph_ix)
 914                        {
 915                            if let Some((run_ix, _, run_origin)) = &mut current_custom_run {
 916                                let bounds = RectF::from_points(
 917                                    *run_origin,
 918                                    glyph_origin + vec2f(0., layout.line_height),
 919                                );
 920                                custom_run_callback(*run_ix, bounds, scene, cx);
 921                                *run_origin =
 922                                    vec2f(origin.x(), glyph_origin.y() + layout.line_height);
 923                            }
 924                            wrap_boundaries.next();
 925                            glyph_origin = vec2f(origin.x(), glyph_origin.y() + layout.line_height);
 926                        }
 927
 928                        // If we've reached the end of the current custom run, paint it.
 929                        if let Some((run_ix, run_end_offset, run_origin)) = current_custom_run {
 930                            if offset + glyph.index == run_end_offset {
 931                                current_custom_run.take();
 932                                let bounds = RectF::from_points(
 933                                    run_origin,
 934                                    glyph_origin + vec2f(0., layout.line_height),
 935                                );
 936                                custom_run_callback(run_ix, bounds, scene, cx);
 937                                custom_runs.next();
 938                            }
 939
 940                            if let Some((_, run_range)) = custom_runs.peek() {
 941                                if run_range.start >= end_offset {
 942                                    break;
 943                                }
 944                                if run_range.start == offset + glyph.index {
 945                                    current_custom_run =
 946                                        Some((run_ix, run_range.end, glyph_origin));
 947                                }
 948                            }
 949                        }
 950
 951                        // If we've reached the start of a new custom run, start tracking it.
 952                        if let Some((run_ix, run_range)) = custom_runs.peek() {
 953                            if offset + glyph.index == run_range.start {
 954                                current_custom_run = Some((*run_ix, run_range.end, glyph_origin));
 955                            }
 956                        }
 957                    }
 958
 959                    // If a custom run extends beyond the end of the line, paint it.
 960                    if let Some((run_ix, run_end_offset, run_origin)) = current_custom_run {
 961                        let line_end = glyph_origin + vec2f(line.width() - prev_position, 0.);
 962                        let bounds = RectF::from_points(
 963                            run_origin,
 964                            line_end + vec2f(0., layout.line_height),
 965                        );
 966                        custom_run_callback(run_ix, bounds, scene, cx);
 967                        if end_offset == run_end_offset {
 968                            custom_runs.next();
 969                        }
 970                    }
 971                }
 972            }
 973
 974            offset = end_offset + 1;
 975            origin.set_y(boundaries.max_y());
 976        }
 977    }
 978
 979    fn rect_for_text_range(
 980        &self,
 981        _: Range<usize>,
 982        _: RectF,
 983        _: RectF,
 984        _: &Self::LayoutState,
 985        _: &Self::PaintState,
 986        _: &V,
 987        _: &ViewContext<V>,
 988    ) -> Option<RectF> {
 989        None
 990    }
 991
 992    fn debug(
 993        &self,
 994        bounds: RectF,
 995        _: &Self::LayoutState,
 996        _: &Self::PaintState,
 997        _: &V,
 998        _: &ViewContext<V>,
 999    ) -> Value {
1000        json!({
1001            "type": "Text",
1002            "bounds": bounds.to_json(),
1003            "text": &self.text,
1004        })
1005    }
1006}