Improve the fidelity of the NanoVG demo some more

This commit is contained in:
Patrick Walton 2020-04-14 18:49:47 -07:00
parent 0fec0061e6
commit 83c05e9f77
2 changed files with 85 additions and 71 deletions

View File

@ -326,8 +326,8 @@ impl LayoutExt for Layout {
let glyph_id = last_glyph.glyph_id; let glyph_id = last_glyph.glyph_id;
let font_metrics = last_glyph.font.font.metrics(); let font_metrics = last_glyph.font.font.metrics();
let glyph_rect = last_glyph.font.font.typographic_bounds(glyph_id).unwrap();
let scale_factor = self.size / font_metrics.units_per_em as f32; let scale_factor = self.size / font_metrics.units_per_em as f32;
let glyph_rect = last_glyph.font.font.typographic_bounds(glyph_id).unwrap();
last_glyph.offset.x() + glyph_rect.max_x() * scale_factor last_glyph.offset.x() + glyph_rect.max_x() * scale_factor
} }
@ -338,14 +338,16 @@ impl LayoutExt for Layout {
}; };
let glyph_id = first_glyph.glyph_id; let glyph_id = first_glyph.glyph_id;
let font_metrics = first_glyph.font.font.metrics();
let scale_factor = self.size / font_metrics.units_per_em as f32;
let glyph_rect = first_glyph.font let glyph_rect = first_glyph.font
.font .font
.raster_bounds(glyph_id, .raster_bounds(glyph_id,
self.size, font_metrics.units_per_em as f32,
Transform2F::default(), Transform2F::default(),
HintingOptions::None, HintingOptions::None,
RasterizationOptions::GrayscaleAa).unwrap(); RasterizationOptions::GrayscaleAa).unwrap();
first_glyph.offset.x() + glyph_rect.min_x() as f32 first_glyph.offset.x() + glyph_rect.min_x() as f32 * scale_factor
} }
fn actual_bounding_box_right(&self) -> f32 { fn actual_bounding_box_right(&self) -> f32 {
@ -355,14 +357,16 @@ impl LayoutExt for Layout {
}; };
let glyph_id = last_glyph.glyph_id; let glyph_id = last_glyph.glyph_id;
let font_metrics = last_glyph.font.font.metrics();
let scale_factor = self.size / font_metrics.units_per_em as f32;
let glyph_rect = last_glyph.font let glyph_rect = last_glyph.font
.font .font
.raster_bounds(glyph_id, .raster_bounds(glyph_id,
self.size, font_metrics.units_per_em as f32,
Transform2F::default(), Transform2F::default(),
HintingOptions::None, HintingOptions::None,
RasterizationOptions::GrayscaleAa).unwrap(); RasterizationOptions::GrayscaleAa).unwrap();
last_glyph.offset.x() + glyph_rect.max_x() as f32 last_glyph.offset.x() + glyph_rect.max_x() as f32 * scale_factor
} }
fn hanging_baseline(&self) -> f32 { fn hanging_baseline(&self) -> f32 {

View File

@ -276,19 +276,24 @@ fn draw_paragraph(context: &mut CanvasRenderingContext2D,
let line_bounds = main_text.lines[text_location.line_index as usize].bounds(); let line_bounds = main_text.lines[text_location.line_index as usize].bounds();
let gutter_origin = line_bounds.origin() + vec2f(-10.0, MAIN_LINE_HEIGHT * 0.5); let gutter_origin = line_bounds.origin() + vec2f(-10.0, MAIN_LINE_HEIGHT * 0.5);
context.set_font_size(12.0); context.set_font_size(12.0);
let gutter_text = format!("{}", text_location.line_index + 1);
let gutter_text_width = context.measure_text(&gutter_text).width;
context.set_text_align(TextAlign::Right); context.set_text_align(TextAlign::Right);
context.set_text_baseline(TextBaseline::Middle); context.set_text_baseline(TextBaseline::Middle);
context.set_fill_style(rgbau(255, 192, 0, 255)); context.set_fill_style(rgbau(255, 192, 0, 255));
let gutter_text_bounds = RectF::new(gutter_origin - vec2f(gutter_text_width, 6.0),
vec2f(gutter_text_width, 12.0)); let gutter_text = format!("{}", text_location.line_index + 1);
let gutter_text_metrics = context.measure_text(&gutter_text);
let gutter_text_bounds =
RectF::from_points(vec2f(gutter_text_metrics.actual_bounding_box_left,
-gutter_text_metrics.font_bounding_box_ascent),
vec2f(gutter_text_metrics.actual_bounding_box_right,
-gutter_text_metrics.font_bounding_box_descent));
let gutter_path_bounds = gutter_text_bounds.dilate(vec2f(4.0, 2.0)); let gutter_path_bounds = gutter_text_bounds.dilate(vec2f(4.0, 2.0));
let gutter_path_radius = gutter_path_bounds.width() * 0.5 - 1.0; let gutter_path_radius = gutter_path_bounds.width() * 0.5 - 1.0;
let path = create_rounded_rect_path(gutter_path_bounds, gutter_path_radius); let path = create_rounded_rect_path(gutter_path_bounds + gutter_origin,
gutter_path_radius);
context.fill_path(path, FillRule::Winding); context.fill_path(path, FillRule::Winding);
context.set_fill_style(rgbau(32, 32, 32, 255)); context.set_fill_style(rgbau(32, 32, 32, 255));
@ -866,13 +871,17 @@ fn draw_search_box(context: &mut CanvasRenderingContext2D,
let corner_radius = rect.height() * 0.5 - 1.0; let corner_radius = rect.height() * 0.5 - 1.0;
let path = create_rounded_rect_path(rect, corner_radius); let path = create_rounded_rect_path(rect, corner_radius);
context.save();
context.clip_path(path.clone(), FillRule::Winding);
context.set_shadow_offset(vec2f(0.0, 1.5));
context.set_shadow_blur(5.0 * hidpi_factor);
context.set_shadow_color(rgbau(0, 0, 0, 92));
context.set_fill_style(rgbau(0, 0, 0, 16)); context.set_fill_style(rgbau(0, 0, 0, 16));
context.fill_path(path, FillRule::Winding); context.fill_path(path.clone(), FillRule::Winding);
context.save();
context.clip_path(path, FillRule::Winding);
let shadow_path = create_rounded_rect_path(rect + vec2f(0.0, 1.5), corner_radius);
context.set_shadow_blur(5.0 * hidpi_factor);
context.set_shadow_offset(vec2f(0.0, 0.0));
context.set_shadow_color(rgbau(0, 0, 0, 92));
context.set_stroke_style(rgbau(0, 0, 0, 92));
context.set_line_width(1.0);
context.stroke_path(shadow_path);
context.restore(); context.restore();
context.set_font_size(rect.height() * 0.5); context.set_font_size(rect.height() * 0.5);
@ -884,7 +893,7 @@ fn draw_search_box(context: &mut CanvasRenderingContext2D,
context.set_font(FONT_NAME_REGULAR); context.set_font(FONT_NAME_REGULAR);
context.set_font_size(17.0); context.set_font_size(17.0);
context.set_fill_style(rgbau(255, 255, 255, 64)); context.set_fill_style(rgbau(255, 255, 255, 32));
context.set_text_align(TextAlign::Left); context.set_text_align(TextAlign::Left);
context.set_text_baseline(TextBaseline::Middle); context.set_text_baseline(TextBaseline::Middle);
context.fill_text(text, rect.origin() + vec2f(1.05, 0.5) * rect.height()); context.fill_text(text, rect.origin() + vec2f(1.05, 0.5) * rect.height());
@ -947,11 +956,15 @@ fn draw_edit_box(context: &mut CanvasRenderingContext2D, rect: RectF, hidpi_fact
context.save(); context.save();
let path = create_rounded_rect_path(rect.contract(1.0), CORNER_RADIUS - 1.0); let path = create_rounded_rect_path(rect.contract(1.0), CORNER_RADIUS - 1.0);
context.set_shadow_color(rgbau(255, 255, 255, 32)); context.set_fill_style(rgbau(255, 255, 255, 32));
context.set_shadow_offset(vec2f(0.0, 1.5)); context.fill_path(path.clone(), FillRule::Winding);
context.set_shadow_blur(4.0 * hidpi_factor); context.clip_path(path.clone(), FillRule::Winding);
context.set_fill_style(rgbau(32, 32, 32, 32)); context.set_line_width(1.0);
context.fill_path(path, FillRule::Winding); context.set_shadow_blur(2.0 * hidpi_factor);
context.set_shadow_color(rgbau(32, 32, 32, 92));
context.set_shadow_offset(vec2f(0.0, 1.0));
context.set_stroke_style(rgbau(32, 32, 32, 92));
context.stroke_path(path);
context.restore(); context.restore();
context.set_stroke_style(rgbau(0, 0, 0, 48)); context.set_stroke_style(rgbau(0, 0, 0, 48));
@ -1009,23 +1022,27 @@ fn draw_check_box(context: &mut CanvasRenderingContext2D,
context.set_text_baseline(TextBaseline::Middle); context.set_text_baseline(TextBaseline::Middle);
context.fill_text(text, rect.origin() + vec2f(28.0, rect.height() * 0.5)); context.fill_text(text, rect.origin() + vec2f(28.0, rect.height() * 0.5));
context.save();
let check_box_rect = RectF::new(vec2f(rect.origin_x(), rect.center().y().floor() - 9.0), let check_box_rect = RectF::new(vec2f(rect.origin_x(), rect.center().y().floor() - 9.0),
vec2f(20.0, 20.0)).contract(1.0); vec2f(20.0, 20.0)).contract(1.0);
let check_box_path = create_rounded_rect_path(check_box_rect, CORNER_RADIUS); let check_box_path = create_rounded_rect_path(check_box_rect, CORNER_RADIUS);
context.save(); context.set_fill_style(rgbau(0, 0, 0, 32));
context.clip_path(check_box_path.clone(), FillRule::Winding); context.fill_path(check_box_path.clone(), FillRule::Winding);
context.set_shadow_offset(vec2f(0.0, 1.0)); context.clip_path(check_box_path, FillRule::Winding);
context.set_shadow_blur(3.0 * hidpi_factor); context.set_line_width(1.0);
context.set_shadow_color(rgbau(0, 0, 0, 32)); context.set_stroke_style(rgbau(0, 0, 0, 92));
context.set_fill_style(rgbau(0, 0, 0, 92)); context.set_shadow_color(rgbau(0, 0, 0, 92));
context.fill_path(check_box_path, FillRule::Winding); context.set_shadow_blur(1.5 * hidpi_factor);
context.set_shadow_offset(vec2f(0.0, 0.0));
let shadow_path = create_rounded_rect_path(check_box_rect + vec2f(0.0, 1.0), CORNER_RADIUS);
context.stroke_path(shadow_path);
context.restore(); context.restore();
context.set_font(FONT_NAME_EMOJI); context.set_font(FONT_NAME_EMOJI);
context.set_font_size(17.0); context.set_font_size(17.0);
context.set_fill_style(rgbau(255, 255, 255, 128)); context.set_fill_style(rgbau(255, 255, 255, 128));
context.set_text_align(TextAlign::Center); context.set_text_align(TextAlign::Center);
context.fill_text("✔︎", rect.origin() + vec2f(11.0, rect.height() * 0.5)); context.fill_text("✔︎", check_box_rect.center());
} }
fn draw_button(context: &mut CanvasRenderingContext2D, fn draw_button(context: &mut CanvasRenderingContext2D,
@ -1102,20 +1119,8 @@ fn draw_slider(context: &mut CanvasRenderingContext2D,
context.fill_path(track_path, FillRule::Winding); context.fill_path(track_path, FillRule::Winding);
context.restore(); context.restore();
// Draw knob shadow.
let knob_position = vec2f(rect.origin_x() + (value * rect.width()).floor(), center_y);
let mut background_gradient =
Gradient::radial(LineSegment2F::new(knob_position, knob_position) + vec2f(0.0, 1.0),
F32x2::splat(knob_radius) * F32x2::new(-3.0, 3.0));
background_gradient.add_color_stop(rgbau(0, 0, 0, 64), 0.0);
background_gradient.add_color_stop(rgbau(0, 0, 0, 0), 1.0);
context.set_fill_style(background_gradient);
let mut path = Path2D::new();
path.rect(RectF::new(knob_position, Vector2F::zero()).dilate(knob_radius + 5.0));
path.ellipse(knob_position, knob_radius, 0.0, 0.0, PI_2);
context.fill_path(path, FillRule::EvenOdd);
// Fill knob. // Fill knob.
let knob_position = vec2f(rect.origin_x() + (value * rect.width()).floor(), center_y);
let mut background_gradient = let mut background_gradient =
Gradient::linear_from_points(knob_position - vec2f(0.0, knob_radius), Gradient::linear_from_points(knob_position - vec2f(0.0, knob_radius),
knob_position + vec2f(0.0, knob_radius)); knob_position + vec2f(0.0, knob_radius));
@ -1124,7 +1129,11 @@ fn draw_slider(context: &mut CanvasRenderingContext2D,
let mut path = Path2D::new(); let mut path = Path2D::new();
path.ellipse(knob_position, knob_radius - 1.0, 0.0, 0.0, PI_2); path.ellipse(knob_position, knob_radius - 1.0, 0.0, 0.0, PI_2);
context.set_fill_style(rgbu(40, 43, 48)); context.set_fill_style(rgbu(40, 43, 48));
context.set_shadow_blur(6.0 * hidpi_factor);
context.set_shadow_color(rgbau(0, 0, 0, 128));
context.set_shadow_offset(vec2f(0.0, 1.0));
context.fill_path(path.clone(), FillRule::Winding); context.fill_path(path.clone(), FillRule::Winding);
context.set_shadow_color(rgbau(0, 0, 0, 0));
context.set_fill_style(background_gradient); context.set_fill_style(background_gradient);
context.fill_path(path, FillRule::Winding); context.fill_path(path, FillRule::Winding);
@ -1156,22 +1165,17 @@ fn draw_thumbnails(context: &mut CanvasRenderingContext2D,
context.save(); context.save();
// Draw drop shadow.
let shadow_path = create_rounded_rect_path(rect, CORNER_RADIUS * 2.0);
context.set_fill_style(rgbau(0, 0, 0, 0));
context.set_shadow_blur(20.0 * hidpi_factor);
context.set_shadow_color(rgbau(0, 0, 0, 128));
context.set_shadow_offset(vec2f(0.0, 4.0));
context.fill_path(shadow_path, FillRule::Winding);
context.set_shadow_color(rgbau(0, 0, 0, 0));
// Draw window. // Draw window.
let mut path = create_rounded_rect_path(rect, CORNER_RADIUS); let mut path = create_rounded_rect_path(rect, CORNER_RADIUS);
path.move_to(rect.origin() + vec2f(-10.0, ARROW_Y_POSITION)); path.move_to(rect.origin() + vec2f(-10.0, ARROW_Y_POSITION));
path.line_to(rect.origin() + vec2f(1.0, ARROW_Y_POSITION - 11.0)); path.line_to(rect.origin() + vec2f(1.0, ARROW_Y_POSITION - 11.0));
path.line_to(rect.origin() + vec2f(1.0, ARROW_Y_POSITION + 11.0)); path.line_to(rect.origin() + vec2f(1.0, ARROW_Y_POSITION + 11.0));
context.set_fill_style(rgbu(200, 200, 200)); context.set_fill_style(rgbu(200, 200, 200));
context.set_shadow_blur(20.0 * hidpi_factor);
context.set_shadow_offset(vec2f(0.0, 4.0));
context.set_shadow_color(rgbau(0, 0, 0, 64));
context.fill_path(path, FillRule::Winding); context.fill_path(path, FillRule::Winding);
context.set_shadow_color(rgbau(0, 0, 0, 0));
// Draw images. // Draw images.
@ -1240,30 +1244,36 @@ fn draw_thumbnails(context: &mut CanvasRenderingContext2D,
// Draw scroll bar. // Draw scroll bar.
context.save();
let scroll_bar_rect = RectF::new(rect.upper_right() + vec2f(-12.0, 4.0), let scroll_bar_rect = RectF::new(rect.upper_right() + vec2f(-12.0, 4.0),
vec2f(8.0, rect.height() - 8.0)); vec2f(8.0, rect.height() - 8.0));
context.save(); let path = create_rounded_rect_path(scroll_bar_rect, CORNER_RADIUS);
context.set_shadow_blur(4.0 * hidpi_factor); context.set_fill_style(rgbau(0, 0, 0, 32));
context.fill_path(path.clone(), FillRule::Winding);
context.clip_path(path, FillRule::Winding);
context.set_stroke_style(rgbau(0, 0, 0, 92));
context.set_shadow_offset(vec2f(0.0, 0.0)); context.set_shadow_offset(vec2f(0.0, 0.0));
context.set_shadow_color(rgbau(0, 0, 0, 92)); context.set_shadow_color(rgbau(0, 0, 0, 92));
context.set_fill_style(rgbau(0, 0, 0, 32)); context.set_shadow_blur(4.0 * hidpi_factor);
let clip_path = create_rounded_rect_path(scroll_bar_rect, CORNER_RADIUS); let shadow_path = create_rounded_rect_path(scroll_bar_rect + vec2f(0.0, 1.0), CORNER_RADIUS);
context.clip_path(clip_path, FillRule::Winding); context.stroke_path(shadow_path);
let path = create_rounded_rect_path(scroll_bar_rect + vec2f(0.0, 1.0), CORNER_RADIUS); context.set_shadow_color(rgbau(0, 0, 0, 0));
context.fill_path(path, FillRule::Winding);
context.restore(); context.restore();
let knob_rect = RectF::new( let knob_rect = RectF::new(
rect.upper_right() + vec2f(-11.0, 5.0 + (rect.height() - 8.0 - scroll_height) * scroll_y), scroll_bar_rect.origin() + vec2f(0.0, (rect.height() - 8.0 - scroll_height) * scroll_y),
vec2f(6.0, scroll_height - 2.0)); vec2f(8.0, scroll_height));
context.set_shadow_blur(4.0 * hidpi_factor); context.set_fill_style(rgbu(220, 220, 220));
context.set_shadow_offset(vec2f(0.0, 1.0)); let path = create_rounded_rect_path(knob_rect.contract(1.0), 3.0);
context.set_shadow_color(rgbu(220, 220, 220)); context.fill_path(path.clone(), FillRule::Winding);
context.set_fill_style(rgbau(0, 0, 0, 32)); context.clip_path(path, FillRule::Winding);
let clip_path = create_rounded_rect_path(knob_rect, 2.0); context.set_stroke_style(rgbu(128, 128, 128));
context.clip_path(clip_path, FillRule::Winding); context.set_line_width(1.0);
let path = create_rounded_rect_path(knob_rect.dilate(2.0) + vec2f(0.0, 1.0), 3.0); let shadow_path = create_rounded_rect_path(knob_rect, 3.0);
context.fill_path(path, FillRule::Winding); context.set_shadow_blur(2.0 * hidpi_factor);
context.set_shadow_color(rgbu(128, 128, 128));
context.set_shadow_offset(vec2f(0.0, 0.0));
context.stroke_path(shadow_path);
context.restore(); context.restore();
} }