Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement new Webrender PushTextShadow API #17675

Closed
wants to merge 2 commits into from
Closed
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

@@ -605,6 +605,8 @@ pub enum DisplayItem {
RadialGradient(Box<RadialGradientDisplayItem>),
Line(Box<LineDisplayItem>),
BoxShadow(Box<BoxShadowDisplayItem>),
PushTextShadow(Box<PushTextShadowDisplayItem>),
PopTextShadow(Box<PopTextShadowDisplayItem>),
Iframe(Box<IframeDisplayItem>),
PushStackingContext(Box<PushStackingContextItem>),
PopStackingContext(Box<PopStackingContextItem>),
@@ -895,9 +897,6 @@ pub struct TextDisplayItem {

/// The orientation of the text: upright or sideways left/right.
pub orientation: TextOrientation,

/// The blur radius for this text. If zero, this text is not blurred.
pub blur_radius: Au,
}

#[derive(Clone, Eq, PartialEq, HeapSizeOf, Deserialize, Serialize)]
@@ -1180,6 +1179,29 @@ pub struct BoxShadowDisplayItem {
pub clip_mode: BoxShadowClipMode,
}

/// Defines a text shadow that affects all items until the paired PopTextShadow.
#[derive(Clone, HeapSizeOf, Deserialize, Serialize)]
pub struct PushTextShadowDisplayItem {
/// Fields common to all display items.
pub base: BaseDisplayItem,

/// The offset of this shadow from the text.
pub offset: Vector2D<Au>,

/// The color of this shadow.
pub color: ColorF,

/// The blur radius for this shadow.
pub blur_radius: Au,
}

/// Defines a text shadow that affects all items until the next PopTextShadow.
#[derive(Clone, HeapSizeOf, Deserialize, Serialize)]
pub struct PopTextShadowDisplayItem {
/// Fields common to all display items.
pub base: BaseDisplayItem,
}

/// Defines a stacking context.
#[derive(Clone, HeapSizeOf, Deserialize, Serialize)]
pub struct PushStackingContextItem {
@@ -1233,6 +1255,8 @@ impl DisplayItem {
DisplayItem::RadialGradient(ref gradient) => &gradient.base,
DisplayItem::Line(ref line) => &line.base,
DisplayItem::BoxShadow(ref box_shadow) => &box_shadow.base,
DisplayItem::PushTextShadow(ref push_text_shadow) => &push_text_shadow.base,
DisplayItem::PopTextShadow(ref pop_text_shadow) => &pop_text_shadow.base,
DisplayItem::Iframe(ref iframe) => &iframe.base,
DisplayItem::PushStackingContext(ref stacking_context) => &stacking_context.base,
DisplayItem::PopStackingContext(ref item) => &item.base,
@@ -1353,6 +1377,8 @@ impl fmt::Debug for DisplayItem {
DisplayItem::RadialGradient(_) => "RadialGradient".to_owned(),
DisplayItem::Line(_) => "Line".to_owned(),
DisplayItem::BoxShadow(_) => "BoxShadow".to_owned(),
DisplayItem::PushTextShadow(_) => "PushTextShadow".to_owned(),
DisplayItem::PopTextShadow(_) => "PopTextShadow".to_owned(),
DisplayItem::Iframe(_) => "Iframe".to_owned(),
DisplayItem::PushStackingContext(_) |
DisplayItem::PopStackingContext(_) |
@@ -25,10 +25,10 @@ use gfx::display_list::{BLUR_INFLATION_FACTOR, BaseDisplayItem, BorderDetails, B
use gfx::display_list::{BorderRadii, BoxShadowClipMode, BoxShadowDisplayItem, ClippingRegion};
use gfx::display_list::{DisplayItem, DisplayItemMetadata, DisplayList, DisplayListSection};
use gfx::display_list::{GradientDisplayItem, IframeDisplayItem, ImageBorder, ImageDisplayItem};
use gfx::display_list::{LineDisplayItem, NormalBorder, OpaqueNode, RadialGradientDisplayItem};
use gfx::display_list::{ScrollRoot, ScrollRootType, SolidColorDisplayItem, StackingContext};
use gfx::display_list::{StackingContextType, TextDisplayItem, TextOrientation, WebGLDisplayItem};
use gfx::display_list::WebRenderImageInfo;
use gfx::display_list::{LineDisplayItem, NormalBorder, OpaqueNode, PushTextShadowDisplayItem};
use gfx::display_list::{PopTextShadowDisplayItem, RadialGradientDisplayItem, ScrollRoot};
use gfx::display_list::{ScrollRootType, SolidColorDisplayItem, StackingContext, StackingContextType};
use gfx::display_list::{TextDisplayItem, TextOrientation, WebGLDisplayItem, WebRenderImageInfo};
use gfx_traits::{combine_id_with_fragment_type, FragmentType, StackingContextId};
use inline::{FIRST_FRAGMENT_OF_ELEMENT, InlineFlow, LAST_FRAGMENT_OF_ELEMENT};
use ipc_channel::ipc;
@@ -526,16 +526,15 @@ pub trait FragmentDisplayListBuilding {
state: &mut DisplayListBuildState,
text_fragment: &ScannedTextFragmentInfo,
stacking_relative_content_box: &Rect<Au>,
text_shadow: Option<&SimpleShadow>,
text_shadows: &[SimpleShadow],
clip: &Rect<Au>);

/// Creates the display item for a text decoration: underline, overline, or line-through.
fn build_display_list_for_text_decoration(&self,
state: &mut DisplayListBuildState,
color: &RGBA,
stacking_relative_box: &LogicalRect<Au>,
clip: &Rect<Au>,
blur: Au);
clip: &Rect<Au>);

/// A helper method that `build_display_list` calls to create per-fragment-type display items.
fn build_fragment_type_specific_display_items(&mut self,
@@ -1867,24 +1866,11 @@ impl FragmentDisplayListBuilding for Fragment {
..
}) |
SpecificFragmentInfo::ScannedText(box ref text_fragment) => {
// Create items for shadows.

This comment has been minimized.

Copy link
@mrobinson

mrobinson Jul 13, 2017

Member

Nice. The new version seems a lot cleaner!

//
// NB: According to CSS-BACKGROUNDS, text shadows render in *reverse* order (front
// to back).

for text_shadow in self.style.get_inheritedtext().text_shadow.0.iter().rev() {
self.build_display_list_for_text_fragment(state,
&*text_fragment,
&stacking_relative_content_box,
Some(text_shadow),
clip);
}

// Create the main text display item.
self.build_display_list_for_text_fragment(state,
&*text_fragment,
&stacking_relative_content_box,
None,
&self.style.get_inheritedtext().text_shadow.0,
clip);

if opts::get().show_debug_fragment_borders {
@@ -2066,22 +2052,20 @@ impl FragmentDisplayListBuilding for Fragment {
state: &mut DisplayListBuildState,
text_fragment: &ScannedTextFragmentInfo,
stacking_relative_content_box: &Rect<Au>,
text_shadow: Option<&SimpleShadow>,
text_shadows: &[SimpleShadow],
clip: &Rect<Au>) {

// NB: The order for painting text components (CSS Text Decoration Module Level 3) is:
// shadows, underline, overline, text, text-emphasis, and then line-through.

// TODO(emilio): Allow changing more properties by ::selection
let text_color = if let Some(shadow) = text_shadow {
// If we're painting a shadow, paint the text the same color as the shadow.
self.style().resolve_color(shadow.color)
} else if text_fragment.selected() {
// Otherwise, paint the text with the color as described in its styling.
// Paint the text with the color as described in its styling.
let text_color = if text_fragment.selected() {
self.selected_style().get_color().color
} else {
self.style().get_color().color
};
let offset = text_shadow.map_or(Vector2D::zero(), |s| {
Vector2D::new(s.horizontal, s.vertical)
});
let shadow_blur_radius = text_shadow.map(|s| s.blur).unwrap_or(Au(0));


// Determine the orientation and cursor to use.
let (orientation, cursor) = if self.style.writing_mode.is_vertical() {
@@ -2097,28 +2081,32 @@ impl FragmentDisplayListBuilding for Fragment {
// FIXME(pcwalton): Get the real container size.
let container_size = Size2D::zero();
let metrics = &text_fragment.run.font_metrics;
let stacking_relative_content_box = stacking_relative_content_box.translate(&offset);
let baseline_origin = stacking_relative_content_box.origin +
LogicalPoint::new(self.style.writing_mode,
Au(0),
metrics.ascent).to_physical(self.style.writing_mode,
container_size).to_vector();

// Create the text display item.
// Base item for all text/shadows
let base = state.create_base_display_item(&stacking_relative_content_box,
LocalClip::from(clip.to_rectf()),
self.node,
self.style().get_cursor(cursor),
DisplayListSection::Content);
state.add_display_item(DisplayItem::Text(box TextDisplayItem {
base: base,
text_run: text_fragment.run.clone(),
range: text_fragment.range,
text_color: text_color.to_gfx_color(),
orientation: orientation,
baseline_origin: baseline_origin,
blur_radius: shadow_blur_radius,
}));

// NB: According to CSS-BACKGROUNDS, text shadows render in *reverse* order (front
// to back).

// Shadows
for shadow in text_shadows.iter().rev() {
state.add_display_item(DisplayItem::PushTextShadow(box PushTextShadowDisplayItem {
base: base.clone(),
blur_radius: shadow.blur,
offset: Vector2D::new(shadow.horizontal, shadow.vertical),
color: self.style().resolve_color(shadow.color).to_gfx_color(),
}));
}


// Create display items for text decorations.
let mut text_decorations = self.style()
@@ -2131,8 +2119,10 @@ impl FragmentDisplayListBuilding for Fragment {

let stacking_relative_content_box =
LogicalRect::from_physical(self.style.writing_mode,
stacking_relative_content_box,
*stacking_relative_content_box,
container_size);

// Underline
if let Some(ref underline_color) = text_decorations.underline {
let mut stacking_relative_box = stacking_relative_content_box;
stacking_relative_box.start.b = stacking_relative_content_box.start.b +
@@ -2141,20 +2131,35 @@ impl FragmentDisplayListBuilding for Fragment {
self.build_display_list_for_text_decoration(state,
underline_color,
&stacking_relative_box,
clip,
shadow_blur_radius);
clip);
}

// Overline
if let Some(ref overline_color) = text_decorations.overline {
let mut stacking_relative_box = stacking_relative_content_box;
stacking_relative_box.size.block = metrics.underline_size;
self.build_display_list_for_text_decoration(state,
overline_color,
&stacking_relative_box,
clip,
shadow_blur_radius);
clip);
}

// Text
state.add_display_item(DisplayItem::Text(box TextDisplayItem {
base: base.clone(),
text_run: text_fragment.run.clone(),
range: text_fragment.range,
text_color: text_color.to_gfx_color(),
orientation: orientation,
baseline_origin: baseline_origin,
}));


// TODO(#17715): emit text-emphasis marks here.
// (just push another TextDisplayItem?)


// Line-Through
if let Some(ref line_through_color) = text_decorations.line_through {
let mut stacking_relative_box = stacking_relative_content_box;
stacking_relative_box.start.b = stacking_relative_box.start.b + metrics.ascent -
@@ -2163,40 +2168,36 @@ impl FragmentDisplayListBuilding for Fragment {
self.build_display_list_for_text_decoration(state,
line_through_color,
&stacking_relative_box,
clip,
shadow_blur_radius);
clip);
}

// Pair all the PushTextShadows
for _ in text_shadows {
state.add_display_item(DisplayItem::PopTextShadow(box PopTextShadowDisplayItem {
base: base.clone(),
}));
}
}

fn build_display_list_for_text_decoration(&self,
state: &mut DisplayListBuildState,
color: &RGBA,
stacking_relative_box: &LogicalRect<Au>,
clip: &Rect<Au>,
blur_radius: Au) {
// Perhaps surprisingly, text decorations are box shadows. This is because they may need
// to have blur in the case of `text-shadow`, and this doesn't hurt performance because box
// shadows are optimized into essentially solid colors if there is no need for the blur.
//
clip: &Rect<Au>) {
// FIXME(pcwalton, #2795): Get the real container size.
let container_size = Size2D::zero();
let stacking_relative_box = stacking_relative_box.to_physical(self.style.writing_mode,
container_size);
let base = state.create_base_display_item(
&shadow_bounds(&stacking_relative_box, blur_radius, Au(0)),
&stacking_relative_box,
LocalClip::from(clip.to_rectf()),
self.node,
self.style.get_cursor(Cursor::Default),
DisplayListSection::Content);
state.add_display_item(DisplayItem::BoxShadow(box BoxShadowDisplayItem {

state.add_display_item(DisplayItem::SolidColor(box SolidColorDisplayItem {
base: base,
box_bounds: stacking_relative_box,
color: color.to_gfx_color(),
offset: Vector2D::zero(),
blur_radius: blur_radius,
spread_radius: Au(0),
border_radius: Au(0),
clip_mode: BoxShadowClipMode::None,
}));
}

@@ -289,7 +289,6 @@ impl WebRenderDisplayItemConverter for DisplayItem {
item.text_run.font_key,
item.text_color,
item.text_run.actual_pt_size,
item.blur_radius.to_f32_px(),
None);
}
}
@@ -449,10 +448,23 @@ impl WebRenderDisplayItemConverter for DisplayItem {
item.border_radius.to_f32_px(),
item.clip_mode.to_clip_mode());
}
DisplayItem::PushTextShadow(ref item) => {
let rect = item.base.bounds.to_rectf();
builder.push_text_shadow(rect,
Some(item.base.local_clip),
webrender_api::TextShadow {
blur_radius: item.blur_radius.to_f32_px(),
offset: item.offset.to_vectorf(),
color: item.color,
});
}
DisplayItem::PopTextShadow(_) => {
builder.pop_text_shadow();
}
DisplayItem::Iframe(ref item) => {
let rect = item.base.bounds.to_rectf();
let pipeline_id = item.iframe.to_webrender();
builder.push_iframe(rect, pipeline_id);
builder.push_iframe(rect, Some(item.base.local_clip), pipeline_id);
}
DisplayItem::PushStackingContext(ref item) => {
let stacking_context = &item.stacking_context;
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.