Add an API for gradients to the canvas frontend, not implemented yet
This commit is contained in:
parent
9a2e4f0b6d
commit
706b6dbd1d
|
@ -358,13 +358,15 @@ pub unsafe extern "C" fn PFCanvasSetTextAlign(canvas: PFCanvasRef, new_text_alig
|
|||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn PFCanvasSetFillStyle(canvas: PFCanvasRef, fill_style: PFFillStyleRef) {
|
||||
(*canvas).set_fill_style(*fill_style)
|
||||
// FIXME(pcwalton): Avoid the copy?
|
||||
(*canvas).set_fill_style((*fill_style).clone())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn PFCanvasSetStrokeStyle(canvas: PFCanvasRef,
|
||||
stroke_style: PFFillStyleRef) {
|
||||
(*canvas).set_stroke_style(*stroke_style)
|
||||
// FIXME(pcwalton): Avoid the copy?
|
||||
(*canvas).set_stroke_style((*stroke_style).clone())
|
||||
}
|
||||
|
||||
/// This function automatically destroys the path. If you wish to use the path again, clone it
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
use pathfinder_color::ColorU;
|
||||
use pathfinder_content::dash::OutlineDash;
|
||||
use pathfinder_content::gradient::Gradient;
|
||||
use pathfinder_content::outline::{ArcDirection, Contour, Outline};
|
||||
use pathfinder_content::stroke::{LineCap, LineJoin as StrokeLineJoin};
|
||||
use pathfinder_content::stroke::{OutlineStrokeToFill, StrokeStyle};
|
||||
|
@ -21,6 +22,7 @@ use pathfinder_geometry::rect::RectF;
|
|||
use pathfinder_geometry::transform2d::Transform2F;
|
||||
use pathfinder_renderer::paint::{Paint, PaintId};
|
||||
use pathfinder_renderer::scene::{PathObject, Scene};
|
||||
use std::borrow::Cow;
|
||||
use std::default::Default;
|
||||
use std::f32::consts::PI;
|
||||
use std::mem;
|
||||
|
@ -129,19 +131,19 @@ impl CanvasRenderingContext2D {
|
|||
|
||||
#[inline]
|
||||
pub fn set_fill_style(&mut self, new_fill_style: FillStyle) {
|
||||
self.current_state.fill_paint = new_fill_style.to_paint();
|
||||
self.current_state.fill_paint = new_fill_style.into_paint();
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_stroke_style(&mut self, new_stroke_style: FillStyle) {
|
||||
self.current_state.stroke_paint = new_stroke_style.to_paint();
|
||||
self.current_state.stroke_paint = new_stroke_style.into_paint();
|
||||
}
|
||||
|
||||
// Shadows
|
||||
|
||||
#[inline]
|
||||
pub fn set_shadow_color(&mut self, new_shadow_color: ColorU) {
|
||||
self.current_state.shadow_paint = Paint { color: new_shadow_color };
|
||||
self.current_state.shadow_paint = Paint::Color(new_shadow_color);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -156,7 +158,7 @@ impl CanvasRenderingContext2D {
|
|||
let mut outline = path.into_outline();
|
||||
outline.transform(&self.current_state.transform);
|
||||
|
||||
let paint = self.current_state.resolve_paint(self.current_state.fill_paint);
|
||||
let paint = self.current_state.resolve_paint(&self.current_state.fill_paint);
|
||||
let paint_id = self.scene.push_paint(&paint);
|
||||
|
||||
self.push_path(outline, paint_id);
|
||||
|
@ -164,7 +166,7 @@ impl CanvasRenderingContext2D {
|
|||
|
||||
#[inline]
|
||||
pub fn stroke_path(&mut self, path: Path2D) {
|
||||
let paint = self.current_state.resolve_paint(self.current_state.stroke_paint);
|
||||
let paint = self.current_state.resolve_paint(&self.current_state.stroke_paint);
|
||||
let paint_id = self.scene.push_paint(&paint);
|
||||
|
||||
let mut stroke_style = self.current_state.resolve_stroke_style();
|
||||
|
@ -195,7 +197,7 @@ impl CanvasRenderingContext2D {
|
|||
|
||||
fn push_path(&mut self, outline: Outline, paint_id: PaintId) {
|
||||
if !self.current_state.shadow_paint.is_fully_transparent() {
|
||||
let paint = self.current_state.resolve_paint(self.current_state.shadow_paint);
|
||||
let paint = self.current_state.resolve_paint(&self.current_state.shadow_paint);
|
||||
let paint_id = self.scene.push_paint(&paint);
|
||||
|
||||
let mut outline = outline.clone();
|
||||
|
@ -281,18 +283,23 @@ impl State {
|
|||
miter_limit: 10.0,
|
||||
line_dash: vec![],
|
||||
line_dash_offset: 0.0,
|
||||
fill_paint: Paint { color: ColorU::black() },
|
||||
stroke_paint: Paint { color: ColorU::black() },
|
||||
shadow_paint: Paint { color: ColorU::transparent_black() },
|
||||
fill_paint: Paint::black(),
|
||||
stroke_paint: Paint::black(),
|
||||
shadow_paint: Paint::transparent_black(),
|
||||
shadow_offset: Vector2F::default(),
|
||||
text_align: TextAlign::Left,
|
||||
global_alpha: 1.0,
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_paint(&self, mut paint: Paint) -> Paint {
|
||||
paint.color.a = (paint.color.a as f32 * self.global_alpha).round() as u8;
|
||||
paint
|
||||
fn resolve_paint<'a>(&self, paint: &'a Paint) -> Cow<'a, Paint> {
|
||||
if self.global_alpha == 1.0 {
|
||||
return Cow::Borrowed(paint);
|
||||
}
|
||||
|
||||
let mut paint = (*paint).clone();
|
||||
paint.set_opacity(self.global_alpha);
|
||||
Cow::Owned(paint)
|
||||
}
|
||||
|
||||
fn resolve_stroke_style(&self) -> StrokeStyle {
|
||||
|
@ -415,16 +422,18 @@ impl Path2D {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO(pcwalton): Gradients.
|
||||
#[derive(Clone, Copy)]
|
||||
#[derive(Clone)]
|
||||
pub enum FillStyle {
|
||||
Color(ColorU),
|
||||
Gradient(Gradient),
|
||||
}
|
||||
|
||||
impl FillStyle {
|
||||
#[inline]
|
||||
fn to_paint(&self) -> Paint {
|
||||
match *self { FillStyle::Color(color) => Paint { color } }
|
||||
fn into_paint(self) -> Paint {
|
||||
match self {
|
||||
FillStyle::Color(color) => Paint::Color(color),
|
||||
FillStyle::Gradient(gradient) => Paint::Gradient(gradient),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -52,6 +52,11 @@ impl ColorU {
|
|||
ColorF(color * F32x4::splat(1.0 / 255.0))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_opaque(&self) -> bool {
|
||||
self.a == !0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_fully_transparent(&self) -> bool {
|
||||
self.a == 0
|
||||
|
|
|
@ -10,27 +10,97 @@
|
|||
|
||||
use crate::sorted_vector::SortedVector;
|
||||
use pathfinder_color::ColorU;
|
||||
use std::cmp::PartialOrd;
|
||||
use pathfinder_geometry::line_segment::LineSegment2F;
|
||||
use pathfinder_simd::default::F32x4;
|
||||
use std::cmp::{self, Ordering, PartialOrd};
|
||||
use std::convert;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::mem;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
pub struct Gradient {
|
||||
line: LineSegment2F,
|
||||
stops: SortedVector<ColorStop>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
|
||||
pub struct ColorStop {
|
||||
pub offset: f32,
|
||||
pub color: ColorU,
|
||||
pub offset: f32,
|
||||
}
|
||||
|
||||
impl Eq for Gradient {}
|
||||
|
||||
impl Hash for Gradient {
|
||||
fn hash<H>(&self, state: &mut H) where H: Hasher {
|
||||
unsafe {
|
||||
let data: [u32; 4] = mem::transmute::<F32x4, [u32; 4]>(self.line.0);
|
||||
data.hash(state);
|
||||
self.stops.hash(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for ColorStop {}
|
||||
|
||||
impl Hash for ColorStop {
|
||||
fn hash<H>(&self, state: &mut H) where H: Hasher {
|
||||
unsafe {
|
||||
self.color.hash(state);
|
||||
let offset = mem::transmute::<f32, u32>(self.offset);
|
||||
offset.hash(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Gradient {
|
||||
#[inline]
|
||||
pub fn new(line: LineSegment2F) -> Gradient {
|
||||
Gradient { line, stops: SortedVector::new() }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn add_color_stop(&mut self, stop: ColorStop) {
|
||||
self.stops.push(stop);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn line(&self) -> LineSegment2F {
|
||||
self.line
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn stops(&self) -> &[ColorStop] {
|
||||
&self.stops.array
|
||||
}
|
||||
|
||||
pub fn sample(&self, t: f32) -> ColorU {
|
||||
if self.stops.is_empty() {
|
||||
return ColorU::transparent_black();
|
||||
}
|
||||
|
||||
let lower_index = self.stops.binary_search_by(|stop| {
|
||||
stop.offset.partial_cmp(&t).unwrap_or(Ordering::Less)
|
||||
}).unwrap_or_else(convert::identity);
|
||||
let upper_index = cmp::min(lower_index + 1, self.stops.len() - 1);
|
||||
|
||||
let lower_stop = &self.stops.array[lower_index];
|
||||
let upper_stop = &self.stops.array[upper_index];
|
||||
|
||||
let denom = upper_stop.offset - lower_stop.offset;
|
||||
if denom == 0.0 {
|
||||
return lower_stop.color;
|
||||
}
|
||||
|
||||
lower_stop.color
|
||||
.to_f32()
|
||||
.lerp(upper_stop.color.to_f32(), (t - lower_stop.offset) / denom)
|
||||
.to_u8()
|
||||
}
|
||||
|
||||
pub fn set_opacity(&mut self, alpha: f32) {
|
||||
for stop in &mut self.stops.array {
|
||||
stop.color.a = (stop.color.a as f32 * alpha).round() as u8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
use std::cmp::Ordering;
|
||||
use std::convert;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub struct SortedVector<T>
|
||||
where
|
||||
T: PartialOrd,
|
||||
|
@ -32,7 +32,7 @@ where
|
|||
|
||||
#[inline]
|
||||
pub fn push(&mut self, value: T) {
|
||||
let index = self.array.binary_search_by(|other| {
|
||||
let index = self.binary_search_by(|other| {
|
||||
other.partial_cmp(&value).unwrap_or(Ordering::Less)
|
||||
}).unwrap_or_else(convert::identity);
|
||||
self.array.insert(index, value);
|
||||
|
@ -58,6 +58,17 @@ where
|
|||
pub fn is_empty(&self) -> bool {
|
||||
self.array.is_empty()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn len(&self) -> usize {
|
||||
self.array.len()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn binary_search_by<'a, F>(&'a self, f: F) -> Result<usize, usize>
|
||||
where F: FnMut(&'a T) -> Ordering {
|
||||
self.array.binary_search_by(f)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -9,10 +9,11 @@
|
|||
// except according to those terms.
|
||||
|
||||
use pathfinder_content::segment::SegmentKind;
|
||||
use pathfinder_renderer::paint::Paint;
|
||||
use pathfinder_renderer::scene::Scene;
|
||||
use pathfinder_geometry::vector::Vector2F;
|
||||
use std::io::{self, Write};
|
||||
use std::fmt;
|
||||
use std::io::{self, Write};
|
||||
|
||||
mod pdf;
|
||||
use pdf::Pdf;
|
||||
|
@ -57,11 +58,7 @@ fn export_svg<W: Write>(scene: &Scene, writer: &mut W) -> io::Result<()> {
|
|||
if !name.is_empty() {
|
||||
write!(writer, " id=\"{}\"", name)?;
|
||||
}
|
||||
writeln!(
|
||||
writer,
|
||||
" fill=\"{:?}\" d=\"{:?}\" />",
|
||||
paint.color, outline
|
||||
)?;
|
||||
writeln!(writer, " fill=\"{:?}\" d=\"{:?}\" />", paint, outline)?;
|
||||
}
|
||||
writeln!(writer, "</svg>")?;
|
||||
Ok(())
|
||||
|
@ -79,7 +76,12 @@ fn export_pdf<W: Write>(scene: &Scene, writer: &mut W) -> io::Result<()> {
|
|||
};
|
||||
|
||||
for (paint, outline, _) in scene.paths() {
|
||||
pdf.set_fill_color(paint.color);
|
||||
match paint {
|
||||
Paint::Color(color) => pdf.set_fill_color(*color),
|
||||
Paint::Gradient(_) => {
|
||||
// TODO(pcwalton): Gradients.
|
||||
}
|
||||
}
|
||||
|
||||
for contour in outline.contours() {
|
||||
for (segment_index, segment) in contour.iter().enumerate() {
|
||||
|
@ -140,7 +142,7 @@ fn export_ps<W: Write>(scene: &Scene, writer: &mut W) -> io::Result<()> {
|
|||
} else {
|
||||
writeln!(writer, "newpath")?;
|
||||
}
|
||||
let color = paint.color.to_f32();
|
||||
|
||||
for contour in outline.contours() {
|
||||
for (segment_index, segment) in contour.iter().enumerate() {
|
||||
if segment_index == 0 {
|
||||
|
@ -174,7 +176,16 @@ fn export_ps<W: Write>(scene: &Scene, writer: &mut W) -> io::Result<()> {
|
|||
writeln!(writer, "closepath")?;
|
||||
}
|
||||
}
|
||||
writeln!(writer, "{} {} {} setrgbcolor", color.r(), color.g(), color.b())?;
|
||||
|
||||
match paint {
|
||||
Paint::Color(color) => {
|
||||
writeln!(writer, "{} {} {} setrgbcolor", color.r, color.g, color.b)?;
|
||||
}
|
||||
Paint::Gradient(_) => {
|
||||
// TODO(pcwalton): Gradients.
|
||||
}
|
||||
}
|
||||
|
||||
writeln!(writer, "fill")?;
|
||||
}
|
||||
writeln!(writer, "showpage")?;
|
||||
|
|
|
@ -10,12 +10,14 @@
|
|||
|
||||
use crate::allocator::{TextureAllocator, TextureLocation};
|
||||
use crate::gpu_data::PaintData;
|
||||
use crate::scene::Scene;
|
||||
use hashbrown::HashMap;
|
||||
use pathfinder_color::ColorU;
|
||||
use pathfinder_content::gradient::Gradient;
|
||||
use pathfinder_geometry::rect::RectI;
|
||||
use pathfinder_geometry::transform2d::{Matrix2x2I, Transform2I};
|
||||
use pathfinder_geometry::vector::Vector2I;
|
||||
use pathfinder_simd::default::I32x4;
|
||||
use std::fmt::{self, Debug, Formatter};
|
||||
|
||||
const PAINT_TEXTURE_LENGTH: u32 = 1024;
|
||||
const PAINT_TEXTURE_SCALE: u32 = 65536 / PAINT_TEXTURE_LENGTH;
|
||||
|
@ -23,23 +25,81 @@ const PAINT_TEXTURE_SCALE: u32 = 65536 / PAINT_TEXTURE_LENGTH;
|
|||
const SOLID_COLOR_TILE_LENGTH: u32 = 16;
|
||||
const MAX_SOLID_COLORS_PER_TILE: u32 = SOLID_COLOR_TILE_LENGTH * SOLID_COLOR_TILE_LENGTH;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct Paint {
|
||||
pub color: ColorU,
|
||||
#[derive(Clone)]
|
||||
pub struct Palette {
|
||||
pub(crate) paints: Vec<Paint>,
|
||||
cache: HashMap<Paint, PaintId>,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||
pub enum Paint {
|
||||
Color(ColorU),
|
||||
Gradient(Gradient),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||
pub struct PaintId(pub u16);
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
|
||||
pub struct GradientId(pub u32);
|
||||
|
||||
impl Debug for Paint {
|
||||
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
Paint::Color(color) => color.fmt(formatter),
|
||||
Paint::Gradient(_) => {
|
||||
// TODO(pcwalton)
|
||||
write!(formatter, "(gradient)")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Palette {
|
||||
#[inline]
|
||||
pub fn new() -> Palette {
|
||||
Palette { paints: vec![], cache: HashMap::new() }
|
||||
}
|
||||
}
|
||||
|
||||
impl Paint {
|
||||
#[inline]
|
||||
pub fn is_opaque(&self) -> bool {
|
||||
self.color.a == 255
|
||||
pub fn black() -> Paint {
|
||||
Paint::Color(ColorU::black())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn transparent_black() -> Paint {
|
||||
Paint::Color(ColorU::transparent_black())
|
||||
}
|
||||
|
||||
pub fn is_opaque(&self) -> bool {
|
||||
match *self {
|
||||
Paint::Color(color) => color.is_opaque(),
|
||||
Paint::Gradient(ref gradient) => {
|
||||
gradient.stops().iter().all(|stop| stop.color.is_opaque())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_fully_transparent(&self) -> bool {
|
||||
self.color.is_fully_transparent()
|
||||
match *self {
|
||||
Paint::Color(color) => color.is_opaque(),
|
||||
Paint::Gradient(ref gradient) => {
|
||||
gradient.stops().iter().all(|stop| stop.color.is_fully_transparent())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_opacity(&mut self, alpha: f32) {
|
||||
if alpha == 1.0 {
|
||||
return;
|
||||
}
|
||||
|
||||
match *self {
|
||||
Paint::Color(ref mut color) => color.a = (color.a as f32 * alpha).round() as u8,
|
||||
Paint::Gradient(ref mut gradient) => gradient.set_opacity(alpha),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -60,7 +120,19 @@ pub struct PaintMetadata {
|
|||
pub is_opaque: bool,
|
||||
}
|
||||
|
||||
impl Scene {
|
||||
impl Palette {
|
||||
#[allow(clippy::trivially_copy_pass_by_ref)]
|
||||
pub fn push_paint(&mut self, paint: &Paint) -> PaintId {
|
||||
if let Some(paint_id) = self.cache.get(paint) {
|
||||
return *paint_id;
|
||||
}
|
||||
|
||||
let paint_id = PaintId(self.paints.len() as u16);
|
||||
self.cache.insert((*paint).clone(), paint_id);
|
||||
self.paints.push((*paint).clone());
|
||||
paint_id
|
||||
}
|
||||
|
||||
pub fn build_paint_info(&self) -> PaintInfo {
|
||||
let mut allocator = TextureAllocator::new(PAINT_TEXTURE_LENGTH);
|
||||
let area = PAINT_TEXTURE_LENGTH as usize * PAINT_TEXTURE_LENGTH as usize;
|
||||
|
@ -68,14 +140,21 @@ impl Scene {
|
|||
let mut solid_color_tile_builder = SolidColorTileBuilder::new();
|
||||
|
||||
for paint in &self.paints {
|
||||
let tex_transform;
|
||||
match paint {
|
||||
Paint::Color(color) => {
|
||||
// TODO(pcwalton): Handle other paint types.
|
||||
let texture_location = solid_color_tile_builder.allocate(&mut allocator);
|
||||
put_pixel(&mut texels, texture_location.rect.origin(), paint.color);
|
||||
let tex_transform = Transform2I {
|
||||
put_pixel(&mut texels, texture_location.rect.origin(), *color);
|
||||
tex_transform = Transform2I {
|
||||
matrix: Matrix2x2I(I32x4::default()),
|
||||
vector: texture_location.rect.origin().scale(PAINT_TEXTURE_SCALE as i32) +
|
||||
Vector2I::splat(PAINT_TEXTURE_SCALE as i32 / 2),
|
||||
};
|
||||
}
|
||||
Paint::Gradient(_) => unimplemented!(),
|
||||
}
|
||||
|
||||
metadata.push(PaintMetadata { tex_transform, is_opaque: paint.is_opaque() });
|
||||
}
|
||||
|
||||
|
|
|
@ -14,8 +14,7 @@ use crate::builder::SceneBuilder;
|
|||
use crate::concurrent::executor::Executor;
|
||||
use crate::options::{BuildOptions, PreparedBuildOptions};
|
||||
use crate::options::{PreparedRenderTransform, RenderCommandListener};
|
||||
use crate::paint::{Paint, PaintId};
|
||||
use hashbrown::HashMap;
|
||||
use crate::paint::{Paint, PaintId, PaintInfo, Palette};
|
||||
use pathfinder_color::ColorU;
|
||||
use pathfinder_geometry::vector::Vector2F;
|
||||
use pathfinder_geometry::rect::RectF;
|
||||
|
@ -25,8 +24,7 @@ use pathfinder_content::outline::Outline;
|
|||
#[derive(Clone)]
|
||||
pub struct Scene {
|
||||
pub(crate) paths: Vec<PathObject>,
|
||||
pub(crate) paints: Vec<Paint>,
|
||||
paint_cache: HashMap<Paint, PaintId>,
|
||||
palette: Palette,
|
||||
bounds: RectF,
|
||||
view_box: RectF,
|
||||
}
|
||||
|
@ -36,8 +34,7 @@ impl Scene {
|
|||
pub fn new() -> Scene {
|
||||
Scene {
|
||||
paths: vec![],
|
||||
paints: vec![],
|
||||
paint_cache: HashMap::new(),
|
||||
palette: Palette::new(),
|
||||
bounds: RectF::default(),
|
||||
view_box: RectF::default(),
|
||||
}
|
||||
|
@ -48,16 +45,14 @@ impl Scene {
|
|||
self.paths.push(path);
|
||||
}
|
||||
|
||||
#[allow(clippy::trivially_copy_pass_by_ref)]
|
||||
pub fn push_paint(&mut self, paint: &Paint) -> PaintId {
|
||||
if let Some(paint_id) = self.paint_cache.get(paint) {
|
||||
return *paint_id;
|
||||
#[inline]
|
||||
pub fn build_paint_info(&self) -> PaintInfo {
|
||||
self.palette.build_paint_info()
|
||||
}
|
||||
|
||||
let paint_id = PaintId(self.paints.len() as u16);
|
||||
self.paint_cache.insert(*paint, paint_id);
|
||||
self.paints.push(*paint);
|
||||
paint_id
|
||||
#[allow(clippy::trivially_copy_pass_by_ref)]
|
||||
pub fn push_paint(&mut self, paint: &Paint) -> PaintId {
|
||||
self.palette.push_paint(paint)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -150,7 +145,11 @@ impl Scene {
|
|||
.any(|path_object| path_object.paint != first_paint_id) {
|
||||
return None;
|
||||
}
|
||||
Some(self.paints[first_paint_id.0 as usize].color)
|
||||
|
||||
match self.palette.paints[first_paint_id.0 as usize] {
|
||||
Paint::Color(color) => Some(color),
|
||||
Paint::Gradient(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -190,7 +189,7 @@ impl<'a> Iterator for PathIter<'a> {
|
|||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let item = self.scene.paths.get(self.pos).map(|path_object| {
|
||||
(
|
||||
self.scene.paints.get(path_object.paint.0 as usize).unwrap(),
|
||||
self.scene.palette.paints.get(path_object.paint.0 as usize).unwrap(),
|
||||
&path_object.outline,
|
||||
&*path_object.name
|
||||
)
|
||||
|
|
|
@ -246,16 +246,15 @@ impl PaintExt for Paint {
|
|||
#[inline]
|
||||
fn from_svg_paint(svg_paint: &UsvgPaint, opacity: Opacity, result_flags: &mut BuildResultFlags)
|
||||
-> Paint {
|
||||
Paint {
|
||||
color: match *svg_paint {
|
||||
// TODO(pcwalton): Support gradients.
|
||||
Paint::Color(match *svg_paint {
|
||||
UsvgPaint::Color(color) => ColorU::from_svg_color(color, opacity),
|
||||
UsvgPaint::Link(_) => {
|
||||
// TODO(pcwalton)
|
||||
result_flags.insert(BuildResultFlags::UNSUPPORTED_LINK_PAINT);
|
||||
ColorU::black()
|
||||
}
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,8 +13,8 @@ use crate::{Twips, Point2};
|
|||
use pathfinder_color::ColorU;
|
||||
use pathfinder_content::stroke::{LineJoin, LineCap};
|
||||
use pathfinder_renderer::paint::Paint;
|
||||
use std::mem;
|
||||
use std::cmp::Ordering;
|
||||
use std::mem;
|
||||
use swf_tree::tags::DefineShape;
|
||||
use swf_tree::{CapStyle, FillStyle, JoinStyle, LineStyle, ShapeRecord, StraightSRgba8, Vector2D};
|
||||
use swf_tree::{fill_styles, join_styles, shape_records};
|
||||
|
@ -149,10 +149,10 @@ impl StyleLayer {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn fill(&self) -> Paint {
|
||||
pub(crate) fn fill(&self) -> &Paint {
|
||||
match &self.fill {
|
||||
PaintOrLine::Paint(paint) => *paint,
|
||||
PaintOrLine::Line(line) => line.color,
|
||||
PaintOrLine::Paint(ref paint) => paint,
|
||||
PaintOrLine::Line(line) => &line.color,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -253,16 +253,7 @@ fn get_new_styles<'a>(
|
|||
a
|
||||
}
|
||||
}
|
||||
) => {
|
||||
Some(PaintOrLine::Paint(Paint {
|
||||
color: ColorU {
|
||||
r: *r,
|
||||
g: *g,
|
||||
b: *b,
|
||||
a: *a
|
||||
}
|
||||
}))
|
||||
},
|
||||
) => Some(PaintOrLine::Paint(Paint::Color(ColorU { r: *r, g: *g, b: *b, a: *a }))),
|
||||
_ => unimplemented!("Unimplemented fill style")
|
||||
}
|
||||
}).chain(
|
||||
|
@ -295,7 +286,7 @@ fn get_new_styles<'a>(
|
|||
// assert_eq!(start_cap, end_cap);
|
||||
Some(PaintOrLine::Line(SwfLineStyle {
|
||||
width: Twips(*width as i32),
|
||||
color: Paint { color: ColorU { r: *r, g: *g, b: *b, a: *a } },
|
||||
color: Paint::Color(ColorU { r: *r, g: *g, b: *b, a: *a }),
|
||||
join: match join {
|
||||
JoinStyle::Bevel => LineJoin::Bevel,
|
||||
JoinStyle::Round => LineJoin::Round,
|
||||
|
|
Loading…
Reference in New Issue