Implement underlines.
This commit is contained in:
parent
d63b3f23e9
commit
f097a6584e
|
@ -50,6 +50,11 @@ impl EvalParameters {
|
|||
kerning: span.kerning,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the height the font would be evaluated at.
|
||||
pub fn height(&self) -> Twips {
|
||||
self.height
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Collect, Copy)]
|
||||
|
@ -188,6 +193,13 @@ impl<'gc> Font<'gc> {
|
|||
Twips::new((self.0.leading as f32 * scale) as i32)
|
||||
}
|
||||
|
||||
/// Get the baseline from the top of the glyph at a given height.
|
||||
pub fn get_baseline_for_height(self, height: Twips) -> Twips {
|
||||
let scale = height.get() as f32 / self.scale();
|
||||
|
||||
Twips::new((self.0.ascent as f32 * scale) as i32)
|
||||
}
|
||||
|
||||
/// Returns whether this font contains kerning information.
|
||||
pub fn has_kerning_info(self) -> bool {
|
||||
!self.0.kerning_pairs.is_empty()
|
||||
|
|
|
@ -5,12 +5,33 @@ use crate::drawing::Drawing;
|
|||
use crate::font::{EvalParameters, Font};
|
||||
use crate::html::dimensions::{BoxBounds, Position, Size};
|
||||
use crate::html::text_format::{FormatSpans, TextFormat, TextSpan};
|
||||
use crate::shape_utils::DrawCommand;
|
||||
use crate::tag_utils::SwfMovie;
|
||||
use gc_arena::{Collect, GcCell, MutationContext};
|
||||
use std::cmp::{max, min};
|
||||
use std::sync::Arc;
|
||||
use swf::Twips;
|
||||
|
||||
/// Draw an underline on a particular drawing.
|
||||
///
|
||||
/// This will not draw underlines shorter than a pixel in width.
|
||||
fn draw_underline(drawing: &mut Drawing, starting_pos: Position<Twips>, width: Twips) {
|
||||
if width < Twips::from_pixels(1.0) {
|
||||
return;
|
||||
}
|
||||
|
||||
let ending_pos = starting_pos + Position::from((width, Twips::zero()));
|
||||
|
||||
drawing.draw_command(DrawCommand::MoveTo {
|
||||
x: starting_pos.x(),
|
||||
y: starting_pos.y(),
|
||||
});
|
||||
drawing.draw_command(DrawCommand::LineTo {
|
||||
x: ending_pos.x(),
|
||||
y: ending_pos.y(),
|
||||
});
|
||||
}
|
||||
|
||||
/// Contains information relating to the current layout operation.
|
||||
pub struct LayoutContext<'a, 'gc> {
|
||||
/// The movie this layout context is pulling fonts from.
|
||||
|
@ -116,6 +137,74 @@ impl<'a, 'gc> LayoutContext<'a, 'gc> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Construct an underline drawing for the current line of text and add it
|
||||
/// to the line.
|
||||
fn append_underlines(&mut self, context: &mut UpdateContext<'_, 'gc, '_>) {
|
||||
let mut starting_pos: Option<Position<Twips>> = None;
|
||||
let mut current_width: Option<Twips> = None;
|
||||
let mut line_drawing = Drawing::new();
|
||||
let mut line = self.current_line;
|
||||
|
||||
line_drawing.set_line_style(Some(swf::LineStyle::new_v1(
|
||||
Twips::new(1),
|
||||
swf::Color::from_rgb(0, 255),
|
||||
)));
|
||||
|
||||
while let Some(linebox) = line {
|
||||
let read = linebox.read();
|
||||
|
||||
if read.is_text_box() {
|
||||
if let Some((_t, tf, font, params, _color)) = read.as_renderable_text(self.text) {
|
||||
let underline_baseline =
|
||||
font.get_baseline_for_height(params.height()) + Twips::from_pixels(2.0);
|
||||
let mut line_extended = false;
|
||||
|
||||
if let Some(starting_pos) = starting_pos {
|
||||
if tf.underline.unwrap_or(false)
|
||||
&& underline_baseline + read.bounds().origin().y() == starting_pos.y()
|
||||
{
|
||||
//Underline is at the same baseline, extend it
|
||||
current_width = Some(read.bounds().extent_x() - starting_pos.x());
|
||||
|
||||
line_extended = true;
|
||||
}
|
||||
}
|
||||
|
||||
if !line_extended {
|
||||
//For whatever reason, we cannot extend the current underline.
|
||||
//This can happen if we don't have an underline to extend, the
|
||||
//underlines don't match, or this span doesn't call for one.
|
||||
if let (Some(pos), Some(width)) = (starting_pos, current_width) {
|
||||
draw_underline(&mut line_drawing, pos, width);
|
||||
|
||||
starting_pos = None;
|
||||
current_width = None;
|
||||
}
|
||||
|
||||
if tf.underline.unwrap_or(false) {
|
||||
starting_pos = Some(
|
||||
read.bounds().origin()
|
||||
+ Position::from((Twips::zero(), underline_baseline)),
|
||||
);
|
||||
current_width = Some(read.bounds().width());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
line = read.next_sibling();
|
||||
}
|
||||
|
||||
if let (Some(starting_pos), Some(current_width)) = (starting_pos, current_width) {
|
||||
draw_underline(&mut line_drawing, starting_pos, current_width);
|
||||
}
|
||||
|
||||
self.append_box(
|
||||
context.gc_context,
|
||||
LayoutBox::from_drawing(context.gc_context, line_drawing),
|
||||
);
|
||||
}
|
||||
|
||||
/// Apply all indents and alignment to the current line, if necessary.
|
||||
///
|
||||
/// The `only_line` parameter should be flagged if this is the only line in
|
||||
|
@ -223,6 +312,8 @@ impl<'a, 'gc> LayoutContext<'a, 'gc> {
|
|||
box_count += 1;
|
||||
}
|
||||
|
||||
self.append_underlines(context);
|
||||
|
||||
line_bounds +=
|
||||
Position::from((left_adjustment + align_adjustment, Twips::from_pixels(0.0)));
|
||||
line_bounds += Size::from((Twips::from_pixels(0.0), font_leading_adjustment));
|
||||
|
|
Loading…
Reference in New Issue