gfx: Paint the insertion point as a one-pixel wide line.

This commit is contained in:
Patrick Walton 2015-09-15 16:32:39 -07:00
parent 357419dc8d
commit efdf435ba3

View file

@ -34,6 +34,7 @@ use gfx::display_list::{GradientStop, ImageDisplayItem, LineDisplayItem};
use gfx::display_list::{OpaqueNode, SolidColorDisplayItem};
use gfx::display_list::{StackingContext, TextDisplayItem, TextOrientation};
use gfx::paint_task::THREAD_TINT_COLORS;
use gfx::text::glyph::CharIndex;
use gfx_traits::color;
use ipc_channel::ipc::{self, IpcSharedMemory};
use msg::compositor_msg::{ScrollPolicy, LayerId};
@ -60,15 +61,19 @@ use style::values::computed::{LengthOrNone, LengthOrPercentage, LengthOrPercenta
use style::values::specified::{AngleOrCorner, HorizontalDirection, VerticalDirection};
use url::Url;
use util::cursor::Cursor;
use util::geometry::{Au, ZERO_POINT};
use util::geometry::{AU_PER_PX, Au, ZERO_POINT};
use util::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize, WritingMode};
use util::opts;
use util::range::Range;
/// The fake fragment ID we use to indicate the inner display list for `overflow: scroll`.
///
/// FIXME(pcwalton): This is pretty ugly. Consider modifying `LayerId` somehow.
const FAKE_FRAGMENT_ID_FOR_OVERFLOW_SCROLL: u32 = 1000000;
/// The logical width of an insertion point: at the moment, a one-pixel-wide line.
const INSERTION_POINT_LOGICAL_WIDTH: Au = Au(1 * AU_PER_PX);
/// Whether a stacking context needs a layer or not.
pub enum StackingContextLayerNecessity {
Always(LayerId, ScrollPolicy),
@ -229,6 +234,14 @@ pub trait FragmentDisplayListBuilding {
stacking_relative_border_box: &Rect<Au>)
-> ClippingRegion;
/// Builds the display items necessary to paint the selection and/or caret for this fragment,
/// if any.
fn build_display_items_for_selection_if_necessary(&self,
display_list: &mut DisplayList,
stacking_relative_border_box: &Rect<Au>,
level: StackingLevel,
clip: &ClippingRegion);
/// Creates the text display item for one text fragment. This can be called multiple times for
/// one fragment if there are text shadows.
///
@ -882,6 +895,50 @@ impl FragmentDisplayListBuilding for Fragment {
(*parent_clip).clone().intersect_rect(&Rect::new(clip_origin, clip_size))
}
fn build_display_items_for_selection_if_necessary(&self,
display_list: &mut DisplayList,
stacking_relative_border_box: &Rect<Au>,
level: StackingLevel,
clip: &ClippingRegion) {
let scanned_text_fragment_info = match self.specific {
SpecificFragmentInfo::ScannedText(ref scanned_text_fragment_info) => {
scanned_text_fragment_info
}
_ => return,
};
let insertion_point_index = match scanned_text_fragment_info.insertion_point {
Some(insertion_point_index) => insertion_point_index,
None => return,
};
let range = Range::new(CharIndex(0), insertion_point_index);
let advance = scanned_text_fragment_info.run.advance_for_range(&range);
let insertion_point_bounds;
let cursor;
if !self.style.writing_mode.is_vertical() {
insertion_point_bounds =
Rect::new(Point2D::new(stacking_relative_border_box.origin.x + advance,
stacking_relative_border_box.origin.y),
Size2D::new(INSERTION_POINT_LOGICAL_WIDTH,
stacking_relative_border_box.size.height));
cursor = Cursor::TextCursor;
} else {
insertion_point_bounds =
Rect::new(Point2D::new(stacking_relative_border_box.origin.x,
stacking_relative_border_box.origin.y + advance),
Size2D::new(stacking_relative_border_box.size.width,
INSERTION_POINT_LOGICAL_WIDTH));
cursor = Cursor::VerticalTextCursor;
};
display_list.push(DisplayItem::SolidColorClass(box SolidColorDisplayItem {
base: BaseDisplayItem::new(insertion_point_bounds,
DisplayItemMetadata::new(self.node, &*self.style, cursor),
clip.clone()),
color: self.style().get_color().color.to_gfx_color(),
}), level);
}
fn build_display_list(&mut self,
display_list: &mut DisplayList,
layout_context: &LayoutContext,
@ -991,6 +1048,12 @@ impl FragmentDisplayListBuilding for Fragment {
&stacking_relative_border_box,
&clip);
}
// Paint the selection point if necessary.
self.build_display_items_for_selection_if_necessary(display_list,
&stacking_relative_border_box,
level,
&clip);
}
// Create special per-fragment-type display items.