Implement `fill-opacity` and `stroke-opacity` in SVG
This commit is contained in:
parent
25a6c33a1a
commit
0deb12b3a2
|
@ -82,8 +82,15 @@ impl<'a> SceneBuilder<'a> {
|
|||
let path_object = &scene.paths[path_index];
|
||||
let outline = scene.apply_render_options(path_object.outline(), built_options);
|
||||
let paint_id = path_object.paint();
|
||||
let object_is_opaque = scene.paints[paint_id.0 as usize].is_opaque();
|
||||
|
||||
let mut tiler = Tiler::new(self,
|
||||
&outline,
|
||||
view_box,
|
||||
path_index as u16,
|
||||
paint_id,
|
||||
object_is_opaque);
|
||||
|
||||
let mut tiler = Tiler::new(self, &outline, view_box, paint_id, path_index as u16);
|
||||
tiler.generate_tiles();
|
||||
|
||||
self.listener.send(RenderCommand::AddFills(tiler.built_object.fills));
|
||||
|
|
|
@ -9,12 +9,27 @@
|
|||
// except according to those terms.
|
||||
|
||||
use crate::gpu_data::PaintData;
|
||||
use crate::scene::{PaintId, Scene};
|
||||
use crate::scene::Scene;
|
||||
use pathfinder_geometry::basic::point::Point2DI32;
|
||||
use pathfinder_geometry::color::ColorU;
|
||||
|
||||
const PAINT_TEXTURE_WIDTH: i32 = 256;
|
||||
const PAINT_TEXTURE_HEIGHT: i32 = 256;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct Paint {
|
||||
pub color: ColorU,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||
pub struct PaintId(pub u16);
|
||||
|
||||
impl Paint {
|
||||
pub(crate) fn is_opaque(&self) -> bool {
|
||||
self.color.a == 255
|
||||
}
|
||||
}
|
||||
|
||||
impl Scene {
|
||||
pub fn build_paint_data(&self) -> PaintData {
|
||||
let size = Point2DI32::new(PAINT_TEXTURE_WIDTH, PAINT_TEXTURE_HEIGHT);
|
||||
|
|
|
@ -14,6 +14,7 @@ use crate::builder::SceneBuilder;
|
|||
use crate::concurrent::executor::Executor;
|
||||
use crate::options::{PreparedRenderOptions, PreparedRenderTransform};
|
||||
use crate::options::{RenderCommandListener, RenderOptions};
|
||||
use crate::paint::{Paint, PaintId};
|
||||
use hashbrown::HashMap;
|
||||
use pathfinder_geometry::basic::point::Point2DF32;
|
||||
use pathfinder_geometry::basic::rect::RectF32;
|
||||
|
@ -222,11 +223,3 @@ impl PathObject {
|
|||
self.paint
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct Paint {
|
||||
pub color: ColorU,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||
pub struct PaintId(pub u16);
|
||||
|
|
|
@ -10,8 +10,7 @@
|
|||
|
||||
use crate::builder::SceneBuilder;
|
||||
use crate::gpu_data::{AlphaTileBatchPrimitive, BuiltObject, TileObjectPrimitive};
|
||||
use crate::paint;
|
||||
use crate::scene::PaintId;
|
||||
use crate::paint::{self, PaintId};
|
||||
use crate::sorted_vector::SortedVector;
|
||||
use pathfinder_geometry::basic::line_segment::LineSegmentF32;
|
||||
use pathfinder_geometry::basic::point::{Point2DF32, Point2DI32};
|
||||
|
@ -33,6 +32,7 @@ pub(crate) struct Tiler<'a> {
|
|||
pub built_object: BuiltObject,
|
||||
paint_id: PaintId,
|
||||
object_index: u16,
|
||||
object_is_opaque: bool,
|
||||
|
||||
point_queue: SortedVector<QueuedEndpoint>,
|
||||
active_edges: SortedVector<ActiveEdge>,
|
||||
|
@ -45,8 +45,9 @@ impl<'a> Tiler<'a> {
|
|||
builder: &'a SceneBuilder<'a>,
|
||||
outline: &'a Outline,
|
||||
view_box: RectF32,
|
||||
paint_id: PaintId,
|
||||
object_index: u16,
|
||||
paint_id: PaintId,
|
||||
object_is_opaque: bool,
|
||||
) -> Tiler<'a> {
|
||||
let bounds = outline
|
||||
.bounds()
|
||||
|
@ -58,8 +59,9 @@ impl<'a> Tiler<'a> {
|
|||
builder,
|
||||
outline,
|
||||
built_object,
|
||||
paint_id,
|
||||
object_index,
|
||||
paint_id,
|
||||
object_is_opaque,
|
||||
|
||||
point_queue: SortedVector::new(),
|
||||
active_edges: SortedVector::new(),
|
||||
|
@ -112,13 +114,20 @@ impl<'a> Tiler<'a> {
|
|||
let tile_coords = self
|
||||
.built_object
|
||||
.local_tile_index_to_coords(tile_index as u32);
|
||||
|
||||
if tile.is_solid() {
|
||||
if tile.backdrop != 0 {
|
||||
self.builder.z_buffer.update(tile_coords, self.object_index);
|
||||
}
|
||||
// Blank tiles are always skipped.
|
||||
if tile.backdrop == 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If this is a solid tile, poke it into the Z-buffer and stop here.
|
||||
if self.object_is_opaque {
|
||||
self.builder.z_buffer.update(tile_coords, self.object_index);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
let origin_uv = paint::paint_id_to_tex_coords(self.paint_id);
|
||||
|
||||
let alpha_tile = AlphaTileBatchPrimitive::new(
|
||||
|
|
|
@ -21,10 +21,11 @@ use pathfinder_geometry::color::ColorU;
|
|||
use pathfinder_geometry::outline::Outline;
|
||||
use pathfinder_geometry::segment::{Segment, SegmentFlags};
|
||||
use pathfinder_geometry::stroke::OutlineStrokeToFill;
|
||||
use pathfinder_renderer::scene::{Paint, PathObject, Scene};
|
||||
use pathfinder_renderer::paint::Paint;
|
||||
use pathfinder_renderer::scene::{PathObject, Scene};
|
||||
use std::fmt::{Display, Formatter, Result as FormatResult};
|
||||
use std::mem;
|
||||
use usvg::{Color as SvgColor, Node, NodeExt, NodeKind, Paint as UsvgPaint};
|
||||
use usvg::{Color as SvgColor, Node, NodeExt, NodeKind, Opacity, Paint as UsvgPaint};
|
||||
use usvg::{PathSegment as UsvgPathSegment, Rect as UsvgRect, Transform as UsvgTransform};
|
||||
use usvg::{Tree, Visibility};
|
||||
|
||||
|
@ -114,9 +115,11 @@ impl BuiltSVG {
|
|||
}
|
||||
NodeKind::Path(ref path) if path.visibility == Visibility::Visible => {
|
||||
if let Some(ref fill) = path.fill {
|
||||
let style = self
|
||||
.scene
|
||||
.push_paint(&Paint::from_svg_paint(&fill.paint, &mut self.result_flags));
|
||||
let style = self.scene.push_paint(&Paint::from_svg_paint(
|
||||
&fill.paint,
|
||||
fill.opacity,
|
||||
&mut self.result_flags,
|
||||
));
|
||||
|
||||
let path = UsvgPathToSegments::new(path.segments.iter().cloned());
|
||||
let path = Transform2DF32PathIter::new(path, &transform);
|
||||
|
@ -129,6 +132,7 @@ impl BuiltSVG {
|
|||
if let Some(ref stroke) = path.stroke {
|
||||
let style = self.scene.push_paint(&Paint::from_svg_paint(
|
||||
&stroke.paint,
|
||||
stroke.opacity,
|
||||
&mut self.result_flags,
|
||||
));
|
||||
let stroke_width = f32::max(stroke.width.value() as f32, HAIRLINE_STROKE_WIDTH);
|
||||
|
@ -235,15 +239,17 @@ impl Display for BuildResultFlags {
|
|||
}
|
||||
|
||||
trait PaintExt {
|
||||
fn from_svg_paint(svg_paint: &UsvgPaint, result_flags: &mut BuildResultFlags) -> Self;
|
||||
fn from_svg_paint(svg_paint: &UsvgPaint, opacity: Opacity, result_flags: &mut BuildResultFlags)
|
||||
-> Self;
|
||||
}
|
||||
|
||||
impl PaintExt for Paint {
|
||||
#[inline]
|
||||
fn from_svg_paint(svg_paint: &UsvgPaint, result_flags: &mut BuildResultFlags) -> Paint {
|
||||
fn from_svg_paint(svg_paint: &UsvgPaint, opacity: Opacity, result_flags: &mut BuildResultFlags)
|
||||
-> Paint {
|
||||
Paint {
|
||||
color: match *svg_paint {
|
||||
UsvgPaint::Color(color) => ColorU::from_svg_color(color),
|
||||
UsvgPaint::Color(color) => ColorU::from_svg_color(color, opacity),
|
||||
UsvgPaint::Link(_) => {
|
||||
// TODO(pcwalton)
|
||||
result_flags.insert(BuildResultFlags::UNSUPPORTED_LINK_PAINT);
|
||||
|
@ -358,17 +364,17 @@ where
|
|||
}
|
||||
|
||||
trait ColorUExt {
|
||||
fn from_svg_color(svg_color: SvgColor) -> Self;
|
||||
fn from_svg_color(svg_color: SvgColor, opacity: Opacity) -> Self;
|
||||
}
|
||||
|
||||
impl ColorUExt for ColorU {
|
||||
#[inline]
|
||||
fn from_svg_color(svg_color: SvgColor) -> ColorU {
|
||||
fn from_svg_color(svg_color: SvgColor, opacity: Opacity) -> ColorU {
|
||||
ColorU {
|
||||
r: svg_color.red,
|
||||
g: svg_color.green,
|
||||
b: svg_color.blue,
|
||||
a: 255,
|
||||
a: (opacity.value() * 255.0).round() as u8,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue