swf: Clean up LineStyle
* Remove LineStyle::color, instead using fill_style with FillStyle::Color to indicate solid color. * Store `flags` in the struct instead of separate bools/values. * Add getters/setters for ease of use. * Add builder-style methods for setting LineStyle properties. * Fix misnamed ALLOW_CLOSE flag to NO_CLOSE.
This commit is contained in:
parent
99d8a5bff3
commit
146b8adc68
|
@ -291,21 +291,20 @@ fn line_style<'gc>(
|
||||||
Some(v) if v == b"bevel" => LineJoinStyle::Bevel,
|
Some(v) if v == b"bevel" => LineJoinStyle::Bevel,
|
||||||
_ => LineJoinStyle::Round,
|
_ => LineJoinStyle::Round,
|
||||||
};
|
};
|
||||||
|
let line_style = LineStyle::new()
|
||||||
|
.with_width(width)
|
||||||
|
.with_color(color)
|
||||||
|
.with_start_cap(cap_style)
|
||||||
|
.with_end_cap(cap_style)
|
||||||
|
.with_join_style(join_style)
|
||||||
|
.with_allow_scale_x(allow_scale_x)
|
||||||
|
.with_allow_scale_y(allow_scale_y)
|
||||||
|
.with_is_pixel_hinted(is_pixel_hinted)
|
||||||
|
.with_allow_close(false);
|
||||||
movie_clip
|
movie_clip
|
||||||
.as_drawing(activation.context.gc_context)
|
.as_drawing(activation.context.gc_context)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.set_line_style(Some(LineStyle {
|
.set_line_style(Some(line_style));
|
||||||
width,
|
|
||||||
color,
|
|
||||||
start_cap: cap_style,
|
|
||||||
end_cap: cap_style,
|
|
||||||
join_style,
|
|
||||||
fill_style: None,
|
|
||||||
allow_scale_x,
|
|
||||||
allow_scale_y,
|
|
||||||
is_pixel_hinted,
|
|
||||||
allow_close: false,
|
|
||||||
}));
|
|
||||||
} else {
|
} else {
|
||||||
movie_clip
|
movie_clip
|
||||||
.as_drawing(activation.context.gc_context)
|
.as_drawing(activation.context.gc_context)
|
||||||
|
|
|
@ -248,18 +248,16 @@ fn line_style<'gc>(
|
||||||
let join_style = joints_to_join_style(activation, joints, miter_limit)?;
|
let join_style = joints_to_join_style(activation, joints, miter_limit)?;
|
||||||
let (allow_scale_x, allow_scale_y) = scale_mode_to_allow_scale_bits(&scale_mode)?;
|
let (allow_scale_x, allow_scale_y) = scale_mode_to_allow_scale_bits(&scale_mode)?;
|
||||||
|
|
||||||
let line_style = LineStyle {
|
let line_style = LineStyle::new()
|
||||||
width,
|
.with_width(width)
|
||||||
color,
|
.with_color(color)
|
||||||
start_cap: caps,
|
.with_start_cap(caps)
|
||||||
end_cap: caps,
|
.with_end_cap(caps)
|
||||||
join_style,
|
.with_join_style(join_style)
|
||||||
fill_style: None,
|
.with_allow_scale_x(allow_scale_x)
|
||||||
allow_scale_x,
|
.with_allow_scale_y(allow_scale_y)
|
||||||
allow_scale_y,
|
.with_is_pixel_hinted(is_pixel_hinted)
|
||||||
is_pixel_hinted,
|
.with_allow_close(false);
|
||||||
allow_close: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(mut draw) = this.as_drawing(activation.context.gc_context) {
|
if let Some(mut draw) = this.as_drawing(activation.context.gc_context) {
|
||||||
draw.set_line_style(Some(line_style));
|
draw.set_line_style(Some(line_style));
|
||||||
|
|
|
@ -705,10 +705,11 @@ impl<'gc> EditText<'gc> {
|
||||||
let background_color = write.background_color;
|
let background_color = write.background_color;
|
||||||
|
|
||||||
if write.has_border {
|
if write.has_border {
|
||||||
write.drawing.set_line_style(Some(swf::LineStyle::new_v1(
|
write.drawing.set_line_style(Some(
|
||||||
Twips::new(1),
|
swf::LineStyle::new()
|
||||||
swf::Color::from_rgb(border_color, 0xFF),
|
.with_width(Twips::new(1))
|
||||||
)));
|
.with_color(swf::Color::from_rgb(border_color, 0xFF)),
|
||||||
|
));
|
||||||
} else {
|
} else {
|
||||||
write.drawing.set_line_style(None);
|
write.drawing.set_line_style(None);
|
||||||
}
|
}
|
||||||
|
|
|
@ -204,17 +204,11 @@ impl MorphShapeStatic {
|
||||||
.line_styles
|
.line_styles
|
||||||
.iter()
|
.iter()
|
||||||
.zip(self.end.line_styles.iter())
|
.zip(self.end.line_styles.iter())
|
||||||
.map(|(start, end)| LineStyle {
|
.map(|(start, end)| {
|
||||||
width: lerp_twips(start.width, end.width, a, b),
|
start
|
||||||
color: lerp_color(&start.color, &end.color, a, b),
|
.clone()
|
||||||
start_cap: start.start_cap,
|
.with_width(lerp_twips(start.width(), end.width(), a, b))
|
||||||
end_cap: start.end_cap,
|
.with_fill_style(lerp_fill(start.fill_style(), end.fill_style(), a, b))
|
||||||
join_style: start.join_style,
|
|
||||||
fill_style: None,
|
|
||||||
allow_scale_x: start.allow_scale_x,
|
|
||||||
allow_scale_y: start.allow_scale_y,
|
|
||||||
is_pixel_hinted: start.is_pixel_hinted,
|
|
||||||
allow_close: start.allow_close,
|
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
|
|
@ -177,7 +177,7 @@ impl Drawing {
|
||||||
// Add command to current line.
|
// Add command to current line.
|
||||||
let stroke_width = if let Some(line) = &mut self.current_line {
|
let stroke_width = if let Some(line) = &mut self.current_line {
|
||||||
line.commands.push(command.clone());
|
line.commands.push(command.clone());
|
||||||
line.style.width
|
line.style.width()
|
||||||
} else {
|
} else {
|
||||||
Twips::ZERO
|
Twips::ZERO
|
||||||
};
|
};
|
||||||
|
@ -310,7 +310,7 @@ impl Drawing {
|
||||||
DrawingPath::Line(line) => {
|
DrawingPath::Line(line) => {
|
||||||
if shape_utils::draw_command_stroke_hit_test(
|
if shape_utils::draw_command_stroke_hit_test(
|
||||||
&line.commands,
|
&line.commands,
|
||||||
line.style.width,
|
line.style.width(),
|
||||||
point,
|
point,
|
||||||
local_matrix,
|
local_matrix,
|
||||||
) {
|
) {
|
||||||
|
@ -330,7 +330,7 @@ impl Drawing {
|
||||||
for line in &self.pending_lines {
|
for line in &self.pending_lines {
|
||||||
if shape_utils::draw_command_stroke_hit_test(
|
if shape_utils::draw_command_stroke_hit_test(
|
||||||
&line.commands,
|
&line.commands,
|
||||||
line.style.width,
|
line.style.width(),
|
||||||
point,
|
point,
|
||||||
local_matrix,
|
local_matrix,
|
||||||
) {
|
) {
|
||||||
|
@ -341,7 +341,7 @@ impl Drawing {
|
||||||
if let Some(line) = &self.current_line {
|
if let Some(line) = &self.current_line {
|
||||||
if shape_utils::draw_command_stroke_hit_test(
|
if shape_utils::draw_command_stroke_hit_test(
|
||||||
&line.commands,
|
&line.commands,
|
||||||
line.style.width,
|
line.style.width(),
|
||||||
point,
|
point,
|
||||||
local_matrix,
|
local_matrix,
|
||||||
) {
|
) {
|
||||||
|
@ -362,7 +362,7 @@ impl Drawing {
|
||||||
y: self.fill_start.1,
|
y: self.fill_start.1,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
line.style.width,
|
line.style.width(),
|
||||||
point,
|
point,
|
||||||
local_matrix,
|
local_matrix,
|
||||||
)
|
)
|
||||||
|
|
|
@ -145,10 +145,11 @@ impl<'a, 'gc> LayoutContext<'a, 'gc> {
|
||||||
let mut line_drawing = Drawing::new();
|
let mut line_drawing = Drawing::new();
|
||||||
let mut has_underline: bool = false;
|
let mut has_underline: bool = false;
|
||||||
|
|
||||||
line_drawing.set_line_style(Some(swf::LineStyle::new_v1(
|
line_drawing.set_line_style(Some(
|
||||||
Twips::new(1),
|
swf::LineStyle::new()
|
||||||
swf::Color::from_rgb(0, 255),
|
.with_width(Twips::new(1))
|
||||||
)));
|
.with_color(swf::Color::from_rgb(0, 255)),
|
||||||
|
));
|
||||||
|
|
||||||
if let Some(linelist) = self.boxes.get(self.current_line..) {
|
if let Some(linelist) = self.boxes.get(self.current_line..) {
|
||||||
for linebox in linelist {
|
for linebox in linelist {
|
||||||
|
|
|
@ -761,7 +761,7 @@ pub fn shape_hit_test(
|
||||||
stroke_width = if i > 0 {
|
stroke_width = if i > 0 {
|
||||||
// Flash renders strokes with a 1px minimum width.
|
// Flash renders strokes with a 1px minimum width.
|
||||||
if let Some(line_style) = line_styles.get(i as usize - 1) {
|
if let Some(line_style) = line_styles.get(i as usize - 1) {
|
||||||
let width = line_style.width.get() as f64;
|
let width = line_style.width().get() as f64;
|
||||||
let scaled_width = 0.5 * width.max(min_width);
|
let scaled_width = 0.5 * width.max(min_width);
|
||||||
Some((scaled_width, scaled_width * scaled_width))
|
Some((scaled_width, scaled_width * scaled_width))
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1219,20 +1219,22 @@ fn swf_shape_to_svg(
|
||||||
// strokes end up rendering very faintly if we use the actual width of 1 twip.
|
// strokes end up rendering very faintly if we use the actual width of 1 twip.
|
||||||
// Therefore, we clamp the stroke width to 1 pixel (20 twips). This won't be 100% accurate
|
// Therefore, we clamp the stroke width to 1 pixel (20 twips). This won't be 100% accurate
|
||||||
// if the shape is scaled, but it looks much closer to the Flash Player.
|
// if the shape is scaled, but it looks much closer to the Flash Player.
|
||||||
let stroke_width = std::cmp::max(style.width.get(), 20);
|
let stroke_width = std::cmp::max(style.width().get(), 20);
|
||||||
|
let color = if let FillStyle::Color(color) = style.fill_style() {
|
||||||
|
color.clone()
|
||||||
|
} else {
|
||||||
|
Color::from_rgba(0)
|
||||||
|
};
|
||||||
let mut svg_path = SvgPath::new()
|
let mut svg_path = SvgPath::new()
|
||||||
.set("fill", "none")
|
.set("fill", "none")
|
||||||
.set(
|
.set(
|
||||||
"stroke",
|
"stroke",
|
||||||
format!(
|
format!("rgba({},{},{},{})", color.r, color.g, color.b, color.a),
|
||||||
"rgba({},{},{},{})",
|
|
||||||
style.color.r, style.color.g, style.color.b, style.color.a
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.set("stroke-width", stroke_width)
|
.set("stroke-width", stroke_width)
|
||||||
.set(
|
.set(
|
||||||
"stroke-linecap",
|
"stroke-linecap",
|
||||||
match style.start_cap {
|
match style.start_cap() {
|
||||||
LineCapStyle::Round => "round",
|
LineCapStyle::Round => "round",
|
||||||
LineCapStyle::Square => "square",
|
LineCapStyle::Square => "square",
|
||||||
LineCapStyle::None => "butt",
|
LineCapStyle::None => "butt",
|
||||||
|
@ -1240,14 +1242,14 @@ fn swf_shape_to_svg(
|
||||||
)
|
)
|
||||||
.set(
|
.set(
|
||||||
"stroke-linejoin",
|
"stroke-linejoin",
|
||||||
match style.join_style {
|
match style.join_style() {
|
||||||
LineJoinStyle::Round => "round",
|
LineJoinStyle::Round => "round",
|
||||||
LineJoinStyle::Bevel => "bevel",
|
LineJoinStyle::Bevel => "bevel",
|
||||||
LineJoinStyle::Miter(_) => "miter",
|
LineJoinStyle::Miter(_) => "miter",
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
if let LineJoinStyle::Miter(miter_limit) = style.join_style {
|
if let LineJoinStyle::Miter(miter_limit) = style.join_style() {
|
||||||
svg_path = svg_path.set("stroke-miterlimit", miter_limit.to_f32());
|
svg_path = svg_path.set("stroke-miterlimit", miter_limit.to_f32());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1480,23 +1482,25 @@ fn swf_shape_to_canvas_commands(
|
||||||
// strokes end up rendering very faintly if we use the actual width of 1 twip.
|
// strokes end up rendering very faintly if we use the actual width of 1 twip.
|
||||||
// Therefore, we clamp the stroke width to 1 pixel (20 twips). This won't be 100% accurate
|
// Therefore, we clamp the stroke width to 1 pixel (20 twips). This won't be 100% accurate
|
||||||
// if the shape is scaled, but it looks much closer to the Flash Player.
|
// if the shape is scaled, but it looks much closer to the Flash Player.
|
||||||
let line_width = std::cmp::max(style.width.get(), 20);
|
let line_width = std::cmp::max(style.width().get(), 20);
|
||||||
|
let color = if let FillStyle::Color(color) = style.fill_style() {
|
||||||
|
color.clone()
|
||||||
|
} else {
|
||||||
|
Color::from_rgba(0)
|
||||||
|
};
|
||||||
let stroke_style = CanvasColor(
|
let stroke_style = CanvasColor(
|
||||||
format!(
|
format!("rgba({},{},{},{})", color.r, color.g, color.b, color.a),
|
||||||
"rgba({},{},{},{})",
|
color.r,
|
||||||
style.color.r, style.color.g, style.color.b, style.color.a
|
color.g,
|
||||||
),
|
color.b,
|
||||||
style.color.r,
|
color.a,
|
||||||
style.color.g,
|
|
||||||
style.color.b,
|
|
||||||
style.color.a,
|
|
||||||
);
|
);
|
||||||
let line_cap = match style.start_cap {
|
let line_cap = match style.start_cap() {
|
||||||
LineCapStyle::Round => "round",
|
LineCapStyle::Round => "round",
|
||||||
LineCapStyle::Square => "square",
|
LineCapStyle::Square => "square",
|
||||||
LineCapStyle::None => "butt",
|
LineCapStyle::None => "butt",
|
||||||
};
|
};
|
||||||
let (line_join, miter_limit) = match style.join_style {
|
let (line_join, miter_limit) = match style.join_style() {
|
||||||
LineJoinStyle::Round => ("round", 999_999.0),
|
LineJoinStyle::Round => ("round", 999_999.0),
|
||||||
LineJoinStyle::Bevel => ("bevel", 999_999.0),
|
LineJoinStyle::Bevel => ("bevel", 999_999.0),
|
||||||
LineJoinStyle::Miter(ml) => ("miter", ml.to_f32()),
|
LineJoinStyle::Miter(ml) => ("miter", ml.to_f32()),
|
||||||
|
|
|
@ -205,30 +205,31 @@ impl ShapeTessellator {
|
||||||
commands,
|
commands,
|
||||||
is_closed,
|
is_closed,
|
||||||
} => {
|
} => {
|
||||||
let mut buffers_builder = BuffersBuilder::new(
|
let color = if let swf::FillStyle::Color(color) = &style.fill_style() {
|
||||||
&mut lyon_mesh,
|
color.clone()
|
||||||
RuffleVertexCtor {
|
} else {
|
||||||
color: style.color.clone(),
|
swf::Color::from_rgba(0)
|
||||||
},
|
};
|
||||||
);
|
let mut buffers_builder =
|
||||||
|
BuffersBuilder::new(&mut lyon_mesh, RuffleVertexCtor { color });
|
||||||
|
|
||||||
// TODO(Herschel): 0 width indicates "hairline".
|
// TODO(Herschel): 0 width indicates "hairline".
|
||||||
let width = (style.width.to_pixels() as f32).max(1.0);
|
let width = (style.width().to_pixels() as f32).max(1.0);
|
||||||
|
|
||||||
let mut options = StrokeOptions::default()
|
let mut options = StrokeOptions::default()
|
||||||
.with_line_width(width)
|
.with_line_width(width)
|
||||||
.with_start_cap(match style.start_cap {
|
.with_start_cap(match style.start_cap() {
|
||||||
swf::LineCapStyle::None => tessellation::LineCap::Butt,
|
swf::LineCapStyle::None => tessellation::LineCap::Butt,
|
||||||
swf::LineCapStyle::Round => tessellation::LineCap::Round,
|
swf::LineCapStyle::Round => tessellation::LineCap::Round,
|
||||||
swf::LineCapStyle::Square => tessellation::LineCap::Square,
|
swf::LineCapStyle::Square => tessellation::LineCap::Square,
|
||||||
})
|
})
|
||||||
.with_end_cap(match style.end_cap {
|
.with_end_cap(match style.end_cap() {
|
||||||
swf::LineCapStyle::None => tessellation::LineCap::Butt,
|
swf::LineCapStyle::None => tessellation::LineCap::Butt,
|
||||||
swf::LineCapStyle::Round => tessellation::LineCap::Round,
|
swf::LineCapStyle::Round => tessellation::LineCap::Round,
|
||||||
swf::LineCapStyle::Square => tessellation::LineCap::Square,
|
swf::LineCapStyle::Square => tessellation::LineCap::Square,
|
||||||
});
|
});
|
||||||
|
|
||||||
let line_join = match style.join_style {
|
let line_join = match style.join_style() {
|
||||||
swf::LineJoinStyle::Round => tessellation::LineJoin::Round,
|
swf::LineJoinStyle::Round => tessellation::LineJoin::Round,
|
||||||
swf::LineJoinStyle::Bevel => tessellation::LineJoin::Bevel,
|
swf::LineJoinStyle::Bevel => tessellation::LineJoin::Bevel,
|
||||||
swf::LineJoinStyle::Miter(limit) => {
|
swf::LineJoinStyle::Miter(limit) => {
|
||||||
|
|
162
swf/src/read.rs
162
swf/src/read.rs
|
@ -1354,78 +1354,53 @@ impl<'a> Reader<'a> {
|
||||||
let end_color = self.read_rgba()?;
|
let end_color = self.read_rgba()?;
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
LineStyle::new_v1(start_width, start_color),
|
LineStyle::new()
|
||||||
LineStyle::new_v1(end_width, end_color),
|
.with_width(start_width)
|
||||||
|
.with_color(start_color),
|
||||||
|
LineStyle::new().with_width(end_width).with_color(end_color),
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
// MorphLineStyle2 in DefineMorphShape2.
|
// MorphLineStyle2 in DefineMorphShape2.
|
||||||
let flags = LineStyleFlag::from_bits_truncate(self.read_u16()?);
|
let mut flags = LineStyleFlag::from_bits_truncate(self.read_u16()?);
|
||||||
let is_pixel_hinted = flags.contains(LineStyleFlag::PIXEL_HINTING);
|
// Verify valid cap and join styles.
|
||||||
let allow_scale_y = !flags.contains(LineStyleFlag::NO_V_SCALE);
|
if flags.contains(LineStyleFlag::JOIN_STYLE) {
|
||||||
let allow_scale_x = !flags.contains(LineStyleFlag::NO_H_SCALE);
|
log::warn!("Invalid line join style");
|
||||||
let has_fill = flags.contains(LineStyleFlag::HAS_FILL);
|
flags -= LineStyleFlag::JOIN_STYLE;
|
||||||
let join_style = match flags & LineStyleFlag::JOIN_STYLE {
|
}
|
||||||
LineStyleFlag::ROUND => LineJoinStyle::Round,
|
if flags.contains(LineStyleFlag::START_CAP_STYLE) {
|
||||||
LineStyleFlag::BEVEL => LineJoinStyle::Bevel,
|
log::warn!("Invalid line start cap style");
|
||||||
LineStyleFlag::MITER => LineJoinStyle::Miter(self.read_fixed8()?),
|
flags -= LineStyleFlag::START_CAP_STYLE;
|
||||||
_ => return Err(Error::invalid_data("Invalid line cap type.")),
|
}
|
||||||
|
if flags.contains(LineStyleFlag::END_CAP_STYLE) {
|
||||||
|
log::warn!("Invalid line end cap style");
|
||||||
|
flags -= LineStyleFlag::END_CAP_STYLE;
|
||||||
|
}
|
||||||
|
let miter_limit = if flags & LineStyleFlag::JOIN_STYLE == LineStyleFlag::MITER {
|
||||||
|
self.read_fixed8()?
|
||||||
|
} else {
|
||||||
|
Fixed8::ZERO
|
||||||
};
|
};
|
||||||
let start_cap =
|
let (start_fill_style, end_fill_style) = if flags.contains(LineStyleFlag::HAS_FILL) {
|
||||||
LineCapStyle::from_u8(((flags & LineStyleFlag::START_CAP_STYLE).bits() >> 6) as u8)
|
let (start, end) = self.read_morph_fill_style()?;
|
||||||
.ok_or_else(|| Error::invalid_data("Invalid line cap type."))?;
|
(start, end)
|
||||||
let end_cap =
|
|
||||||
LineCapStyle::from_u8(((flags & LineStyleFlag::END_CAP_STYLE).bits() >> 8) as u8)
|
|
||||||
.ok_or_else(|| Error::invalid_data("Invalid line cap type."))?;
|
|
||||||
let allow_close = !flags.contains(LineStyleFlag::ALLOW_CLOSE);
|
|
||||||
|
|
||||||
let (start_color, end_color) = if !has_fill {
|
|
||||||
(self.read_rgba()?, self.read_rgba()?)
|
|
||||||
} else {
|
} else {
|
||||||
(
|
(
|
||||||
Color {
|
FillStyle::Color(self.read_rgba()?),
|
||||||
r: 0,
|
FillStyle::Color(self.read_rgba()?),
|
||||||
g: 0,
|
|
||||||
b: 0,
|
|
||||||
a: 0,
|
|
||||||
},
|
|
||||||
Color {
|
|
||||||
r: 0,
|
|
||||||
g: 0,
|
|
||||||
b: 0,
|
|
||||||
a: 0,
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
let (start_fill_style, end_fill_style) = if has_fill {
|
|
||||||
let (start, end) = self.read_morph_fill_style()?;
|
|
||||||
(Some(start), Some(end))
|
|
||||||
} else {
|
|
||||||
(None, None)
|
|
||||||
};
|
|
||||||
Ok((
|
Ok((
|
||||||
LineStyle {
|
LineStyle {
|
||||||
width: start_width,
|
width: start_width,
|
||||||
color: start_color,
|
|
||||||
start_cap,
|
|
||||||
end_cap,
|
|
||||||
join_style,
|
|
||||||
allow_scale_x,
|
|
||||||
allow_scale_y,
|
|
||||||
is_pixel_hinted,
|
|
||||||
allow_close,
|
|
||||||
fill_style: start_fill_style,
|
fill_style: start_fill_style,
|
||||||
|
flags,
|
||||||
|
miter_limit,
|
||||||
},
|
},
|
||||||
LineStyle {
|
LineStyle {
|
||||||
width: end_width,
|
width: end_width,
|
||||||
color: end_color,
|
|
||||||
start_cap,
|
|
||||||
end_cap,
|
|
||||||
join_style,
|
|
||||||
allow_scale_x,
|
|
||||||
allow_scale_y,
|
|
||||||
is_pixel_hinted,
|
|
||||||
allow_close,
|
|
||||||
fill_style: end_fill_style,
|
fill_style: end_fill_style,
|
||||||
|
flags,
|
||||||
|
miter_limit,
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -1682,54 +1657,39 @@ impl<'a> Reader<'a> {
|
||||||
} else {
|
} else {
|
||||||
self.read_rgb()?
|
self.read_rgb()?
|
||||||
};
|
};
|
||||||
Ok(LineStyle::new_v1(width, color))
|
Ok(LineStyle::new().with_width(width).with_color(color))
|
||||||
} else {
|
} else {
|
||||||
// LineStyle2 in DefineShape4
|
// LineStyle2 in DefineShape4
|
||||||
let flags = LineStyleFlag::from_bits_truncate(self.read_u16()?);
|
let mut flags = LineStyleFlag::from_bits_truncate(self.read_u16()?);
|
||||||
let is_pixel_hinted = flags.contains(LineStyleFlag::PIXEL_HINTING);
|
// Verify valid cap and join styles.
|
||||||
let allow_scale_y = !flags.contains(LineStyleFlag::NO_V_SCALE);
|
if flags.contains(LineStyleFlag::JOIN_STYLE) {
|
||||||
let allow_scale_x = !flags.contains(LineStyleFlag::NO_H_SCALE);
|
log::warn!("Invalid line join style");
|
||||||
let has_fill = flags.contains(LineStyleFlag::HAS_FILL);
|
flags -= LineStyleFlag::JOIN_STYLE;
|
||||||
let join_style = match flags & LineStyleFlag::JOIN_STYLE {
|
}
|
||||||
LineStyleFlag::ROUND => LineJoinStyle::Round,
|
if flags.contains(LineStyleFlag::START_CAP_STYLE) {
|
||||||
LineStyleFlag::BEVEL => LineJoinStyle::Bevel,
|
log::warn!("Invalid line start cap style");
|
||||||
LineStyleFlag::MITER => LineJoinStyle::Miter(self.read_fixed8()?),
|
flags -= LineStyleFlag::START_CAP_STYLE;
|
||||||
_ => return Err(Error::invalid_data("Invalid line cap type.")),
|
}
|
||||||
|
if flags.contains(LineStyleFlag::END_CAP_STYLE) {
|
||||||
|
log::warn!("Invalid line end cap style");
|
||||||
|
flags -= LineStyleFlag::END_CAP_STYLE;
|
||||||
|
}
|
||||||
|
let miter_limit = if flags & LineStyleFlag::JOIN_STYLE == LineStyleFlag::MITER {
|
||||||
|
self.read_fixed8()?
|
||||||
|
} else {
|
||||||
|
Fixed8::ZERO
|
||||||
};
|
};
|
||||||
let start_cap =
|
|
||||||
LineCapStyle::from_u8(((flags & LineStyleFlag::START_CAP_STYLE).bits() >> 6) as u8)
|
|
||||||
.ok_or_else(|| Error::invalid_data("Invalid line cap type."))?;
|
|
||||||
let end_cap =
|
|
||||||
LineCapStyle::from_u8(((flags & LineStyleFlag::END_CAP_STYLE).bits() >> 8) as u8)
|
|
||||||
.ok_or_else(|| Error::invalid_data("Invalid line cap type."))?;
|
|
||||||
let allow_close = !flags.contains(LineStyleFlag::ALLOW_CLOSE);
|
|
||||||
|
|
||||||
let color = if !has_fill {
|
let fill_style = if flags.contains(LineStyleFlag::HAS_FILL) {
|
||||||
self.read_rgba()?
|
self.read_fill_style(shape_version)?
|
||||||
} else {
|
} else {
|
||||||
Color {
|
FillStyle::Color(self.read_rgba()?)
|
||||||
r: 0,
|
|
||||||
g: 0,
|
|
||||||
b: 0,
|
|
||||||
a: 0,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let fill_style = if has_fill {
|
|
||||||
Some(self.read_fill_style(shape_version)?)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
};
|
||||||
Ok(LineStyle {
|
Ok(LineStyle {
|
||||||
width,
|
width,
|
||||||
color,
|
|
||||||
start_cap,
|
|
||||||
end_cap,
|
|
||||||
join_style,
|
|
||||||
fill_style,
|
fill_style,
|
||||||
allow_scale_x,
|
flags,
|
||||||
allow_scale_y,
|
miter_limit,
|
||||||
is_pixel_hinted,
|
|
||||||
allow_close,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2995,15 +2955,9 @@ pub mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn read_line_style() {
|
fn read_line_style() {
|
||||||
// DefineShape1 and 2 read RGB colors.
|
// DefineShape1 and 2 read RGB colors.
|
||||||
let line_style = LineStyle::new_v1(
|
let line_style = LineStyle::new()
|
||||||
Twips::from_pixels(0.0),
|
.with_width(Twips::from_pixels(0.0))
|
||||||
Color {
|
.with_color(Color::from_rgba(0xffff0000));
|
||||||
r: 255,
|
|
||||||
g: 0,
|
|
||||||
b: 0,
|
|
||||||
a: 255,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
reader(&[0, 0, 255, 0, 0]).read_line_style(2).unwrap(),
|
reader(&[0, 0, 255, 0, 0]).read_line_style(2).unwrap(),
|
||||||
line_style
|
line_style
|
||||||
|
|
|
@ -737,15 +737,9 @@ pub fn tag_tests() -> Vec<TagTestData> {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
})],
|
})],
|
||||||
line_styles: vec![LineStyle::new_v1(
|
line_styles: vec![LineStyle::new()
|
||||||
Twips::from_pixels(10.0),
|
.with_width(Twips::from_pixels(10.0))
|
||||||
Color {
|
.with_color(Color::from_rgba(0xff00ff00))],
|
||||||
r: 0,
|
|
||||||
g: 255,
|
|
||||||
b: 0,
|
|
||||||
a: 255,
|
|
||||||
},
|
|
||||||
)],
|
|
||||||
shape: vec![
|
shape: vec![
|
||||||
ShapeRecord::StyleChange(Box::new(StyleChangeData {
|
ShapeRecord::StyleChange(Box::new(StyleChangeData {
|
||||||
move_to: Some((Twips::from_pixels(20.0), Twips::from_pixels(20.0))),
|
move_to: Some((Twips::from_pixels(20.0), Twips::from_pixels(20.0))),
|
||||||
|
@ -840,15 +834,9 @@ pub fn tag_tests() -> Vec<TagTestData> {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
})],
|
})],
|
||||||
line_styles: vec![LineStyle::new_v1(
|
line_styles: vec![LineStyle::new()
|
||||||
Twips::from_pixels(2.0),
|
.with_width(Twips::from_pixels(2.0))
|
||||||
Color {
|
.with_color(Color::from_rgba(0xffffff00))],
|
||||||
r: 255,
|
|
||||||
g: 255,
|
|
||||||
b: 0,
|
|
||||||
a: 255,
|
|
||||||
},
|
|
||||||
)],
|
|
||||||
shape: vec![
|
shape: vec![
|
||||||
ShapeRecord::StyleChange(Box::new(StyleChangeData {
|
ShapeRecord::StyleChange(Box::new(StyleChangeData {
|
||||||
move_to: Some((Twips::from_pixels(20.0), Twips::from_pixels(60.0))),
|
move_to: Some((Twips::from_pixels(20.0), Twips::from_pixels(60.0))),
|
||||||
|
@ -969,23 +957,9 @@ pub fn tag_tests() -> Vec<TagTestData> {
|
||||||
},
|
},
|
||||||
focal_point: Fixed8::from_f64(0.97265625),
|
focal_point: Fixed8::from_f64(0.97265625),
|
||||||
}],
|
}],
|
||||||
line_styles: vec![LineStyle {
|
line_styles: vec![LineStyle::new()
|
||||||
width: Twips::from_pixels(10.0),
|
.with_width(Twips::from_pixels(10.0))
|
||||||
color: Color {
|
.with_color(Color::from_rgba(0xff00ff00))],
|
||||||
r: 0,
|
|
||||||
g: 255,
|
|
||||||
b: 0,
|
|
||||||
a: 255,
|
|
||||||
},
|
|
||||||
start_cap: LineCapStyle::Round,
|
|
||||||
end_cap: LineCapStyle::Round,
|
|
||||||
join_style: LineJoinStyle::Round,
|
|
||||||
fill_style: None,
|
|
||||||
allow_scale_x: true,
|
|
||||||
allow_scale_y: true,
|
|
||||||
is_pixel_hinted: false,
|
|
||||||
allow_close: true,
|
|
||||||
}],
|
|
||||||
shape: vec![
|
shape: vec![
|
||||||
ShapeRecord::StyleChange(Box::new(StyleChangeData {
|
ShapeRecord::StyleChange(Box::new(StyleChangeData {
|
||||||
move_to: Some((Twips::from_pixels(20.0), Twips::from_pixels(20.0))),
|
move_to: Some((Twips::from_pixels(20.0), Twips::from_pixels(20.0))),
|
||||||
|
@ -1092,23 +1066,9 @@ pub fn tag_tests() -> Vec<TagTestData> {
|
||||||
},
|
},
|
||||||
focal_point: Fixed8::from_f64(-0.9921875),
|
focal_point: Fixed8::from_f64(-0.9921875),
|
||||||
}],
|
}],
|
||||||
line_styles: vec![LineStyle {
|
line_styles: vec![LineStyle::new()
|
||||||
width: Twips::from_pixels(2.0),
|
.with_width(Twips::from_pixels(2.0))
|
||||||
color: Color {
|
.with_color(Color::from_rgba(0xffffff00))],
|
||||||
r: 255,
|
|
||||||
g: 255,
|
|
||||||
b: 0,
|
|
||||||
a: 255,
|
|
||||||
},
|
|
||||||
start_cap: LineCapStyle::Round,
|
|
||||||
end_cap: LineCapStyle::Round,
|
|
||||||
join_style: LineJoinStyle::Round,
|
|
||||||
fill_style: None,
|
|
||||||
allow_scale_x: true,
|
|
||||||
allow_scale_y: true,
|
|
||||||
is_pixel_hinted: false,
|
|
||||||
allow_close: true,
|
|
||||||
}],
|
|
||||||
shape: vec![
|
shape: vec![
|
||||||
ShapeRecord::StyleChange(Box::new(StyleChangeData {
|
ShapeRecord::StyleChange(Box::new(StyleChangeData {
|
||||||
move_to: Some((Twips::from_pixels(26.0), Twips::from_pixels(147.35))),
|
move_to: Some((Twips::from_pixels(26.0), Twips::from_pixels(147.35))),
|
||||||
|
@ -1217,23 +1177,9 @@ pub fn tag_tests() -> Vec<TagTestData> {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
})],
|
})],
|
||||||
line_styles: vec![LineStyle {
|
line_styles: vec![LineStyle::new()
|
||||||
width: Twips::from_pixels(0.0),
|
.with_width(Twips::ZERO)
|
||||||
color: Color {
|
.with_color(Color::from_rgba(0x00000000))],
|
||||||
r: 0,
|
|
||||||
g: 0,
|
|
||||||
b: 0,
|
|
||||||
a: 0,
|
|
||||||
},
|
|
||||||
start_cap: LineCapStyle::Round,
|
|
||||||
end_cap: LineCapStyle::Round,
|
|
||||||
join_style: LineJoinStyle::Round,
|
|
||||||
fill_style: None,
|
|
||||||
allow_scale_x: true,
|
|
||||||
allow_scale_y: true,
|
|
||||||
is_pixel_hinted: false,
|
|
||||||
allow_close: true,
|
|
||||||
}],
|
|
||||||
shape: vec![
|
shape: vec![
|
||||||
ShapeRecord::StyleChange(Box::new(StyleChangeData {
|
ShapeRecord::StyleChange(Box::new(StyleChangeData {
|
||||||
move_to: None,
|
move_to: None,
|
||||||
|
@ -1305,23 +1251,9 @@ pub fn tag_tests() -> Vec<TagTestData> {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
})],
|
})],
|
||||||
line_styles: vec![LineStyle {
|
line_styles: vec![LineStyle::new()
|
||||||
width: Twips::from_pixels(0.0),
|
.with_width(Twips::from_pixels(0.0))
|
||||||
color: Color {
|
.with_color(Color::from_rgba(0x00000000))],
|
||||||
r: 0,
|
|
||||||
g: 0,
|
|
||||||
b: 0,
|
|
||||||
a: 0,
|
|
||||||
},
|
|
||||||
start_cap: LineCapStyle::Round,
|
|
||||||
end_cap: LineCapStyle::Round,
|
|
||||||
join_style: LineJoinStyle::Round,
|
|
||||||
fill_style: None,
|
|
||||||
allow_scale_x: true,
|
|
||||||
allow_scale_y: true,
|
|
||||||
is_pixel_hinted: false,
|
|
||||||
allow_close: true,
|
|
||||||
}],
|
|
||||||
shape: vec![
|
shape: vec![
|
||||||
ShapeRecord::StraightEdge {
|
ShapeRecord::StraightEdge {
|
||||||
delta_x: Twips::from_pixels(200.0),
|
delta_x: Twips::from_pixels(200.0),
|
||||||
|
@ -1641,35 +1573,23 @@ pub fn tag_tests() -> Vec<TagTestData> {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
line_styles: vec![
|
line_styles: vec![
|
||||||
LineStyle {
|
LineStyle::new()
|
||||||
width: Twips::from_pixels(20.0),
|
.with_width(Twips::from_pixels(20.0))
|
||||||
color: Color {
|
.with_color(Color {
|
||||||
r: 0,
|
r: 0,
|
||||||
g: 153,
|
g: 153,
|
||||||
b: 0,
|
b: 0,
|
||||||
a: 255,
|
a: 255,
|
||||||
},
|
})
|
||||||
start_cap: LineCapStyle::None,
|
.with_allow_scale_x(false)
|
||||||
end_cap: LineCapStyle::None,
|
.with_allow_scale_y(false)
|
||||||
join_style: LineJoinStyle::Bevel,
|
.with_is_pixel_hinted(true)
|
||||||
fill_style: None,
|
.with_join_style(LineJoinStyle::Bevel)
|
||||||
allow_scale_x: false,
|
.with_start_cap(LineCapStyle::None)
|
||||||
allow_scale_y: false,
|
.with_end_cap(LineCapStyle::None),
|
||||||
is_pixel_hinted: true,
|
LineStyle::new()
|
||||||
allow_close: true,
|
.with_width(Twips::from_pixels(20.0))
|
||||||
},
|
.with_fill_style(FillStyle::LinearGradient(Gradient {
|
||||||
LineStyle {
|
|
||||||
width: Twips::from_pixels(20.0),
|
|
||||||
color: Color {
|
|
||||||
r: 0,
|
|
||||||
g: 0,
|
|
||||||
b: 0,
|
|
||||||
a: 0,
|
|
||||||
},
|
|
||||||
start_cap: LineCapStyle::Round,
|
|
||||||
end_cap: LineCapStyle::Round,
|
|
||||||
join_style: LineJoinStyle::Round,
|
|
||||||
fill_style: Some(FillStyle::LinearGradient(Gradient {
|
|
||||||
matrix: Matrix {
|
matrix: Matrix {
|
||||||
tx: Twips::from_pixels(50.0),
|
tx: Twips::from_pixels(50.0),
|
||||||
ty: Twips::from_pixels(50.0),
|
ty: Twips::from_pixels(50.0),
|
||||||
|
@ -1700,29 +1620,20 @@ pub fn tag_tests() -> Vec<TagTestData> {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
})),
|
}))
|
||||||
allow_scale_x: true,
|
.with_allow_scale_y(false)
|
||||||
allow_scale_y: false,
|
.with_is_pixel_hinted(true),
|
||||||
is_pixel_hinted: true,
|
LineStyle::new()
|
||||||
allow_close: true,
|
.with_width(Twips::from_pixels(20.0))
|
||||||
},
|
.with_color(Color {
|
||||||
LineStyle {
|
|
||||||
width: Twips::from_pixels(20.0),
|
|
||||||
color: Color {
|
|
||||||
r: 0,
|
r: 0,
|
||||||
g: 153,
|
g: 153,
|
||||||
b: 0,
|
b: 0,
|
||||||
a: 255,
|
a: 255,
|
||||||
},
|
})
|
||||||
start_cap: LineCapStyle::Round,
|
.with_join_style(LineJoinStyle::Miter(Fixed8::from_f32(56.0)))
|
||||||
end_cap: LineCapStyle::Round,
|
.with_allow_scale_y(false)
|
||||||
join_style: LineJoinStyle::Miter(Fixed8::from_f32(56.0)),
|
.with_is_pixel_hinted(true),
|
||||||
fill_style: None,
|
|
||||||
allow_scale_x: true,
|
|
||||||
allow_scale_y: false,
|
|
||||||
is_pixel_hinted: true,
|
|
||||||
allow_close: true,
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
shape: vec![
|
shape: vec![
|
||||||
|
@ -2572,18 +2483,9 @@ pub fn tag_tests() -> Vec<TagTestData> {
|
||||||
has_scaling_strokes: true,
|
has_scaling_strokes: true,
|
||||||
styles: ShapeStyles {
|
styles: ShapeStyles {
|
||||||
fill_styles: vec![],
|
fill_styles: vec![],
|
||||||
line_styles: vec![LineStyle {
|
line_styles: vec![LineStyle::new()
|
||||||
width: Twips::from_pixels(40.0),
|
.with_width(Twips::from_pixels(40.0))
|
||||||
color: Color {
|
.with_fill_style(FillStyle::Bitmap {
|
||||||
r: 0,
|
|
||||||
g: 0,
|
|
||||||
b: 0,
|
|
||||||
a: 0,
|
|
||||||
},
|
|
||||||
start_cap: LineCapStyle::Round,
|
|
||||||
end_cap: LineCapStyle::Round,
|
|
||||||
join_style: LineJoinStyle::Round,
|
|
||||||
fill_style: Some(FillStyle::Bitmap {
|
|
||||||
id: 1,
|
id: 1,
|
||||||
matrix: Matrix {
|
matrix: Matrix {
|
||||||
a: Fixed16::from_f32(20.0),
|
a: Fixed16::from_f32(20.0),
|
||||||
|
@ -2594,12 +2496,7 @@ pub fn tag_tests() -> Vec<TagTestData> {
|
||||||
},
|
},
|
||||||
is_smoothed: false,
|
is_smoothed: false,
|
||||||
is_repeating: true,
|
is_repeating: true,
|
||||||
}),
|
})],
|
||||||
allow_scale_x: true,
|
|
||||||
allow_scale_y: true,
|
|
||||||
is_pixel_hinted: false,
|
|
||||||
allow_close: true,
|
|
||||||
}],
|
|
||||||
},
|
},
|
||||||
shape: vec![
|
shape: vec![
|
||||||
ShapeRecord::StyleChange(Box::new(StyleChangeData {
|
ShapeRecord::StyleChange(Box::new(StyleChangeData {
|
||||||
|
|
190
swf/src/types.rs
190
swf/src/types.rs
|
@ -1116,31 +1116,153 @@ pub struct GradientRecord {
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct LineStyle {
|
pub struct LineStyle {
|
||||||
pub width: Twips,
|
pub(crate) width: Twips,
|
||||||
pub color: Color,
|
pub(crate) fill_style: FillStyle,
|
||||||
pub start_cap: LineCapStyle,
|
pub(crate) flags: LineStyleFlag,
|
||||||
pub end_cap: LineCapStyle,
|
pub(crate) miter_limit: Fixed8,
|
||||||
pub join_style: LineJoinStyle,
|
|
||||||
pub fill_style: Option<FillStyle>,
|
|
||||||
pub allow_scale_x: bool,
|
|
||||||
pub allow_scale_y: bool,
|
|
||||||
pub is_pixel_hinted: bool,
|
|
||||||
pub allow_close: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LineStyle {
|
impl LineStyle {
|
||||||
pub const fn new_v1(width: Twips, color: Color) -> LineStyle {
|
#[inline]
|
||||||
LineStyle {
|
pub fn new() -> LineStyle {
|
||||||
width,
|
Default::default()
|
||||||
color,
|
}
|
||||||
start_cap: LineCapStyle::Round,
|
|
||||||
end_cap: LineCapStyle::Round,
|
#[inline]
|
||||||
join_style: LineJoinStyle::Round,
|
pub fn allow_close(&self) -> bool {
|
||||||
fill_style: None,
|
!self.flags.contains(LineStyleFlag::NO_CLOSE)
|
||||||
allow_scale_x: false,
|
}
|
||||||
allow_scale_y: false,
|
|
||||||
is_pixel_hinted: false,
|
#[inline]
|
||||||
allow_close: true,
|
pub fn with_allow_close(mut self, val: bool) -> Self {
|
||||||
|
self.flags.set(LineStyleFlag::NO_CLOSE, !val);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn allow_scale_x(&self) -> bool {
|
||||||
|
!self.flags.contains(LineStyleFlag::NO_H_SCALE)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn with_allow_scale_x(mut self, val: bool) -> Self {
|
||||||
|
self.flags.set(LineStyleFlag::NO_H_SCALE, !val);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn allow_scale_y(&self) -> bool {
|
||||||
|
!self.flags.contains(LineStyleFlag::NO_V_SCALE)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn with_allow_scale_y(mut self, val: bool) -> Self {
|
||||||
|
self.flags.set(LineStyleFlag::NO_V_SCALE, !val);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn is_pixel_hinted(&self) -> bool {
|
||||||
|
self.flags.contains(LineStyleFlag::PIXEL_HINTING)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn with_is_pixel_hinted(mut self, val: bool) -> Self {
|
||||||
|
self.flags.set(LineStyleFlag::PIXEL_HINTING, val);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn start_cap(&self) -> LineCapStyle {
|
||||||
|
let cap = (self.flags & LineStyleFlag::START_CAP_STYLE).bits() >> 6;
|
||||||
|
LineCapStyle::from_u8(cap as u8).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn with_start_cap(mut self, val: LineCapStyle) -> Self {
|
||||||
|
self.flags -= LineStyleFlag::START_CAP_STYLE;
|
||||||
|
self.flags |= LineStyleFlag::from_bits_truncate((val as u16) << 6);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn end_cap(&self) -> LineCapStyle {
|
||||||
|
let cap = (self.flags & LineStyleFlag::END_CAP_STYLE).bits() >> 8;
|
||||||
|
LineCapStyle::from_u8(cap as u8).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn with_end_cap(mut self, val: LineCapStyle) -> Self {
|
||||||
|
self.flags -= LineStyleFlag::END_CAP_STYLE;
|
||||||
|
self.flags |= LineStyleFlag::from_bits_truncate((val as u16) << 8);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn join_style(&self) -> LineJoinStyle {
|
||||||
|
match self.flags & LineStyleFlag::JOIN_STYLE {
|
||||||
|
LineStyleFlag::ROUND => LineJoinStyle::Round,
|
||||||
|
LineStyleFlag::BEVEL => LineJoinStyle::Bevel,
|
||||||
|
LineStyleFlag::MITER => LineJoinStyle::Miter(self.miter_limit),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn with_join_style(mut self, val: LineJoinStyle) -> Self {
|
||||||
|
self.flags -= LineStyleFlag::JOIN_STYLE;
|
||||||
|
self.flags |= match val {
|
||||||
|
LineJoinStyle::Round => LineStyleFlag::ROUND,
|
||||||
|
LineJoinStyle::Bevel => LineStyleFlag::BEVEL,
|
||||||
|
LineJoinStyle::Miter(miter_limit) => {
|
||||||
|
self.miter_limit = miter_limit;
|
||||||
|
LineStyleFlag::MITER
|
||||||
|
}
|
||||||
|
};
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn fill_style(&self) -> &FillStyle {
|
||||||
|
&self.fill_style
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn with_fill_style(mut self, val: FillStyle) -> Self {
|
||||||
|
self.flags
|
||||||
|
.set(LineStyleFlag::HAS_FILL, !matches!(val, FillStyle::Color(_)));
|
||||||
|
self.fill_style = val;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn with_color(mut self, val: Color) -> Self {
|
||||||
|
self.flags.remove(LineStyleFlag::HAS_FILL);
|
||||||
|
self.fill_style = FillStyle::Color(val);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn width(&self) -> Twips {
|
||||||
|
self.width
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn with_width(mut self, val: Twips) -> Self {
|
||||||
|
self.width = val;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for LineStyle {
|
||||||
|
#[inline]
|
||||||
|
fn default() -> Self {
|
||||||
|
// Hairline black stroke.
|
||||||
|
Self {
|
||||||
|
width: Twips::ZERO,
|
||||||
|
fill_style: FillStyle::Color(Color::from_rgb(0, 255)),
|
||||||
|
flags: Default::default(),
|
||||||
|
miter_limit: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1157,7 +1279,7 @@ bitflags! {
|
||||||
|
|
||||||
// Second byte.
|
// Second byte.
|
||||||
const END_CAP_STYLE = 0b11 << 8;
|
const END_CAP_STYLE = 0b11 << 8;
|
||||||
const ALLOW_CLOSE = 1 << 10;
|
const NO_CLOSE = 1 << 10;
|
||||||
|
|
||||||
// JOIN_STYLE mask values.
|
// JOIN_STYLE mask values.
|
||||||
const ROUND = 0b00 << 4;
|
const ROUND = 0b00 << 4;
|
||||||
|
@ -1166,6 +1288,13 @@ bitflags! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for LineStyleFlag {
|
||||||
|
#[inline]
|
||||||
|
fn default() -> Self {
|
||||||
|
LineStyleFlag::empty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, Copy, FromPrimitive)]
|
#[derive(Debug, PartialEq, Clone, Copy, FromPrimitive)]
|
||||||
pub enum LineCapStyle {
|
pub enum LineCapStyle {
|
||||||
Round = 0,
|
Round = 0,
|
||||||
|
@ -1174,11 +1303,19 @@ pub enum LineCapStyle {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LineCapStyle {
|
impl LineCapStyle {
|
||||||
|
#[inline]
|
||||||
pub fn from_u8(n: u8) -> Option<Self> {
|
pub fn from_u8(n: u8) -> Option<Self> {
|
||||||
num_traits::FromPrimitive::from_u8(n)
|
num_traits::FromPrimitive::from_u8(n)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for LineCapStyle {
|
||||||
|
#[inline]
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Round
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||||
pub enum LineJoinStyle {
|
pub enum LineJoinStyle {
|
||||||
Round,
|
Round,
|
||||||
|
@ -1186,6 +1323,13 @@ pub enum LineJoinStyle {
|
||||||
Miter(Fixed8),
|
Miter(Fixed8),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for LineJoinStyle {
|
||||||
|
#[inline]
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Round
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, Copy, FromPrimitive)]
|
#[derive(Debug, PartialEq, Clone, Copy, FromPrimitive)]
|
||||||
pub enum AudioCompression {
|
pub enum AudioCompression {
|
||||||
UncompressedUnknownEndian = 0,
|
UncompressedUnknownEndian = 0,
|
||||||
|
|
113
swf/src/write.rs
113
swf/src/write.rs
|
@ -1205,17 +1205,19 @@ impl<W: Write> Writer<W> {
|
||||||
// TODO(Herschel): Handle overflow.
|
// TODO(Herschel): Handle overflow.
|
||||||
self.write_u16(start.width.get() as u16)?;
|
self.write_u16(start.width.get() as u16)?;
|
||||||
self.write_u16(end.width.get() as u16)?;
|
self.write_u16(end.width.get() as u16)?;
|
||||||
self.write_rgba(&start.color)?;
|
match (&start.fill_style, &end.fill_style) {
|
||||||
self.write_rgba(&end.color)?;
|
(FillStyle::Color(start), FillStyle::Color(end)) => {
|
||||||
|
self.write_rgba(start)?;
|
||||||
|
self.write_rgba(end)?;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(Error::invalid_data(
|
||||||
|
"Complex line styles can only be used in DefineMorphShape2 tags",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if start.start_cap != end.start_cap
|
if start.flags != end.flags {
|
||||||
|| start.join_style != end.join_style
|
|
||||||
|| start.allow_scale_x != end.allow_scale_x
|
|
||||||
|| start.allow_scale_y != end.allow_scale_y
|
|
||||||
|| start.is_pixel_hinted != end.is_pixel_hinted
|
|
||||||
|| start.allow_close != end.allow_close
|
|
||||||
|| start.end_cap != end.end_cap
|
|
||||||
{
|
|
||||||
return Err(Error::invalid_data(
|
return Err(Error::invalid_data(
|
||||||
"Morph start and end line styles must have the same join parameters.",
|
"Morph start and end line styles must have the same join parameters.",
|
||||||
));
|
));
|
||||||
|
@ -1226,41 +1228,21 @@ impl<W: Write> Writer<W> {
|
||||||
self.write_u16(end.width.get() as u16)?;
|
self.write_u16(end.width.get() as u16)?;
|
||||||
|
|
||||||
// MorphLineStyle2
|
// MorphLineStyle2
|
||||||
let mut bits = self.bits();
|
self.write_u16(start.flags.bits())?;
|
||||||
bits.write_ubits(2, start.start_cap as u32)?;
|
if let LineJoinStyle::Miter(miter_factor) = start.join_style() {
|
||||||
bits.write_ubits(
|
|
||||||
2,
|
|
||||||
match start.join_style {
|
|
||||||
LineJoinStyle::Round => 0,
|
|
||||||
LineJoinStyle::Bevel => 1,
|
|
||||||
LineJoinStyle::Miter(_) => 2,
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
bits.write_bit(start.fill_style.is_some())?;
|
|
||||||
bits.write_bit(!start.allow_scale_x)?;
|
|
||||||
bits.write_bit(!start.allow_scale_y)?;
|
|
||||||
bits.write_bit(start.is_pixel_hinted)?;
|
|
||||||
bits.write_ubits(5, 0)?;
|
|
||||||
bits.write_bit(!start.allow_close)?;
|
|
||||||
bits.write_ubits(2, start.end_cap as u32)?;
|
|
||||||
drop(bits);
|
|
||||||
if let LineJoinStyle::Miter(miter_factor) = start.join_style {
|
|
||||||
self.write_fixed8(miter_factor)?;
|
self.write_fixed8(miter_factor)?;
|
||||||
}
|
}
|
||||||
match (&start.fill_style, &end.fill_style) {
|
if start.flags.contains(LineStyleFlag::HAS_FILL) {
|
||||||
(&None, &None) => {
|
self.write_morph_fill_style(&start.fill_style, &end.fill_style)?;
|
||||||
self.write_rgba(&start.color)?;
|
} else {
|
||||||
self.write_rgba(&end.color)?;
|
match (&start.fill_style, &end.fill_style) {
|
||||||
}
|
(FillStyle::Color(start), FillStyle::Color(end)) => {
|
||||||
|
self.write_rgba(start)?;
|
||||||
(&Some(ref start_fill), &Some(ref end_fill)) => {
|
self.write_rgba(end)?;
|
||||||
self.write_morph_fill_style(start_fill, end_fill)?
|
}
|
||||||
}
|
_ => {
|
||||||
|
return Err(Error::invalid_data("Unexpected line fill style fill type"));
|
||||||
_ => {
|
}
|
||||||
return Err(Error::invalid_data(
|
|
||||||
"Morph start and end line styles must both have fill styles.",
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1584,34 +1566,31 @@ impl<W: Write> Writer<W> {
|
||||||
self.write_u16(line_style.width.get() as u16)?;
|
self.write_u16(line_style.width.get() as u16)?;
|
||||||
if shape_version >= 4 {
|
if shape_version >= 4 {
|
||||||
// LineStyle2
|
// LineStyle2
|
||||||
let mut flags = LineStyleFlag::empty();
|
self.write_u16(line_style.flags.bits())?;
|
||||||
flags.set(LineStyleFlag::PIXEL_HINTING, line_style.is_pixel_hinted);
|
if let LineJoinStyle::Miter(miter_factor) = line_style.join_style() {
|
||||||
flags.set(LineStyleFlag::NO_V_SCALE, !line_style.allow_scale_y);
|
|
||||||
flags.set(LineStyleFlag::NO_H_SCALE, !line_style.allow_scale_x);
|
|
||||||
flags.set(LineStyleFlag::HAS_FILL, line_style.fill_style.is_some());
|
|
||||||
flags |= match line_style.join_style {
|
|
||||||
LineJoinStyle::Round => LineStyleFlag::ROUND,
|
|
||||||
LineJoinStyle::Bevel => LineStyleFlag::BEVEL,
|
|
||||||
LineJoinStyle::Miter(_) => LineStyleFlag::MITER,
|
|
||||||
};
|
|
||||||
let mut flags = flags.bits();
|
|
||||||
flags |= (line_style.start_cap as u16) << 6;
|
|
||||||
flags |= (line_style.end_cap as u16) << 8;
|
|
||||||
self.write_u16(flags)?;
|
|
||||||
|
|
||||||
if let LineJoinStyle::Miter(miter_factor) = line_style.join_style {
|
|
||||||
self.write_fixed8(miter_factor)?;
|
self.write_fixed8(miter_factor)?;
|
||||||
}
|
}
|
||||||
match line_style.fill_style {
|
if line_style.flags.contains(LineStyleFlag::HAS_FILL) {
|
||||||
None => self.write_rgba(&line_style.color)?,
|
self.write_fill_style(&line_style.fill_style, shape_version)?;
|
||||||
Some(ref fill) => self.write_fill_style(fill, shape_version)?,
|
} else if let FillStyle::Color(color) = &line_style.fill_style {
|
||||||
|
self.write_rgba(color)?;
|
||||||
|
} else {
|
||||||
|
return Err(Error::invalid_data("Unexpected line style fill type"));
|
||||||
}
|
}
|
||||||
} else if shape_version >= 3 {
|
|
||||||
// LineStyle1 with RGBA
|
|
||||||
self.write_rgba(&line_style.color)?;
|
|
||||||
} else {
|
} else {
|
||||||
// LineStyle1 with RGB
|
// LineStyle1
|
||||||
self.write_rgb(&line_style.color)?;
|
let color = if let FillStyle::Color(color) = &line_style.fill_style {
|
||||||
|
color
|
||||||
|
} else {
|
||||||
|
return Err(Error::invalid_data(
|
||||||
|
"Complex line styles can only be used in DefineShape4 tags",
|
||||||
|
));
|
||||||
|
};
|
||||||
|
if shape_version >= 3 {
|
||||||
|
self.write_rgba(color)?
|
||||||
|
} else {
|
||||||
|
self.write_rgb(color)?
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue