| ... | @@ -135,6 +135,7 @@ impl TextEngine { | ... | @@ -135,6 +135,7 @@ impl TextEngine { |
| 135 | let mut start = 0; | 135 | let mut start = 0; |
| 136 | for (index, span) in paragraph.spans().iter().enumerate() { | 136 | for (index, span) in paragraph.spans().iter().enumerate() { |
| 137 | let format = &span.format; | 137 | let format = &span.format; |
| | 138 | let link = format.hyperlink == Some(true); |
| 138 | let size = format.font_size.unwrap_or(11.0); | 139 | let size = format.font_size.unwrap_or(11.0); |
| 139 | if !size.is_finite() || size <= 0.0 { | 140 | if !size.is_finite() || size <= 0.0 { |
| 140 | return Err(LayoutError::InvalidFontSize); | 141 | return Err(LayoutError::InvalidFontSize); |
| ... | @@ -160,10 +161,15 @@ impl TextEngine { | ... | @@ -160,10 +161,15 @@ impl TextEngine { |
| 160 | FontStyle::Normal | 161 | FontStyle::Normal |
| 161 | }), | 162 | }), |
| 162 | StyleProperty::Brush(TextBrush { | 163 | StyleProperty::Brush(TextBrush { |
| 163 | color: format.color.unwrap_or(0), | 164 | // Links take OneNote's blue unless given a colour of their own. |
| | 165 | color: match format.color { |
| | 166 | Some(color) if color != 0xff000000 => color, |
| | 167 | _ if link => 0x00ff0000, |
| | 168 | _ => 0, |
| | 169 | }, |
| 164 | highlight: format.highlight.filter(|color| *color != 0xff000000), | 170 | highlight: format.highlight.filter(|color| *color != 0xff000000), |
| 165 | }), | 171 | }), |
| 166 | StyleProperty::Underline(format.underline.unwrap_or(false)), | 172 | StyleProperty::Underline(format.underline.unwrap_or(false) || link), |
| 167 | StyleProperty::Strikethrough(format.strike.unwrap_or(false)), | 173 | StyleProperty::Strikethrough(format.strike.unwrap_or(false)), |
| 168 | ]; | 174 | ]; |
| 169 | for property in properties { | 175 | for property in properties { |
| ... | @@ -554,6 +560,43 @@ mod tests { | ... | @@ -554,6 +560,43 @@ mod tests { |
| 554 | assert_eq!(fonts.len(), 1); | 560 | assert_eq!(fonts.len(), 1); |
| 555 | } | 561 | } |
| 556 | | 562 | |
| | 563 | #[test] |
| | 564 | fn links_draw_blue_and_underlined_unless_coloured() { |
| | 565 | let mut engine = TextEngine::default(); |
| | 566 | let link = Format { |
| | 567 | hyperlink: Some(true), |
| | 568 | ..Format::default() |
| | 569 | }; |
| | 570 | let layout = engine |
| | 571 | .layout( |
| | 572 | &Paragraph::from_runs([ |
| | 573 | ("plain ".into(), Format::default()), |
| | 574 | ("link".into(), link.clone()), |
| | 575 | ( |
| | 576 | " red".into(), |
| | 577 | Format { |
| | 578 | color: Some(0x0000_00ff), |
| | 579 | ..link |
| | 580 | }, |
| | 581 | ), |
| | 582 | ]), |
| | 583 | 300.0, |
| | 584 | ) |
| | 585 | .unwrap(); |
| | 586 | let runs: Vec<_> = layout |
| | 587 | .lines() |
| | 588 | .flat_map(|(line, _)| line.items().collect::<Vec<_>>()) |
| | 589 | .filter_map(|item| match item { |
| | 590 | PositionedLayoutItem::GlyphRun(run) => { |
| | 591 | let style = run.style(); |
| | 592 | Some((style.brush.color, style.underline.is_some())) |
| | 593 | } |
| | 594 | _ => None, |
| | 595 | }) |
| | 596 | .collect(); |
| | 597 | assert_eq!(runs, [(0, false), (0x00ff_0000, true), (0x0000_00ff, true)]); |
| | 598 | } |
| | 599 | |
| 557 | #[test] | 600 | #[test] |
| 558 | fn paragraph_alignment_offsets_lines_within_the_wrap_width() { | 601 | fn paragraph_alignment_offsets_lines_within_the_wrap_width() { |
| 559 | let mut engine = TextEngine::default(); | 602 | let mut engine = TextEngine::default(); |