Implement DefineMorphShape tags.

This commit is contained in:
Mike Welsh 2017-02-22 18:48:12 -08:00
parent d76aef617b
commit b5a67bad71
8 changed files with 737 additions and 0 deletions

View File

@ -500,6 +500,8 @@ impl<R: Read> Reader<R> {
Some(TagCode::DefineFontInfo) => tag_reader.read_define_font_info(1)?,
Some(TagCode::DefineFontInfo2) => tag_reader.read_define_font_info(2)?,
Some(TagCode::DefineFontName) => tag_reader.read_define_font_name()?,
Some(TagCode::DefineMorphShape) => tag_reader.read_define_morph_shape(1)?,
Some(TagCode::DefineMorphShape2) => tag_reader.read_define_morph_shape(2)?,
Some(TagCode::DefineShape) => tag_reader.read_define_shape(1)?,
Some(TagCode::DefineShape2) => tag_reader.read_define_shape(2)?,
Some(TagCode::DefineShape3) => tag_reader.read_define_shape(3)?,
@ -1174,6 +1176,265 @@ impl<R: Read> Reader<R> {
})
}
fn read_define_morph_shape(&mut self, shape_version: u8) -> Result<Tag> {
let id = self.read_character_id()?;
let start_shape_bounds = self.read_rectangle()?;
let end_shape_bounds = self.read_rectangle()?;
let (start_edge_bounds, end_edge_bounds,
has_non_scaling_strokes, has_scaling_strokes) =
if shape_version >= 2 {
let start_edge_bounds = self.read_rectangle()?;
let end_edge_bounds = self.read_rectangle()?;
let flags = self.read_u8()?;
(start_edge_bounds, end_edge_bounds, flags & 0b10 != 0, flags & 0b1 != 0)
} else {
(start_shape_bounds.clone(), end_shape_bounds.clone(), true, false)
};
self.read_u32()?; // Offset to EndEdges.
let num_fill_styles = match self.read_u8()? {
0xff => self.read_u16()? as usize,
n => n as usize,
};
let mut start_fill_styles = Vec::with_capacity(num_fill_styles);
let mut end_fill_styles = Vec::with_capacity(num_fill_styles);
for _ in 0..num_fill_styles {
let (start, end) = self.read_morph_fill_style(shape_version)?;
start_fill_styles.push(start);
end_fill_styles.push(end);
}
let num_line_styles = match self.read_u8()? {
0xff => self.read_u16()? as usize,
n => n as usize,
};
let mut start_line_styles = Vec::with_capacity(num_line_styles);
let mut end_line_styles = Vec::with_capacity(num_line_styles);
for _ in 0..num_line_styles {
let (start, end) = self.read_morph_line_style(shape_version)?;
start_line_styles.push(start);
end_line_styles.push(end);
}
// TODO(Herschel): Add read_shape
self.num_fill_bits = self.read_ubits(4)? as u8;
self.num_line_bits = self.read_ubits(4)? as u8;
let mut start_shape = Vec::new();
while let Some(record) = self.read_shape_record(1)? {
start_shape.push(record);
}
self.byte_align();
let mut end_shape = Vec::new();
self.read_u8()?; // NumFillBits and NumLineBits are written as 0 for the end shape.
while let Some(record) = self.read_shape_record(1)? {
end_shape.push(record);
}
Ok(Tag::DefineMorphShape(Box::new(DefineMorphShape {
id: id,
version: shape_version,
has_non_scaling_strokes: has_non_scaling_strokes,
has_scaling_strokes: has_scaling_strokes,
start: MorphShape {
shape_bounds: start_shape_bounds,
edge_bounds: start_edge_bounds,
shape: start_shape,
fill_styles: start_fill_styles,
line_styles: start_line_styles,
},
end: MorphShape {
shape_bounds: end_shape_bounds,
edge_bounds: end_edge_bounds,
shape: end_shape,
fill_styles: end_fill_styles,
line_styles: end_line_styles,
},
})))
}
fn read_morph_line_style(&mut self, shape_version: u8) -> Result<(LineStyle, LineStyle)> {
if shape_version < 2 {
let start_width = self.read_u16()?;
let end_width = self.read_u16()?;
let start_color = self.read_rgba()?;
let end_color = self.read_rgba()?;
Ok((
LineStyle::new_v1(start_width, start_color),
LineStyle::new_v1(end_width, end_color)
))
} else {
// MorphLineStyle2 in DefineMorphShape2.
let start_width = self.read_u16()?;
let end_width = self.read_u16()?;
let start_cap = match self.read_ubits(2)? {
0 => LineCapStyle::Round,
1 => LineCapStyle::None,
2 => LineCapStyle::Square,
_ => return Err(Error::new(ErrorKind::InvalidData, "Invalid line cap type.")),
};
let join_style_id = self.read_ubits(2)?;
let has_fill = self.read_bit()?;
let allow_scale_x = !self.read_bit()?;
let allow_scale_y = !self.read_bit()?;
let is_pixel_hinted = self.read_bit()?;
self.read_ubits(5)?;
let allow_close = !self.read_bit()?;
let end_cap = match self.read_ubits(2)? {
0 => LineCapStyle::Round,
1 => LineCapStyle::None,
2 => LineCapStyle::Square,
_ => return Err(Error::new(ErrorKind::InvalidData, "Invalid line cap type.")),
};
let join_style = match join_style_id {
0 => LineJoinStyle::Round,
1 => LineJoinStyle::Bevel,
2 => LineJoinStyle::Miter(self.read_fixed8()?),
_ => return Err(Error::new(ErrorKind::InvalidData, "Invalid line cap type.")),
};
let (start_color, end_color) = if !has_fill {
(self.read_rgba()?, self.read_rgba()?)
} else {
(Color { r: 0, 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(shape_version)?;
(Some(start), Some(end))
} else {
(None, None)
};
Ok((
LineStyle {
width: start_width,
color: start_color,
start_cap: start_cap,
end_cap: end_cap,
join_style: join_style,
allow_scale_x: allow_scale_x,
allow_scale_y: allow_scale_y,
is_pixel_hinted: is_pixel_hinted,
allow_close: allow_close,
fill_style: start_fill_style,
},
LineStyle {
width: end_width,
color: end_color,
start_cap: start_cap,
end_cap: end_cap,
join_style: join_style,
allow_scale_x: allow_scale_x,
allow_scale_y: allow_scale_y,
is_pixel_hinted: is_pixel_hinted,
allow_close: allow_close,
fill_style: end_fill_style,
}
))
}
}
fn read_morph_fill_style(&mut self, shape_version: u8) -> Result<(FillStyle, FillStyle)> {
let fill_style_type = self.read_u8()?;
let fill_style = match fill_style_type {
0x00 => {
let start_color = self.read_rgba()?;
let end_color = self.read_rgba()?;
(FillStyle::Color(start_color), FillStyle::Color(end_color))
},
0x10 => {
let (start_gradient, end_gradient) = self.read_morph_gradient()?;
(
FillStyle::LinearGradient(start_gradient),
FillStyle::LinearGradient(end_gradient)
)
},
0x12 => {
let (start_gradient, end_gradient) = self.read_morph_gradient()?;
(
FillStyle::RadialGradient(start_gradient),
FillStyle::RadialGradient(end_gradient)
)
},
0x13 => {
if self.version < 8 || shape_version < 2 {
return Err(Error::new(ErrorKind::InvalidData,
"Focal gradients are only supported in SWF version 8 \
or higher."));
}
// TODO(Herschel): How is focal_point stored?
let (start_gradient, end_gradient) = self.read_morph_gradient()?;
let start_focal_point = self.read_fixed8()?;
let end_focal_point = self.read_fixed8()?;
(
FillStyle::FocalGradient {
gradient: start_gradient,
focal_point: start_focal_point,
},
FillStyle::FocalGradient {
gradient: end_gradient,
focal_point: end_focal_point,
}
)
},
0x40...0x43 => {
let id = self.read_character_id()?;
(
FillStyle::Bitmap {
id: id,
matrix: self.read_matrix()?,
is_smoothed: (fill_style_type & 0b10) == 0,
is_repeating: (fill_style_type & 0b01) == 0,
},
FillStyle::Bitmap {
id: id,
matrix: self.read_matrix()?,
is_smoothed: (fill_style_type & 0b10) == 0,
is_repeating: (fill_style_type & 0b01) == 0,
},
)
}
_ => return Err(Error::new(ErrorKind::InvalidData, "Invalid fill style.")),
};
Ok(fill_style)
}
fn read_morph_gradient(&mut self) -> Result<(Gradient, Gradient)> {
let start_matrix = self.read_matrix()?;
let end_matrix = self.read_matrix()?;
let num_records = self.read_u8()? as usize;
let mut start_records = Vec::with_capacity(num_records);
let mut end_records = Vec::with_capacity(num_records);
for _ in 0..num_records {
start_records.push(GradientRecord {
ratio: self.read_u8()?,
color: self.read_rgba()?,
});
end_records.push(GradientRecord {
ratio: self.read_u8()?,
color: self.read_rgba()?,
});
}
Ok((
Gradient {
matrix: start_matrix,
spread: GradientSpread::Pad, // TODO(Herschel): What are the defaults?
interpolation: GradientInterpolation::RGB,
records: start_records,
},
Gradient {
matrix: end_matrix,
spread: GradientSpread::Pad, // TODO(Herschel): What are the defaults?
interpolation: GradientInterpolation::RGB,
records: end_records,
}
))
}
fn read_define_shape(&mut self, version: u8) -> Result<Tag> {
let id = self.read_u16()?;
let shape_bounds = self.read_rectangle()?;

View File

@ -534,6 +534,238 @@ pub fn tag_tests() -> Vec<TagTestData> { vec![
read_tag_bytes_from_file("tests/swfs/DefineFont4-CC.swf", TagCode::DefineFontName)
),
(
3,
Tag::DefineMorphShape(Box::new(DefineMorphShape {
version: 1,
id: 1,
has_non_scaling_strokes: true,
has_scaling_strokes: false,
start: MorphShape {
shape_bounds: Rectangle { x_min: 15.0, x_max: 65.0, y_min: 15.0, y_max: 65.0 },
edge_bounds: Rectangle { x_min: 15.0, x_max: 65.0, y_min: 15.0, y_max: 65.0 },
fill_styles: vec![
FillStyle::LinearGradient(
Gradient {
matrix: Matrix {
translate_x: 40.0,
translate_y: 40.0,
scale_x: 0.024429321,
scale_y: 0.024429321,
rotate_skew_0: 0.024429321,
rotate_skew_1: -0.024429321
},
spread: GradientSpread::Pad,
interpolation: GradientInterpolation::RGB,
records: vec![
GradientRecord { ratio: 0, color: Color { r: 255, g: 255, b: 255, a: 255 } },
GradientRecord { ratio: 255, color: Color { r: 0, g: 0, b: 0, a: 255 } },
]
}
)
],
line_styles: vec![LineStyle::new_v1(200, Color { r: 0, g: 255, b: 0, a: 255 })],
shape: vec![
ShapeRecord::StyleChange(StyleChangeData {
move_to: Some((20.0, 20.0)),
fill_style_0: None,
fill_style_1: None,
line_style: Some(1),
new_styles: None
}),
ShapeRecord::StraightEdge { delta_x: 40.0, delta_y: 0.0 },
ShapeRecord::StraightEdge { delta_x: 0.0, delta_y: 40.0 },
ShapeRecord::StraightEdge { delta_x: -40.0, delta_y: 0.0 },
ShapeRecord::StraightEdge { delta_x: 0.0, delta_y: -40.0 },
ShapeRecord::StyleChange(StyleChangeData {
move_to: None,
fill_style_0: Some(1),
fill_style_1: None,
line_style: None,
new_styles: None
}),
ShapeRecord::StraightEdge { delta_x: 40.0, delta_y: 0.0 },
ShapeRecord::StraightEdge { delta_x: 0.0, delta_y: 40.0 },
ShapeRecord::StraightEdge { delta_x: -40.0, delta_y: 0.0 },
ShapeRecord::StraightEdge { delta_x: 0.0, delta_y: -40.0 },
]
},
end: MorphShape {
shape_bounds: Rectangle { x_min: 19.0, x_max: 75.05, y_min: 8.35, y_max: 61.0 },
edge_bounds: Rectangle { x_min: 19.0, x_max: 75.05, y_min: 8.35, y_max: 61.0 },
fill_styles: vec![
FillStyle::LinearGradient(Gradient {
matrix: Matrix {
translate_x: 48.4,
translate_y: 34.65,
scale_x: 0.0058898926,
scale_y: 0.030914307,
rotate_skew_0: 0.0,
rotate_skew_1: 0.0
},
spread: GradientSpread::Pad,
interpolation: GradientInterpolation::RGB,
records: vec![
GradientRecord { ratio: 56, color: Color { r: 255, g: 0, b: 0, a: 255 } },
GradientRecord { ratio: 157, color: Color { r: 0, g: 0, b: 255, a: 255 } }
]
})
],
line_styles: vec![LineStyle::new_v1( 40, Color { r: 255, g: 255, b: 0, a: 255 } )],
shape: vec![
ShapeRecord::StyleChange(StyleChangeData {
move_to: Some((20.0, 60.0)),
fill_style_0: None,
fill_style_1: None,
line_style: None,
new_styles: None
}),
ShapeRecord::StraightEdge { delta_x: 17.4, delta_y: -50.65 },
ShapeRecord::StraightEdge { delta_x: 22.6, delta_y: 10.65 },
ShapeRecord::CurvedEdge { control_delta_x: 28.15, control_delta_y: 19.1, anchor_delta_x: -28.15, anchor_delta_y: 20.9 },
ShapeRecord::CurvedEdge { control_delta_x: -19.05, control_delta_y: -22.0, anchor_delta_x: -20.95, anchor_delta_y: 22.0 },
ShapeRecord::StraightEdge { delta_x: 17.4, delta_y: -50.65 },
ShapeRecord::StraightEdge { delta_x: 22.6, delta_y: 10.65 },
ShapeRecord::CurvedEdge { control_delta_x: 28.15, control_delta_y: 19.1, anchor_delta_x: -28.15, anchor_delta_y: 20.9 },
ShapeRecord::CurvedEdge { control_delta_x: -19.05, control_delta_y: -22.0, anchor_delta_x: -20.95, anchor_delta_y: 22.0 }
]
}
})),
read_tag_bytes_from_file("tests/swfs/DefineMorphShape-MX.swf", TagCode::DefineMorphShape)
),
(
8,
Tag::DefineMorphShape(Box::new(DefineMorphShape {
version: 2,
id: 1,
has_non_scaling_strokes: false,
has_scaling_strokes: true,
start: MorphShape {
shape_bounds: Rectangle { x_min: 15.0, x_max: 225.0, y_min: 15.0, y_max: 225.0 },
edge_bounds: Rectangle { x_min: 20.0, x_max: 220.0, y_min: 20.0, y_max: 220.0 },
fill_styles: vec![
FillStyle::FocalGradient {
gradient: Gradient {
matrix: Matrix {
translate_x: 116.05,
translate_y: 135.05,
scale_x: 0.11468506,
scale_y: 0.18927002,
rotate_skew_0: 0.0,
rotate_skew_1: 0.0
},
spread: GradientSpread::Pad,
interpolation: GradientInterpolation::RGB,
records: vec![
GradientRecord { ratio: 0, color: Color { r: 255, g: 0, b: 0, a: 255 } },
GradientRecord { ratio: 70, color: Color { r: 255, g: 0, b: 255, a: 255 } },
GradientRecord { ratio: 255, color: Color { r: 0, g: 0, b: 0, a: 255 } }
]
},
focal_point: 0.97265625
}
],
line_styles: vec![
LineStyle {
width: 200,
color: Color { 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![
ShapeRecord::StyleChange(StyleChangeData {
move_to: Some((20.0, 20.0)),
fill_style_0: None,
fill_style_1: None,
line_style: Some(1),
new_styles: None
}),
ShapeRecord::StraightEdge { delta_x: 200.0, delta_y: 0.0 },
ShapeRecord::StraightEdge { delta_x: 0.0, delta_y: 200.0 },
ShapeRecord::StraightEdge { delta_x: -200.0, delta_y: 0.0 },
ShapeRecord::StraightEdge { delta_x: 0.0, delta_y: -200.0 },
ShapeRecord::StyleChange(StyleChangeData {
move_to: None,
fill_style_0: Some(1),
fill_style_1: None,
line_style: None,
new_styles: None
}),
ShapeRecord::StraightEdge { delta_x: 200.0, delta_y: 0.0 },
ShapeRecord::StraightEdge { delta_x: 0.0, delta_y: 200.0 },
ShapeRecord::StraightEdge { delta_x: -200.0, delta_y: 0.0 },
ShapeRecord::StraightEdge { delta_x: 0.0, delta_y: -200.0 }
]
},
end: MorphShape {
shape_bounds: Rectangle { x_min: 25.0, x_max: 212.05, y_min: 15.35, y_max: 148.35 },
edge_bounds: Rectangle { x_min: 26.0, x_max: 211.05, y_min: 16.35, y_max: 147.35 },
fill_styles: vec![
FillStyle::FocalGradient {
gradient: Gradient {
matrix: Matrix {
translate_x: 164.0,
translate_y: 150.05,
scale_x: 0.036087036,
scale_y: 0.041992188,
rotate_skew_0: 0.1347351,
rotate_skew_1: -0.15675354
},
spread: GradientSpread::Pad,
interpolation: GradientInterpolation::RGB,
records: vec![
GradientRecord { ratio: 0, color: Color { r: 0, g: 255, b: 255, a: 255 } },
GradientRecord { ratio: 183, color: Color { r: 0, g: 255, b: 0, a: 255 } },
GradientRecord { ratio: 226, color: Color { r: 255, g: 0, b: 255, a: 255 } }
]
},
focal_point: -0.9921875
}
],
line_styles: vec![
LineStyle {
width: 40,
color: Color { 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![
ShapeRecord::StyleChange(StyleChangeData {
move_to: Some((26.0, 147.35)),
fill_style_0: None,
fill_style_1: None,
line_style: None,
new_styles: None
}),
ShapeRecord::StraightEdge { delta_x: 95.0, delta_y: -131.0 },
ShapeRecord::StraightEdge { delta_x: 59.0, delta_y: 17.0 },
ShapeRecord::CurvedEdge { control_delta_x: 62.1, control_delta_y: 57.0, anchor_delta_x: -62.1, anchor_delta_y: 57.0 },
ShapeRecord::CurvedEdge { control_delta_x: -73.2, control_delta_y: -70.6, anchor_delta_x: -80.8, anchor_delta_y: 70.6 },
ShapeRecord::StraightEdge { delta_x: 95.0, delta_y: -131.0 },
ShapeRecord::StraightEdge { delta_x: 59.0, delta_y: 17.0 },
ShapeRecord::CurvedEdge { control_delta_x: 62.1, control_delta_y: 57.0, anchor_delta_x: -62.1, anchor_delta_y: 57.0 },
ShapeRecord::CurvedEdge { control_delta_x: -73.2, control_delta_y: -70.6, anchor_delta_x: -80.8, anchor_delta_y: 70.6 }
]
}
})),
read_tag_bytes_from_file("tests/swfs/DefineMorphShape2-CC.swf", TagCode::DefineMorphShape2)
),
(
8,
Tag::DefineScalingGrid {

View File

@ -318,6 +318,7 @@ pub enum Tag {
DefineFontAlignZones { id: CharacterId, thickness: FontThickness, zones: Vec<FontAlignZone> },
DefineFontInfo(Box<FontInfo>),
DefineFontName { id: CharacterId, name: String, copyright_info: String },
DefineMorphShape(Box<DefineMorphShape>),
DefineScalingGrid { id: CharacterId, splitter_rect: Rectangle },
DefineShape(Shape),
DefineSound(Box<Sound>),
@ -624,6 +625,25 @@ pub enum ButtonActionCondition {
KeyPress
}
#[derive(Clone, Debug, PartialEq)]
pub struct DefineMorphShape {
pub version: u8,
pub id: CharacterId,
pub has_non_scaling_strokes: bool,
pub has_scaling_strokes: bool,
pub start: MorphShape,
pub end: MorphShape,
}
#[derive(Clone, Debug, PartialEq)]
pub struct MorphShape {
pub shape_bounds: Rectangle,
pub edge_bounds: Rectangle,
pub fill_styles: Vec<FillStyle>,
pub line_styles: Vec<LineStyle>,
pub shape: Vec<ShapeRecord>,
}
#[derive(Clone, Debug, PartialEq)]
pub struct FontV1 {
pub id: CharacterId,

View File

@ -628,6 +628,8 @@ impl<W: Write> Writer<W> {
self.write_c_string(copyright_info)?;
},
&Tag::DefineMorphShape(ref define_morph_shape) => self.write_define_morph_shape(define_morph_shape)?,
&Tag::DefineScalingGrid { id, ref splitter_rect } => {
let mut buf = Vec::new();
{
@ -912,6 +914,228 @@ impl<W: Write> Writer<W> {
Ok(())
}
fn write_define_morph_shape(&mut self, data: &DefineMorphShape) -> Result<()> {
if data.start.fill_styles.len() != data.end.fill_styles.len() ||
data.start.line_styles.len() != data.end.line_styles.len() {
return Err(Error::new(ErrorKind::InvalidData,
"Start and end state of a morph shape must have the same number of styles."));
}
let num_fill_styles = data.start.fill_styles.len();
let num_line_styles = data.start.line_styles.len();
let num_fill_bits = count_ubits(num_fill_styles as u32);
let num_line_bits = count_ubits(num_line_styles as u32);
// Need to write styles first, to calculate offset to EndEdges.
let mut start_buf = Vec::new();
{
let mut writer = Writer::new(&mut start_buf, self.version);
// Styles
// TODO(Herschel): Make fn write_style_len. Check version.
if num_fill_styles >= 0xff {
writer.write_u8(0xff)?;
writer.write_u16(num_fill_styles as u16)?;
} else {
writer.write_u8(num_fill_styles as u8)?;
}
for (start, end) in data.start.fill_styles.iter().zip(data.end.fill_styles.iter()) {
writer.write_morph_fill_style(start, end, data.version)?;
}
if num_line_styles >= 0xff {
writer.write_u8(0xff)?;
writer.write_u16(num_line_styles as u16)?;
} else {
writer.write_u8(num_line_styles as u8)?;
}
for (start, end) in data.start.line_styles.iter().zip(data.end.line_styles.iter()) {
writer.write_morph_line_style(start, end, data.version)?;
}
// TODO(Herschel): Make fn write_shape.
writer.write_ubits(4, num_fill_bits as u32)?;
writer.write_ubits(4, num_line_bits as u32)?;
writer.num_fill_bits = num_fill_bits;
writer.num_line_bits = num_line_bits;
for shape_record in &data.start.shape {
writer.write_shape_record(shape_record, 1)?;
}
// End shape record.
writer.write_ubits(6, 0)?;
writer.flush_bits()?;
}
let mut buf = Vec::new();
{
let mut writer = Writer::new(&mut buf, self.version);
writer.write_character_id(data.id)?;
writer.write_rectangle(&data.start.shape_bounds)?;
writer.write_rectangle(&data.end.shape_bounds)?;
if data.version >= 2 {
writer.write_rectangle(&data.start.edge_bounds)?;
writer.write_rectangle(&data.end.edge_bounds)?;
writer.write_u8(
if data.has_non_scaling_strokes { 0b10 } else { 0 } |
if data.has_scaling_strokes { 0b1 } else { 0 }
)?;
}
// Offset to EndEdges.
writer.write_u32(start_buf.len() as u32)?;
writer.output.write_all(&start_buf)?;
// EndEdges.
writer.write_u8(0)?; // NumFillBits and NumLineBits are written as 0 for the end shape.
writer.num_fill_bits = num_fill_bits;
writer.num_line_bits = num_line_bits;
for shape_record in &data.end.shape {
writer.write_shape_record(shape_record, 1)?;
}
// End shape record.
writer.write_ubits(6, 0)?;
writer.flush_bits()?;
}
let tag_code = if data.version == 1 { TagCode::DefineMorphShape } else { TagCode::DefineMorphShape2 };
self.write_tag_header(tag_code, buf.len() as u32)?;
self.output.write_all(&buf)?;
Ok(())
}
fn write_morph_fill_style(&mut self, start: &FillStyle, end: &FillStyle, shape_version: u8) -> Result<()> {
match (start, end) {
(&FillStyle::Color(ref start_color), &FillStyle::Color(ref end_color)) => {
self.write_u8(0x00)?; // Solid color.
self.write_rgba(start_color)?;
self.write_rgba(end_color)?;
},
(&FillStyle::LinearGradient(ref start_gradient), &FillStyle::LinearGradient(ref end_gradient)) => {
self.write_u8(0x10)?; // Linear gradient.
self.write_morph_gradient(start_gradient, end_gradient)?;
},
(&FillStyle::RadialGradient(ref start_gradient), &FillStyle::RadialGradient(ref end_gradient)) => {
self.write_u8(0x12)?; // Linear gradient.
self.write_morph_gradient(start_gradient, end_gradient)?;
},
(
&FillStyle::FocalGradient { gradient: ref start_gradient, focal_point: start_focal_point },
&FillStyle::FocalGradient { gradient: ref end_gradient, focal_point: end_focal_point }
) => {
if self.version < 8 || shape_version < 2 {
return Err(Error::new(ErrorKind::InvalidData,
"Focal gradients are only support in SWF version 8 \
and higher."));
}
self.write_u8(0x13)?; // Focal gradient.
self.write_morph_gradient(start_gradient, end_gradient)?;
self.write_fixed8(start_focal_point)?;
self.write_fixed8(end_focal_point)?;
},
(
&FillStyle::Bitmap { id, matrix: ref start_matrix, is_smoothed, is_repeating },
&FillStyle::Bitmap { id: end_id, matrix: ref end_matrix, is_smoothed: end_is_smoothed, is_repeating: end_is_repeating }
) if id == end_id && is_smoothed == end_is_smoothed || is_repeating == end_is_repeating => {
let fill_style_type = match (is_smoothed, is_repeating) {
(true, true) => 0x40,
(true, false) => 0x41,
(false, true) => 0x42,
(false, false) => 0x43,
};
self.write_u8(fill_style_type)?;
self.write_u16(id)?;
self.write_matrix(start_matrix)?;
self.write_matrix(end_matrix)?;
},
_ => return Err(Error::new(ErrorKind::InvalidData,
"Morph start and end fill styles must be the same variant.")),
}
Ok(())
}
fn write_morph_gradient(&mut self, start: &Gradient, end: &Gradient) -> Result<()> {
self.write_matrix(&start.matrix)?;
self.write_matrix(&end.matrix)?;
if start.records.len() != end.records.len() {
return Err(Error::new(ErrorKind::InvalidData,
"Morph start and end gradient must have the same amount of records."));
}
self.write_u8(start.records.len() as u8)?;
for (start_record, end_record) in start.records.iter().zip(end.records.iter()) {
self.write_u8(start_record.ratio)?;
self.write_rgba(&start_record.color)?;
self.write_u8(end_record.ratio)?;
self.write_rgba(&end_record.color)?;
}
Ok(())
}
fn write_morph_line_style(&mut self, start: &LineStyle, end: &LineStyle, shape_version: u8) -> Result<()> {
if shape_version < 2 {
self.write_u16(start.width)?;
self.write_u16(end.width)?;
self.write_rgba(&start.color)?;
self.write_rgba(&end.color)?;
} else {
if start.start_cap != end.start_cap || 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::new(ErrorKind::InvalidData,
"Morph start and end line styles must have the same join parameters."));
}
self.write_u16(start.width)?;
self.write_u16(end.width)?;
// MorphLineStyle2
self.write_ubits(2, match start.start_cap {
LineCapStyle::Round => 0,
LineCapStyle::None => 1,
LineCapStyle::Square => 2,
})?;
self.write_ubits(2, match start.join_style {
LineJoinStyle::Round => 0,
LineJoinStyle::Bevel => 1,
LineJoinStyle::Miter(_) => 2,
})?;
self.write_bit(start.fill_style.is_some())?;
self.write_bit(!start.allow_scale_x)?;
self.write_bit(!start.allow_scale_y)?;
self.write_bit(start.is_pixel_hinted)?;
self.write_ubits(5, 0)?;
self.write_bit(!start.allow_close)?;
self.write_ubits(2, match start.end_cap {
LineCapStyle::Round => 0,
LineCapStyle::None => 1,
LineCapStyle::Square => 2,
})?;
if let LineJoinStyle::Miter(miter_factor) = start.join_style {
self.write_fixed8(miter_factor)?;
}
match (&start.fill_style, &end.fill_style) {
(&None, &None) => {
self.write_rgba(&start.color)?;
self.write_rgba(&end.color)?;
},
(&Some(ref start_fill), &Some(ref end_fill)) =>
self.write_morph_fill_style(start_fill, end_fill, shape_version)?,
_ => return Err(Error::new(ErrorKind::InvalidData,
"Morph start and end line styles must both have fill styles.")),
}
}
Ok(())
}
fn write_define_scene_and_frame_label_data(&mut self,
scenes: &Vec<FrameLabel>,
frame_labels: &Vec<FrameLabel>)

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.