Auto merge of #389 - pcwalton:gradient-wrap, r=pcwalton

Implement gradient wrap/spread modes in SVG.

Closes #386.
This commit is contained in:
bors-servo 2020-07-13 15:41:15 -04:00 committed by GitHub
commit 7fceca9f97
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 45 additions and 11 deletions

View File

@ -24,6 +24,7 @@ use std::mem;
pub struct Gradient { pub struct Gradient {
pub geometry: GradientGeometry, pub geometry: GradientGeometry,
stops: Vec<ColorStop>, stops: Vec<ColorStop>,
pub wrap: GradientWrap,
} }
#[derive(Clone, Copy, PartialEq, Debug)] #[derive(Clone, Copy, PartialEq, Debug)]
@ -49,6 +50,12 @@ pub enum GradientGeometry {
} }
} }
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum GradientWrap {
Clamp,
Repeat,
}
impl Eq for Gradient {} impl Eq for Gradient {}
impl Hash for Gradient { impl Hash for Gradient {
@ -90,7 +97,11 @@ impl Hash for ColorStop {
impl Gradient { impl Gradient {
#[inline] #[inline]
pub fn linear(line: LineSegment2F) -> Gradient { pub fn linear(line: LineSegment2F) -> Gradient {
Gradient { geometry: GradientGeometry::Linear(line), stops: Vec::new() } Gradient {
geometry: GradientGeometry::Linear(line),
stops: Vec::new(),
wrap: GradientWrap::Clamp,
}
} }
#[inline] #[inline]
@ -104,6 +115,7 @@ impl Gradient {
Gradient { Gradient {
geometry: GradientGeometry::Radial { line: line.to_line(), radii, transform }, geometry: GradientGeometry::Radial { line: line.to_line(), radii, transform },
stops: Vec::new(), stops: Vec::new(),
wrap: GradientWrap::Clamp,
} }
} }

View File

@ -9,13 +9,13 @@
// except according to those terms. // except according to those terms.
use crate::allocator::{AllocationMode, TextureAllocator}; use crate::allocator::{AllocationMode, TextureAllocator};
use crate::gpu_data::{ColorCombineMode, RenderCommand, TextureLocation, TextureMetadataEntry, TexturePageDescriptor}; use crate::gpu_data::{ColorCombineMode, RenderCommand, TextureLocation, TextureMetadataEntry};
use crate::gpu_data::{TexturePageId, TileBatchTexture}; use crate::gpu_data::{TexturePageDescriptor, TexturePageId, TileBatchTexture};
use crate::scene::{RenderTarget, SceneId}; use crate::scene::{RenderTarget, SceneId};
use hashbrown::HashMap; use hashbrown::HashMap;
use pathfinder_color::ColorU; use pathfinder_color::ColorU;
use pathfinder_content::effects::{BlendMode, Filter, PatternFilter}; use pathfinder_content::effects::{BlendMode, Filter, PatternFilter};
use pathfinder_content::gradient::{Gradient, GradientGeometry}; use pathfinder_content::gradient::{Gradient, GradientGeometry, GradientWrap};
use pathfinder_content::pattern::{Pattern, PatternSource}; use pathfinder_content::pattern::{Pattern, PatternSource};
use pathfinder_content::render_target::RenderTargetId; use pathfinder_content::render_target::RenderTargetId;
use pathfinder_geometry::line_segment::LineSegment2F; use pathfinder_geometry::line_segment::LineSegment2F;
@ -368,12 +368,20 @@ impl Palette {
let color_texture_metadata = paint.overlay.as_ref().map(|overlay| { let color_texture_metadata = paint.overlay.as_ref().map(|overlay| {
match overlay.contents { match overlay.contents {
PaintContents::Gradient(ref gradient) => { PaintContents::Gradient(ref gradient) => {
let mut sampling_flags = TextureSamplingFlags::empty();
match gradient.wrap {
GradientWrap::Repeat => {
sampling_flags.insert(TextureSamplingFlags::REPEAT_U);
}
GradientWrap::Clamp => {}
}
// FIXME(pcwalton): The gradient size might not be big enough. Detect this. // FIXME(pcwalton): The gradient size might not be big enough. Detect this.
let location = gradient_tile_builder.allocate(allocator, gradient); let location = gradient_tile_builder.allocate(allocator, gradient);
PaintColorTextureMetadata { PaintColorTextureMetadata {
location, location,
page_scale: allocator.page_scale(location.page), page_scale: allocator.page_scale(location.page),
sampling_flags: TextureSamplingFlags::empty(), sampling_flags,
filter: match gradient.geometry { filter: match gradient.geometry {
GradientGeometry::Linear(_) => PaintFilter::None, GradientGeometry::Linear(_) => PaintFilter::None,
GradientGeometry::Radial { line, radii, .. } => { GradientGeometry::Radial { line, radii, .. } => {

View File

@ -17,7 +17,7 @@ use hashbrown::HashMap;
use pathfinder_color::ColorU; use pathfinder_color::ColorU;
use pathfinder_content::dash::OutlineDash; use pathfinder_content::dash::OutlineDash;
use pathfinder_content::fill::FillRule; use pathfinder_content::fill::FillRule;
use pathfinder_content::gradient::{ColorStop, Gradient}; use pathfinder_content::gradient::{ColorStop, Gradient, GradientWrap};
use pathfinder_content::outline::Outline; use pathfinder_content::outline::Outline;
use pathfinder_content::segment::{Segment, SegmentFlags}; use pathfinder_content::segment::{Segment, SegmentFlags};
use pathfinder_content::stroke::{LineCap, LineJoin, OutlineStrokeToFill, StrokeStyle}; use pathfinder_content::stroke::{LineCap, LineJoin, OutlineStrokeToFill, StrokeStyle};
@ -56,7 +56,6 @@ bitflags! {
const UNSUPPORTED_LINK_PAINT = 0x0020; const UNSUPPORTED_LINK_PAINT = 0x0020;
const UNSUPPORTED_FILTER_ATTR = 0x0040; const UNSUPPORTED_FILTER_ATTR = 0x0040;
const UNSUPPORTED_MASK_ATTR = 0x0080; const UNSUPPORTED_MASK_ATTR = 0x0080;
const UNSUPPORTED_GRADIENT_SPREAD_METHOD = 0x0100;
} }
} }
@ -237,11 +236,27 @@ impl SVGScene {
id: String, id: String,
usvg_base_gradient: &BaseGradient) { usvg_base_gradient: &BaseGradient) {
for stop in &usvg_base_gradient.stops { for stop in &usvg_base_gradient.stops {
gradient.add(ColorStop::from_usvg_stop(stop)); let mut stop = ColorStop::from_usvg_stop(stop);
if usvg_base_gradient.spread_method == SpreadMethod::Reflect {
stop.offset *= 0.5;
}
gradient.add(stop);
} }
if usvg_base_gradient.spread_method != SpreadMethod::Pad { // Reflect gradient if necessary.
self.result_flags.insert(BuildResultFlags::UNSUPPORTED_GRADIENT_SPREAD_METHOD); if usvg_base_gradient.spread_method == SpreadMethod::Reflect {
for stop in &usvg_base_gradient.stops {
let mut stop = ColorStop::from_usvg_stop(stop);
if usvg_base_gradient.spread_method == SpreadMethod::Reflect {
stop.offset = 1.0 - stop.offset * 0.5;
}
gradient.add(stop);
}
}
match usvg_base_gradient.spread_method {
SpreadMethod::Pad => {}
SpreadMethod::Reflect | SpreadMethod::Repeat => gradient.wrap = GradientWrap::Repeat,
} }
let transform = usvg_transform_to_transform_2d(&usvg_base_gradient.transform); let transform = usvg_transform_to_transform_2d(&usvg_base_gradient.transform);
@ -304,7 +319,6 @@ impl Display for BuildResultFlags {
"non-color paint", "non-color paint",
"filter attribute", "filter attribute",
"mask attribute", "mask attribute",
"gradient spread method",
]; ];
} }
} }