layout: Implement CSS linear gradients per the CSS-IMAGES specification.

This implements the CSS `linear-gradient` property per the CSS-IMAGES
specification:

    http://dev.w3.org/csswg/css-images-3/

Improves GitHub.
This commit is contained in:
Patrick Walton 2014-10-15 21:07:36 -07:00
parent 44fa9f9b18
commit 215c2a9d4c
17 changed files with 865 additions and 42 deletions

View file

@ -33,6 +33,10 @@ use std::slice::Items;
use style::computed_values::border_style;
use sync::Arc;
// It seems cleaner to have layout code not mention Azure directly, so let's just reexport this for
// layout to use.
pub use azure::azure_hl::GradientStop;
pub mod optimizer;
/// An opaque handle to a node. The only safe operation that can be performed on this node is to
@ -295,6 +299,7 @@ pub enum DisplayItem {
TextDisplayItemClass(Box<TextDisplayItem>),
ImageDisplayItemClass(Box<ImageDisplayItem>),
BorderDisplayItemClass(Box<BorderDisplayItem>),
GradientDisplayItemClass(Box<GradientDisplayItem>),
LineDisplayItemClass(Box<LineDisplayItem>),
/// A pseudo-display item that exists only so that queries like `ContentBoxQuery` and
@ -382,6 +387,22 @@ pub struct ImageDisplayItem {
pub stretch_size: Size2D<Au>,
}
/// Paints a gradient.
#[deriving(Clone)]
pub struct GradientDisplayItem {
/// Fields common to all display items.
pub base: BaseDisplayItem,
/// The start point of the gradient (computed during display list construction).
pub start_point: Point2D<Au>,
/// The end point of the gradient (computed during display list construction).
pub end_point: Point2D<Au>,
/// A list of color stops.
pub stops: Vec<GradientStop>,
}
/// Renders a border.
#[deriving(Clone)]
pub struct BorderDisplayItem {
@ -482,6 +503,13 @@ impl DisplayItem {
border.style)
}
GradientDisplayItemClass(ref gradient) => {
render_context.draw_linear_gradient(&gradient.base.bounds,
&gradient.start_point,
&gradient.end_point,
gradient.stops.as_slice());
}
LineDisplayItemClass(ref line) => {
render_context.draw_line(&line.base.bounds,
line.color,
@ -498,6 +526,7 @@ impl DisplayItem {
TextDisplayItemClass(ref text) => &text.base,
ImageDisplayItemClass(ref image_item) => &image_item.base,
BorderDisplayItemClass(ref border) => &border.base,
GradientDisplayItemClass(ref gradient) => &gradient.base,
LineDisplayItemClass(ref line) => &line.base,
PseudoDisplayItemClass(ref base) => &**base,
}
@ -509,6 +538,7 @@ impl DisplayItem {
TextDisplayItemClass(ref mut text) => &mut text.base,
ImageDisplayItemClass(ref mut image_item) => &mut image_item.base,
BorderDisplayItemClass(ref mut border) => &mut border.base,
GradientDisplayItemClass(ref mut gradient) => &mut gradient.base,
LineDisplayItemClass(ref mut line) => &mut line.base,
PseudoDisplayItemClass(ref mut base) => &mut **base,
}
@ -535,6 +565,7 @@ impl fmt::Show for DisplayItem {
TextDisplayItemClass(_) => "Text",
ImageDisplayItemClass(_) => "Image",
BorderDisplayItemClass(_) => "Border",
GradientDisplayItemClass(_) => "Gradient",
LineDisplayItemClass(_) => "Line",
PseudoDisplayItemClass(_) => "Pseudo",
},
@ -544,3 +575,4 @@ impl fmt::Show for DisplayItem {
)
}
}

View file

@ -2,22 +2,23 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use display_list::{SidewaysLeft, SidewaysRight, TextDisplayItem, Upright};
use font_context::FontContext;
use style::computed_values::border_style;
//! Painting of display lists using Moz2D/Azure.
use azure::azure_hl::{B8G8R8A8, A8, Color, ColorPattern, ColorPatternRef, DrawOptions};
use azure::azure_hl::{DrawSurfaceOptions,DrawTarget, Linear, SourceOp, StrokeOptions};
use azure::azure_hl::{DrawSurfaceOptions, DrawTarget, ExtendClamp, GradientStop, Linear};
use azure::azure_hl::{LinearGradientPattern, LinearGradientPatternRef, SourceOp, StrokeOptions};
use azure::scaled_font::ScaledFont;
use azure::{AZ_CAP_BUTT, AzDrawTargetFillGlyphs, AzFloat, struct__AzDrawOptions, struct__AzGlyph};
use azure::{struct__AzGlyphBuffer, struct__AzPoint};
use azure::{AZ_CAP_BUTT, AzFloat, struct__AzDrawOptions, struct__AzGlyph};
use azure::{struct__AzGlyphBuffer, struct__AzPoint, AzDrawTargetFillGlyphs};
use display_list::{SidewaysLeft, SidewaysRight, TextDisplayItem, Upright};
use font_context::FontContext;
use geom::matrix2d::Matrix2D;
use geom::point::Point2D;
use geom::rect::Rect;
use geom::size::Size2D;
use geom::side_offsets::SideOffsets2D;
use libc::types::common::c99::{uint16_t, uint32_t};
use geom::size::Size2D;
use libc::size_t;
use libc::types::common::c99::{uint16_t, uint32_t};
use png::{RGB8, RGBA8, K8, KA8};
use servo_net::image::base::Image;
use servo_util::geometry::Au;
@ -25,9 +26,10 @@ use servo_util::opts;
use servo_util::range::Range;
use std::num::Zero;
use std::ptr;
use style::computed_values::border_style;
use sync::Arc;
use text::glyph::CharIndex;
use text::TextRun;
use text::glyph::CharIndex;
pub struct RenderContext<'a> {
pub draw_target: &'a DrawTarget,
@ -443,6 +445,36 @@ impl<'a> RenderContext<'a> {
self.draw_target.set_transform(current_transform)
}
}
/// Draws a linear gradient in the given boundaries from the given start point to the given end
/// point with the given stops.
pub fn draw_linear_gradient(&self,
bounds: &Rect<Au>,
start_point: &Point2D<Au>,
end_point: &Point2D<Au>,
stops: &[GradientStop]) {
self.draw_target.make_current();
let stops = self.draw_target.create_gradient_stops(stops, ExtendClamp);
let pattern = LinearGradientPattern::new(&start_point.to_azure_point(),
&end_point.to_azure_point(),
stops,
&Matrix2D::identity());
self.draw_target.fill_rect(&bounds.to_azure_rect(),
LinearGradientPatternRef(&pattern),
None);
}
}
trait ToAzurePoint {
fn to_azure_point(&self) -> Point2D<AzFloat>;
}
impl ToAzurePoint for Point2D<Au> {
fn to_azure_point(&self) -> Point2D<AzFloat> {
Point2D(self.x.to_nearest_px() as AzFloat, self.y.to_nearest_px() as AzFloat)
}
}
trait ToAzureRect {
@ -451,8 +483,7 @@ trait ToAzureRect {
impl ToAzureRect for Rect<Au> {
fn to_azure_rect(&self) -> Rect<AzFloat> {
Rect(Point2D(self.origin.x.to_nearest_px() as AzFloat,
self.origin.y.to_nearest_px() as AzFloat),
Rect(self.origin.to_azure_point(),
Size2D(self.size.width.to_nearest_px() as AzFloat,
self.size.height.to_nearest_px() as AzFloat))
}