Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ The release run heads these entries with the version and opens a fresh

## Unreleased

- A curve in a StarView metafile is drawn as a curve. The polygon flags that
say which of its points are bezier control points were read and dropped, so
every curve came out as a line through them.

- A StarView metafile's map mode is read in full: its unit, so a drawing that
switches to twips or points is no longer off by the factor between them, and
the relative map mode, which composes with the one before it rather than
Expand Down
14 changes: 9 additions & 5 deletions src/odr/internal/svm/PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,11 @@ Each stage is one pull request, stacked on the one before it.
`TRANSPARENT` are done. `WALLPAPER` and `FLOATTRANSPARENT` are not: the
first has a format of its own, the second nests a whole metafile.
8. **The map mode** (#772 defect 6) - done.
9. **Stretch.** BΓ©zier flags (#772 defect 4), the `EPS` substitute metafile,
and version-1 (pre-`VCLMTF`) files via `SvmConverter.cxx`.
9. **Stretch.** BΓ©zier flags (#772 defect 4) are done. Left: `WALLPAPER`,
`FLOATTRANSPARENT` and `EPS`, which all nest something of their own; the
`MASK` family; `MOVECLIPREGION`; `ZCOMPRESS`ed bitmaps; and version-1
(pre-`VCLMTF`) files via `SvmConverter.cxx`. None of them occurs in the
corpus.

The order follows what files actually contain, not the action list. Over 1125
metafiles harvested from the `odt`/`ods` fixtures:
Expand Down Expand Up @@ -122,9 +125,10 @@ are worth writing down:
What is left: `ZCOMPRESS`, a LibreOffice-only compression whose zlib stream
would have to be inflated (miniz is already a dependency) before any of the
above, and the `MASK` family, which stencils one colour through a bitmap.
- **BΓ©ziers are cheap once the flags are read.** A polygon flag of
`PolyFlags::Control` marks a control point, so a flagged polygon maps onto an
SVG path's `C` segments directly. The reader is the part that is missing.
- **BΓ©ziers were cheap once the flags were read** - this one is taken. A
polygon that carries curves is written *twice*, the second time with one
`PolyFlags` per point, and two control points between two corners are an
svg `C`.
- **Gradients, hatches and dashes are declarative in SVG** β€”
`<linearGradient>`, `<radialGradient>`, `<pattern>`, `stroke-dasharray`. No
rasterising, no tiling by hand.
Expand Down
59 changes: 42 additions & 17 deletions src/odr/internal/svm/svm_format.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -362,23 +362,39 @@ svm::Rectangle svm::read_rectangle(std::istream &in) {
return result;
}

std::vector<svm::IntPair> svm::read_polygon(std::istream &in) {
std::vector<IntPair> result;
svm::Polygon svm::read_polygon(std::istream &in) {
Polygon result;

std::uint16_t size;
read_primitive(in, size);

result.resize(size);
for (auto &&p : result) {
result.points.resize(size);
for (auto &&p : result.points) {
p = read_int_pair(in);
}

return result;
}

std::vector<std::vector<svm::IntPair>>
svm::read_poly_polygon(std::istream &in) {
std::vector<std::vector<IntPair>> result;
svm::Polygon svm::read_flagged_polygon(std::istream &in) {
read_version_length(in);

Polygon result = read_polygon(in);

bool has_flags{};
read_primitive(in, has_flags);
if (has_flags) {
result.flags.resize(result.points.size());
for (auto &&flag : result.flags) {
read_primitive(in, flag);
}
}

return result;
}

std::vector<svm::Polygon> svm::read_poly_polygon(std::istream &in) {
std::vector<Polygon> result;

std::uint16_t size;
read_primitive(in, size);
Expand Down Expand Up @@ -562,18 +578,20 @@ svm::PolyLineAction svm::read_poly_line_action(std::istream &in,
const VersionLength &vl) {
PolyLineAction result;

result.points = read_polygon(in);
result.polygon = read_polygon(in);

if (vl.version >= 2) {
result.line_info = read_line_info(in);
}

if (vl.version >= 3) {
bool has_flags;
bool has_flags{};
read_primitive(in, has_flags);

// the same polygon again, with what each point is; it replaces the
// corners-only one read above
if (has_flags) {
// TODO flags not implemented
result.polygon = read_flagged_polygon(in);
}
}

Expand All @@ -584,14 +602,14 @@ svm::PolygonAction svm::read_polygon_action(std::istream &in,
const VersionLength &vl) {
PolygonAction result;

result.points = read_polygon(in);
result.polygon = read_polygon(in);

if (vl.version >= 3) {
bool has_flags;
if (vl.version >= 2) {
bool has_flags{};
read_primitive(in, has_flags);

if (has_flags) {
// TODO flags not implemented
result.polygon = read_flagged_polygon(in);
}
}

Expand All @@ -605,11 +623,18 @@ svm::PolyPolygonAction svm::read_poly_polygon_action(std::istream &in,
result.polygons = read_poly_polygon(in);

if (vl.version >= 2) {
std::uint16_t complex_polygons;
std::uint16_t complex_polygons{};
read_primitive(in, complex_polygons);

if (complex_polygons > 0) {
// TODO complex not implemented
// each names one of the polygons above and replaces it with the same
// shape, curves included
for (std::uint16_t i = 0; i < complex_polygons; ++i) {
std::uint16_t index{};
read_primitive(in, index);
Polygon polygon = read_flagged_polygon(in);
if (index < result.polygons.size()) {
result.polygons[index] = std::move(polygon);
}
}
}

Expand Down
31 changes: 25 additions & 6 deletions src/odr/internal/svm/svm_format.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,15 @@ enum MetaFontStrikeout {
STRIKEOUT_NONE = 0,
};

/// `PolyFlags`: what a polygon's point is. Two `CONTROL` points between two
/// corners are a bezier segment; everything else is a line.
enum MetaPolyFlags {
POLY_NORMAL = 0,
POLY_SMOOTH = 1,
POLY_CONTROL = 2,
POLY_SYMMETRIC = 3,
};

/// `MapUnit`, the unit a map mode's coordinates are in. `MAP_RELATIVE` has
/// none of its own: it composes with the map mode before it.
enum MetaMapUnit {
Expand Down Expand Up @@ -288,17 +297,24 @@ struct ArcAction final {
IntPair end;
};

struct PolyLineAction final {
/// A polygon, and - where the file carried them - what its points are.
struct Polygon final {
std::vector<IntPair> points;
/// One `PolyFlags` per point, or empty where every point is a corner.
std::vector<std::uint8_t> flags;
};

struct PolyLineAction final {
Polygon polygon;
LineInfo line_info;
};

struct PolygonAction final {
std::vector<IntPair> points;
Polygon polygon;
};

struct PolyPolygonAction final {
std::vector<std::vector<IntPair>> polygons;
std::vector<Polygon> polygons;
};

struct TextAction final {
Expand Down Expand Up @@ -363,7 +379,7 @@ struct Hatch final {
/// clip at all, is no region and reads as `std::nullopt`.
struct Region final {
std::vector<Rectangle> rectangles;
std::vector<std::vector<IntPair>> polygons;
std::vector<Polygon> polygons;
};

/// A dib as something a browser reads. A metafile stores a dib *with* its
Expand Down Expand Up @@ -425,8 +441,11 @@ std::string read_string_with_encoding(std::istream &in, TextEncoding encoding);
VersionLength read_version_length(std::istream &in);
IntPair read_int_pair(std::istream &in);
Rectangle read_rectangle(std::istream &in);
std::vector<IntPair> read_polygon(std::istream &in);
std::vector<std::vector<IntPair>> read_poly_polygon(std::istream &in);
Polygon read_polygon(std::istream &in);
/// `Polygon::Read`: the points again, and the flags behind them - what a
/// polygon carrying curves is written as.
Polygon read_flagged_polygon(std::istream &in);
std::vector<Polygon> read_poly_polygon(std::istream &in);

Header read_header(std::istream &in);
ActionHeader read_action_header(std::istream &in);
Expand Down
Loading
Loading