Icon-O-Matic: replace SVG parser with nanosvg
The parser was based on an old example from agg. NanoSVG is originally based on the same code, but has lots of bugfixes. So it makes sense to use it. Nanosvg revision 25241c5a8f8451d41ab1b02ab2d865b01600d949 Fixes #5955, #8586, #13021. Change-Id: I38ff9aa4e1d403c41979ebe42f7b45d4500a870c Reviewed-on: https://review.haiku-os.org/c/haiku/+/2661 Reviewed-by: waddlesplash <[email protected]>
This commit is contained in:
committed by
waddlesplash
parent
c419919252
commit
2a3b385efb
@@ -233,11 +233,8 @@ Application Icon-O-Matic :
|
||||
|
||||
# import_export/svg
|
||||
DocumentBuilder.cpp
|
||||
PathTokenizer.cpp
|
||||
SVGExporter.cpp
|
||||
SVGGradients.cpp
|
||||
SVGImporter.cpp
|
||||
SVGParser.cpp
|
||||
|
||||
# shape
|
||||
PathManipulator.cpp
|
||||
|
||||
@@ -6,21 +6,8 @@
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.2
|
||||
// Copyright (C) 2002-2004 Maxim Shemanarev (http://www.antigrain.com)
|
||||
//
|
||||
// Permission to copy, use, modify, sell and distribute this software
|
||||
// is granted provided this copyright notice appears in all copies.
|
||||
// This software is provided "as is" without express or implied
|
||||
// warranty, and with no claim as to its suitability for any purpose.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
// Contact: [email protected]
|
||||
// [email protected]
|
||||
// http://www.antigrain.com
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#define NANOSVG_IMPLEMENTATION
|
||||
#include "DocumentBuilder.h"
|
||||
|
||||
#include <new>
|
||||
@@ -28,8 +15,6 @@
|
||||
|
||||
#include <Bitmap.h>
|
||||
|
||||
#include <agg_bounding_rect.h>
|
||||
|
||||
#include "AutoDeleter.h"
|
||||
#include "GradientTransformable.h"
|
||||
#include "Icon.h"
|
||||
@@ -39,167 +24,25 @@
|
||||
#include "StrokeTransformer.h"
|
||||
#include "Style.h"
|
||||
#include "StyleContainer.h"
|
||||
#include "SVGGradients.h"
|
||||
#include "SVGImporter.h"
|
||||
#include "VectorPath.h"
|
||||
|
||||
#include <agg_math_stroke.h>
|
||||
#include <agg_trans_affine.h>
|
||||
|
||||
using std::nothrow;
|
||||
|
||||
namespace agg {
|
||||
namespace svg {
|
||||
|
||||
// constructor
|
||||
DocumentBuilder::DocumentBuilder()
|
||||
: fGradients(20),
|
||||
fCurrentGradient(NULL),
|
||||
fWidth(0),
|
||||
DocumentBuilder::DocumentBuilder(NSVGimage* source)
|
||||
: fWidth(0),
|
||||
fHeight(0),
|
||||
fViewBox(0.0, 0.0, -1.0, -1.0),
|
||||
fTitle("")
|
||||
fTitle(""),
|
||||
fSource(source)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// remove_all
|
||||
void
|
||||
DocumentBuilder::remove_all()
|
||||
{
|
||||
fPathStorage.remove_all();
|
||||
fAttributesStorage.remove_all();
|
||||
fAttributesStack.remove_all();
|
||||
fTransform.reset();
|
||||
}
|
||||
|
||||
// begin_path
|
||||
void
|
||||
DocumentBuilder::begin_path()
|
||||
{
|
||||
push_attr();
|
||||
unsigned idx = fPathStorage.start_new_path();
|
||||
fAttributesStorage.add(path_attributes(cur_attr(), idx));
|
||||
}
|
||||
|
||||
// end_path
|
||||
void
|
||||
DocumentBuilder::end_path()
|
||||
{
|
||||
if (fAttributesStorage.size() == 0) {
|
||||
throw exception("end_path: The path was not begun");
|
||||
}
|
||||
path_attributes attr = cur_attr();
|
||||
unsigned idx = fAttributesStorage[fAttributesStorage.size() - 1].index;
|
||||
attr.index = idx;
|
||||
fAttributesStorage[fAttributesStorage.size() - 1] = attr;
|
||||
pop_attr();
|
||||
}
|
||||
|
||||
// move_to
|
||||
void
|
||||
DocumentBuilder::move_to(double x, double y, bool rel) // M, m
|
||||
{
|
||||
if (rel)
|
||||
fPathStorage.move_rel(x, y);
|
||||
else
|
||||
fPathStorage.move_to(x, y);
|
||||
}
|
||||
|
||||
// line_to
|
||||
void
|
||||
DocumentBuilder::line_to(double x, double y, bool rel) // L, l
|
||||
{
|
||||
if (rel)
|
||||
fPathStorage.line_rel(x, y);
|
||||
else
|
||||
fPathStorage.line_to(x, y);
|
||||
}
|
||||
|
||||
// hline_to
|
||||
void
|
||||
DocumentBuilder::hline_to(double x, bool rel) // H, h
|
||||
{
|
||||
if (rel)
|
||||
fPathStorage.hline_rel(x);
|
||||
else
|
||||
fPathStorage.hline_to(x);
|
||||
}
|
||||
|
||||
// vline_to
|
||||
void
|
||||
DocumentBuilder::vline_to(double y, bool rel) // V, v
|
||||
{
|
||||
if (rel)
|
||||
fPathStorage.vline_rel(y);
|
||||
else
|
||||
fPathStorage.vline_to(y);
|
||||
}
|
||||
|
||||
// curve3
|
||||
void
|
||||
DocumentBuilder::curve3(double x1, double y1, // Q, q
|
||||
double x, double y, bool rel)
|
||||
{
|
||||
if (rel)
|
||||
fPathStorage.curve3_rel(x1, y1, x, y);
|
||||
else
|
||||
fPathStorage.curve3(x1, y1, x, y);
|
||||
}
|
||||
|
||||
// curve3
|
||||
void
|
||||
DocumentBuilder::curve3(double x, double y, bool rel) // T, t
|
||||
{
|
||||
if (rel)
|
||||
fPathStorage.curve3_rel(x, y);
|
||||
else
|
||||
fPathStorage.curve3(x, y);
|
||||
}
|
||||
|
||||
// curve4
|
||||
void
|
||||
DocumentBuilder::curve4(double x1, double y1, // C, c
|
||||
double x2, double y2,
|
||||
double x, double y, bool rel)
|
||||
{
|
||||
if (rel) {
|
||||
fPathStorage.curve4_rel(x1, y1, x2, y2, x, y);
|
||||
} else {
|
||||
fPathStorage.curve4(x1, y1, x2, y2, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
// curve4
|
||||
void
|
||||
DocumentBuilder::curve4(double x2, double y2, // S, s
|
||||
double x, double y, bool rel)
|
||||
{
|
||||
if (rel) {
|
||||
fPathStorage.curve4_rel(x2, y2, x, y);
|
||||
} else {
|
||||
fPathStorage.curve4(x2, y2, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
// elliptical_arc
|
||||
void
|
||||
DocumentBuilder::elliptical_arc(double rx, double ry, double angle,
|
||||
bool large_arc_flag, bool sweep_flag,
|
||||
double x, double y, bool rel)
|
||||
{
|
||||
angle = angle / 180.0 * pi;
|
||||
if (rel) {
|
||||
fPathStorage.arc_rel(rx, ry, angle, large_arc_flag, sweep_flag, x, y);
|
||||
} else {
|
||||
fPathStorage.arc_to(rx, ry, angle, large_arc_flag, sweep_flag, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
// close_subpath
|
||||
void
|
||||
DocumentBuilder::close_subpath()
|
||||
{
|
||||
fPathStorage.end_poly(path_flags_close);
|
||||
}
|
||||
|
||||
// SetTitle
|
||||
void
|
||||
DocumentBuilder::SetTitle(const char* title)
|
||||
@@ -216,244 +59,6 @@ DocumentBuilder::SetDimensions(uint32 width, uint32 height, BRect viewBox)
|
||||
fViewBox = viewBox;
|
||||
}
|
||||
|
||||
// cur_attr
|
||||
path_attributes&
|
||||
DocumentBuilder::cur_attr()
|
||||
{
|
||||
if (fAttributesStack.size() == 0) {
|
||||
throw exception("cur_attr: Attribute stack is empty");
|
||||
}
|
||||
return fAttributesStack[fAttributesStack.size() - 1];
|
||||
}
|
||||
|
||||
// push_attr
|
||||
void
|
||||
DocumentBuilder::push_attr()
|
||||
{
|
||||
//printf("DocumentBuilder::push_attr() (size: %d)\n", fAttributesStack.size());
|
||||
fAttributesStack.add(fAttributesStack.size() ? fAttributesStack[fAttributesStack.size() - 1]
|
||||
: path_attributes());
|
||||
}
|
||||
|
||||
// pop_attr
|
||||
void
|
||||
DocumentBuilder::pop_attr()
|
||||
{
|
||||
//printf("DocumentBuilder::pop_attr() (size: %d)\n", fAttributesStack.size());
|
||||
if (fAttributesStack.size() == 0) {
|
||||
throw exception("pop_attr: Attribute stack is empty");
|
||||
}
|
||||
fAttributesStack.remove_last();
|
||||
}
|
||||
|
||||
// fill
|
||||
void
|
||||
DocumentBuilder::fill(const rgba8& f)
|
||||
{
|
||||
path_attributes& attr = cur_attr();
|
||||
attr.fill_color = f;
|
||||
attr.fill_flag = true;
|
||||
}
|
||||
|
||||
// stroke
|
||||
void
|
||||
DocumentBuilder::stroke(const rgba8& s)
|
||||
{
|
||||
path_attributes& attr = cur_attr();
|
||||
attr.stroke_color = s;
|
||||
attr.stroke_flag = true;
|
||||
}
|
||||
|
||||
// even_odd
|
||||
void
|
||||
DocumentBuilder::even_odd(bool flag)
|
||||
{
|
||||
cur_attr().even_odd_flag = flag;
|
||||
}
|
||||
|
||||
// stroke_width
|
||||
void
|
||||
DocumentBuilder::stroke_width(double w)
|
||||
{
|
||||
path_attributes& attr = cur_attr();
|
||||
attr.stroke_width = w;
|
||||
attr.stroke_flag = true;
|
||||
}
|
||||
|
||||
// fill_none
|
||||
void
|
||||
DocumentBuilder::fill_none()
|
||||
{
|
||||
cur_attr().fill_flag = false;
|
||||
}
|
||||
|
||||
// fill_url
|
||||
void
|
||||
DocumentBuilder::fill_url(const char* url)
|
||||
{
|
||||
sprintf(cur_attr().fill_url, "%s", url);
|
||||
}
|
||||
|
||||
// stroke_none
|
||||
void
|
||||
DocumentBuilder::stroke_none()
|
||||
{
|
||||
cur_attr().stroke_flag = false;
|
||||
}
|
||||
|
||||
// stroke_url
|
||||
void
|
||||
DocumentBuilder::stroke_url(const char* url)
|
||||
{
|
||||
sprintf(cur_attr().stroke_url, "%s", url);
|
||||
}
|
||||
|
||||
// opacity
|
||||
void
|
||||
DocumentBuilder::opacity(double op)
|
||||
{
|
||||
cur_attr().opacity *= op;
|
||||
//printf("opacity: %.1f\n", cur_attr().opacity);
|
||||
}
|
||||
|
||||
// fill_opacity
|
||||
void
|
||||
DocumentBuilder::fill_opacity(double op)
|
||||
{
|
||||
cur_attr().fill_color.opacity(op);
|
||||
// cur_attr().opacity *= op;
|
||||
}
|
||||
|
||||
// stroke_opacity
|
||||
void
|
||||
DocumentBuilder::stroke_opacity(double op)
|
||||
{
|
||||
cur_attr().stroke_color.opacity(op);
|
||||
// cur_attr().opacity *= op;
|
||||
}
|
||||
|
||||
// line_join
|
||||
void
|
||||
DocumentBuilder::line_join(line_join_e join)
|
||||
{
|
||||
cur_attr().line_join = join;
|
||||
}
|
||||
|
||||
// line_cap
|
||||
void
|
||||
DocumentBuilder::line_cap(line_cap_e cap)
|
||||
{
|
||||
cur_attr().line_cap = cap;
|
||||
}
|
||||
|
||||
// miter_limit
|
||||
void
|
||||
DocumentBuilder::miter_limit(double ml)
|
||||
{
|
||||
cur_attr().miter_limit = ml;
|
||||
}
|
||||
|
||||
// transform
|
||||
trans_affine&
|
||||
DocumentBuilder::transform()
|
||||
{
|
||||
return cur_attr().transform;
|
||||
}
|
||||
|
||||
// parse_path
|
||||
void
|
||||
DocumentBuilder::parse_path(PathTokenizer& tok)
|
||||
{
|
||||
char lastCmd = 0;
|
||||
while(tok.next()) {
|
||||
double arg[10];
|
||||
char cmd = tok.last_command();
|
||||
unsigned i;
|
||||
switch(cmd) {
|
||||
case 'M': case 'm':
|
||||
arg[0] = tok.last_number();
|
||||
arg[1] = tok.next(cmd);
|
||||
if (lastCmd != cmd)
|
||||
move_to(arg[0], arg[1], cmd == 'm');
|
||||
else
|
||||
line_to(arg[0], arg[1], lastCmd == 'm');
|
||||
break;
|
||||
|
||||
case 'L': case 'l':
|
||||
arg[0] = tok.last_number();
|
||||
arg[1] = tok.next(cmd);
|
||||
line_to(arg[0], arg[1], cmd == 'l');
|
||||
break;
|
||||
|
||||
case 'V': case 'v':
|
||||
vline_to(tok.last_number(), cmd == 'v');
|
||||
break;
|
||||
|
||||
case 'H': case 'h':
|
||||
hline_to(tok.last_number(), cmd == 'h');
|
||||
break;
|
||||
|
||||
case 'Q': case 'q':
|
||||
arg[0] = tok.last_number();
|
||||
for(i = 1; i < 4; i++) {
|
||||
arg[i] = tok.next(cmd);
|
||||
}
|
||||
curve3(arg[0], arg[1], arg[2], arg[3], cmd == 'q');
|
||||
break;
|
||||
|
||||
case 'T': case 't':
|
||||
arg[0] = tok.last_number();
|
||||
arg[1] = tok.next(cmd);
|
||||
curve3(arg[0], arg[1], cmd == 't');
|
||||
break;
|
||||
|
||||
case 'C': case 'c':
|
||||
arg[0] = tok.last_number();
|
||||
for(i = 1; i < 6; i++) {
|
||||
arg[i] = tok.next(cmd);
|
||||
}
|
||||
curve4(arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], cmd == 'c');
|
||||
break;
|
||||
|
||||
case 'S': case 's':
|
||||
arg[0] = tok.last_number();
|
||||
for(i = 1; i < 4; i++) {
|
||||
arg[i] = tok.next(cmd);
|
||||
}
|
||||
curve4(arg[0], arg[1], arg[2], arg[3], cmd == 's');
|
||||
break;
|
||||
|
||||
case 'A': case 'a': {
|
||||
arg[0] = tok.last_number();
|
||||
for(i = 1; i < 3; i++) {
|
||||
arg[i] = tok.next(cmd);
|
||||
}
|
||||
bool large_arc_flag = (bool)tok.next(cmd);
|
||||
bool sweep_flag = (bool)tok.next(cmd);
|
||||
for(i = 3; i < 5; i++) {
|
||||
arg[i] = tok.next(cmd);
|
||||
}
|
||||
elliptical_arc(arg[0], arg[1], arg[2],
|
||||
large_arc_flag, sweep_flag,
|
||||
arg[3], arg[4], cmd == 'a');
|
||||
break;
|
||||
}
|
||||
|
||||
case 'Z': case 'z':
|
||||
close_subpath();
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
char buf[100];
|
||||
sprintf(buf, "parse_path: Invalid path command '%c'", cmd);
|
||||
throw exception(buf);
|
||||
}
|
||||
}
|
||||
lastCmd = cmd;
|
||||
}
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// GetIcon
|
||||
@@ -461,22 +66,10 @@ status_t
|
||||
DocumentBuilder::GetIcon(Icon* icon, SVGImporter* importer,
|
||||
const char* fallbackName)
|
||||
{
|
||||
double xMin;
|
||||
double yMin;
|
||||
double xMax;
|
||||
double yMax;
|
||||
|
||||
int32 pathCount = fAttributesStorage.size();
|
||||
|
||||
agg::conv_transform<agg::path_storage> transformedPaths(
|
||||
fPathStorage, fTransform);
|
||||
agg::bounding_rect(transformedPaths, *this, 0, pathCount,
|
||||
&xMin, &yMin, &xMax, &yMax);
|
||||
|
||||
xMin = floor(xMin);
|
||||
yMin = floor(yMin);
|
||||
xMax = ceil(xMax);
|
||||
yMax = ceil(yMax);
|
||||
double xMin = 0;
|
||||
double yMin = 0;
|
||||
double xMax = ceil(fSource->width);
|
||||
double yMax = ceil(fSource->height);
|
||||
|
||||
BRect bounds;
|
||||
if (fViewBox.IsValid()) {
|
||||
@@ -497,7 +90,7 @@ printf("using bounding box: ");
|
||||
bounds.PrintToStream();
|
||||
}
|
||||
|
||||
float size = min_c(bounds.Width() + 1.0, bounds.Height() + 1.0);
|
||||
float size = max_c(bounds.Width(), bounds.Height());
|
||||
double scale = 64.0 / size;
|
||||
printf("scale: %f\n", scale);
|
||||
|
||||
@@ -510,15 +103,11 @@ printf("scale: %f\n", scale);
|
||||
// else
|
||||
// icon->SetName(fallbackName);
|
||||
|
||||
for (int32 i = 0; i < pathCount; i++) {
|
||||
|
||||
path_attributes& attributes = fAttributesStorage[i];
|
||||
|
||||
if (attributes.fill_flag)
|
||||
_AddShape(attributes, false, transform, icon);
|
||||
|
||||
if (attributes.stroke_flag)
|
||||
_AddShape(attributes, true, transform, icon);
|
||||
for (NSVGshape* shape = fSource->shapes; shape != NULL; shape = shape->next) {
|
||||
if (shape->fill.type != NSVG_PAINT_NONE)
|
||||
_AddShape(shape, false, transform, icon);
|
||||
if (shape->stroke.type != NSVG_PAINT_NONE)
|
||||
_AddShape(shape, true, transform, icon);
|
||||
}
|
||||
|
||||
// clean up styles and paths (remove duplicates)
|
||||
@@ -543,218 +132,67 @@ printf("scale: %f\n", scale);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// StartGradient
|
||||
void
|
||||
DocumentBuilder::StartGradient(bool radial)
|
||||
{
|
||||
if (fCurrentGradient) {
|
||||
fprintf(stderr, "DocumentBuilder::StartGradient() - ERROR: "
|
||||
"previous gradient (%s) not finished!\n",
|
||||
fCurrentGradient->ID());
|
||||
}
|
||||
|
||||
if (radial)
|
||||
fCurrentGradient = new SVGRadialGradient();
|
||||
else
|
||||
fCurrentGradient = new SVGLinearGradient();
|
||||
|
||||
_AddGradient(fCurrentGradient);
|
||||
}
|
||||
|
||||
// EndGradient
|
||||
void
|
||||
DocumentBuilder::EndGradient()
|
||||
{
|
||||
if (fCurrentGradient) {
|
||||
// fCurrentGradient->PrintToStream();
|
||||
} else {
|
||||
fprintf(stderr, "DocumentBuilder::EndGradient() - "
|
||||
"ERROR: no gradient started!\n");
|
||||
}
|
||||
fCurrentGradient = NULL;
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// _AddGradient
|
||||
void
|
||||
DocumentBuilder::_AddGradient(SVGGradient* gradient)
|
||||
{
|
||||
if (gradient) {
|
||||
fGradients.AddItem((void*)gradient);
|
||||
}
|
||||
}
|
||||
|
||||
// _GradientAt
|
||||
SVGGradient*
|
||||
DocumentBuilder::_GradientAt(int32 index) const
|
||||
{
|
||||
return (SVGGradient*)fGradients.ItemAt(index);
|
||||
}
|
||||
|
||||
// _FindGradient
|
||||
SVGGradient*
|
||||
DocumentBuilder::_FindGradient(const char* name) const
|
||||
{
|
||||
for (int32 i = 0; SVGGradient* g = _GradientAt(i); i++) {
|
||||
if (strcmp(g->ID(), name) == 0)
|
||||
return g;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// AddVertexSource
|
||||
template<class VertexSource>
|
||||
status_t
|
||||
AddPathsFromVertexSource(Icon* icon, Shape* shape,
|
||||
VertexSource& source, int32 index)
|
||||
AddPathsFromVertexSource(Icon* icon, Shape* shape, NSVGshape* svgShape)
|
||||
{
|
||||
//printf("AddPathsFromVertexSource(pathID = %ld)\n", index);
|
||||
|
||||
// start with the first path
|
||||
VectorPath* path = new (nothrow) VectorPath();
|
||||
if (!path || !icon->Paths()->AddPath(path)) {
|
||||
delete path;
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
|
||||
if (!shape->Paths()->AddPath(path))
|
||||
return B_NO_MEMORY;
|
||||
|
||||
source.rewind(index);
|
||||
double x1 = 0, y1 = 0;
|
||||
unsigned cmd = source.vertex(&x1, &y1);
|
||||
bool keepGoing = true;
|
||||
int32 subPath = 0;
|
||||
while (keepGoing) {
|
||||
if (agg::is_next_poly(cmd)) {
|
||||
//printf("next polygon\n");
|
||||
if (agg::is_end_poly(cmd)) {
|
||||
//printf(" end polygon\n");
|
||||
path->SetClosed(true);
|
||||
subPath++;
|
||||
} else {
|
||||
//printf(" not end polygon\n");
|
||||
}
|
||||
|
||||
if (agg::is_stop(cmd)) {
|
||||
//printf(" stop = true\n");
|
||||
keepGoing = false;
|
||||
} else {
|
||||
if (subPath > 0) {
|
||||
//printf(" new subpath\n");
|
||||
path->CleanUp();
|
||||
if (path->CountPoints() == 0) {
|
||||
//printf(" path with no points!\n");
|
||||
icon->Paths()->RemovePath(path);
|
||||
shape->Paths()->RemovePath(path);
|
||||
path->ReleaseReference();
|
||||
}
|
||||
path = new (nothrow) VectorPath();
|
||||
if (!path || !icon->Paths()->AddPath(path)) {
|
||||
delete path;
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
if (!shape->Paths()->AddPath(path))
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
}
|
||||
for (NSVGpath* svgPath = svgShape->paths; svgPath != NULL;
|
||||
svgPath = svgPath->next) {
|
||||
VectorPath* path = new (nothrow) VectorPath();
|
||||
if (!path || !icon->Paths()->AddPath(path)) {
|
||||
delete path;
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
switch (cmd) {
|
||||
case agg::path_cmd_move_to:
|
||||
//printf("move to (%.2f, %.2f) (subPath: %ld)\n", x1, y1, subPath);
|
||||
if (path->CountPoints() > 0) {
|
||||
// cannot MoveTo on a path that has already points!
|
||||
path->CleanUp();
|
||||
path = new (nothrow) VectorPath();
|
||||
if (!path || !icon->Paths()->AddPath(path)) {
|
||||
delete path;
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
if (!shape->Paths()->AddPath(path))
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
if (!path->AddPoint(BPoint(x1, y1)))
|
||||
return B_NO_MEMORY;
|
||||
path->SetInOutConnected(path->CountPoints() - 1, false);
|
||||
break;
|
||||
|
||||
case agg::path_cmd_line_to:
|
||||
//printf("line to (%.2f, %.2f) (subPath: %ld)\n", x1, y1, subPath);
|
||||
if (!path->AddPoint(BPoint(x1, y1)))
|
||||
return B_NO_MEMORY;
|
||||
path->SetInOutConnected(path->CountPoints() - 1, false);
|
||||
break;
|
||||
if (!shape->Paths()->AddPath(path))
|
||||
return B_NO_MEMORY;
|
||||
|
||||
case agg::path_cmd_curve3: {
|
||||
double x2 = 0, y2 = 0;
|
||||
cmd = source.vertex(&x2, &y2);
|
||||
//printf("curve3 (%.2f, %.2f)\n", x1, y1);
|
||||
//printf(" (%.2f, %.2f)\n", x2, y2);
|
||||
path->SetClosed(svgPath->closed);
|
||||
|
||||
// convert to curve4 for easier editing
|
||||
int32 start = path->CountPoints() - 1;
|
||||
BPoint from;
|
||||
path->GetPointAt(start, from);
|
||||
int pointCount = svgPath->npts;
|
||||
float* points = svgPath->pts;
|
||||
|
||||
double cx2 = (1.0/3.0) * from.x + (2.0/3.0) * x1;
|
||||
double cy2 = (1.0/3.0) * from.y + (2.0/3.0) * y1;
|
||||
double cx3 = (2.0/3.0) * x1 + (1.0/3.0) * x2;
|
||||
double cy3 = (2.0/3.0) * y1 + (1.0/3.0) * y2;
|
||||
// First entry in the points list is always a "move" to the path
|
||||
// starting point
|
||||
if (!path->AddPoint(BPoint(points[0], points[1])))
|
||||
return B_NO_MEMORY;
|
||||
path->SetInOutConnected(path->CountPoints() - 1, false);
|
||||
|
||||
path->SetPointOut(start, BPoint(cx2, cy2));
|
||||
pointCount--;
|
||||
points += 2;
|
||||
|
||||
if (!path->AddPoint(BPoint(x2, y2)))
|
||||
return B_NO_MEMORY;
|
||||
while (pointCount > 0) {
|
||||
BPoint vector1(points[0], points[1]);
|
||||
BPoint vector2(points[2], points[3]);
|
||||
BPoint endPoint(points[4], points[5]);
|
||||
|
||||
int32 end = path->CountPoints() - 1;
|
||||
path->SetInOutConnected(end, false);
|
||||
path->SetPointIn(end, BPoint(cx3, cy3));
|
||||
break;
|
||||
}
|
||||
if (!path->AddPoint(endPoint))
|
||||
return B_NO_MEMORY;
|
||||
|
||||
case agg::path_cmd_curve4: {
|
||||
double x2 = 0, y2 = 0;
|
||||
double x3 = 0, y3 = 0;
|
||||
cmd = source.vertex(&x2, &y2);
|
||||
cmd = source.vertex(&x3, &y3);
|
||||
int32 start = path->CountPoints() - 2;
|
||||
int32 end = path->CountPoints() - 1;
|
||||
|
||||
if (!path->AddPoint(BPoint(x3, y3)))
|
||||
return B_NO_MEMORY;
|
||||
path->SetInOutConnected(end, false);
|
||||
path->SetPointOut(start, vector1);
|
||||
path->SetPointIn(end, vector2);
|
||||
|
||||
int32 start = path->CountPoints() - 2;
|
||||
int32 end = path->CountPoints() - 1;
|
||||
|
||||
//printf("curve4 [%ld] (%.2f, %.2f) -> [%ld] (%.2f, %.2f) -> (%.2f, %.2f)\n", start, x1, y1, end, x2, y2, x3, y3);
|
||||
|
||||
path->SetInOutConnected(end, false);
|
||||
path->SetPointOut(start, BPoint(x1, y1));
|
||||
path->SetPointIn(end, BPoint(x2, y2));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
//printf("unkown command\n");
|
||||
break;
|
||||
pointCount -= 3;
|
||||
points += 6;
|
||||
}
|
||||
cmd = source.vertex(&x1, &y1);
|
||||
}
|
||||
//path->PrintToStream();
|
||||
path->CleanUp();
|
||||
if (path->CountPoints() == 0) {
|
||||
//printf("path with no points!\n");
|
||||
icon->Paths()->RemovePath(path);
|
||||
shape->Paths()->RemovePath(path);
|
||||
path->ReleaseReference();
|
||||
}
|
||||
|
||||
// FIXME handle closed vs open paths
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// _AddShape
|
||||
status_t
|
||||
DocumentBuilder::_AddShape(path_attributes& attributes, bool outline,
|
||||
DocumentBuilder::_AddShape(NSVGshape* svgShape, bool outline,
|
||||
const Transformable& transform, Icon* icon)
|
||||
{
|
||||
Shape* shape = new (nothrow) Shape(NULL);
|
||||
@@ -763,20 +201,43 @@ DocumentBuilder::_AddShape(path_attributes& attributes, bool outline,
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
|
||||
if (AddPathsFromVertexSource(icon, shape, fPathStorage, attributes.index) < B_OK)
|
||||
if (AddPathsFromVertexSource(icon, shape, svgShape) < B_OK)
|
||||
printf("failed to convert from vertex source\n");
|
||||
|
||||
shape->multiply(attributes.transform);
|
||||
shape->SetName(svgShape->id);
|
||||
shape->Multiply(transform);
|
||||
|
||||
StrokeTransformer* stroke = NULL;
|
||||
NSVGpaint* paint = NULL;
|
||||
if (outline) {
|
||||
stroke = new (nothrow) StrokeTransformer(shape->VertexSource());
|
||||
paint = &svgShape->stroke;
|
||||
|
||||
if (stroke) {
|
||||
stroke->width(attributes.stroke_width);
|
||||
stroke->line_cap(attributes.line_cap);
|
||||
stroke->line_join(attributes.line_join);
|
||||
stroke->width(svgShape->strokeWidth);
|
||||
switch(svgShape->strokeLineCap) {
|
||||
case NSVG_CAP_BUTT:
|
||||
stroke->line_cap(agg::butt_cap);
|
||||
break;
|
||||
case NSVG_CAP_ROUND:
|
||||
stroke->line_cap(agg::round_cap);
|
||||
break;
|
||||
case NSVG_CAP_SQUARE:
|
||||
stroke->line_cap(agg::square_cap);
|
||||
break;
|
||||
}
|
||||
|
||||
switch(svgShape->strokeLineJoin) {
|
||||
case NSVG_JOIN_MITER:
|
||||
stroke->line_join(agg::miter_join);
|
||||
break;
|
||||
case NSVG_JOIN_ROUND:
|
||||
stroke->line_join(agg::round_join);
|
||||
break;
|
||||
case NSVG_JOIN_BEVEL:
|
||||
stroke->line_join(agg::bevel_join);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!shape->AddTransformer(stroke)) {
|
||||
@@ -784,45 +245,83 @@ DocumentBuilder::_AddShape(path_attributes& attributes, bool outline,
|
||||
stroke = NULL;
|
||||
}
|
||||
} else {
|
||||
// if (attributes.even_odd_flag)
|
||||
// shape->SetFillingRule(FILL_MODE_EVEN_ODD);
|
||||
// else
|
||||
// shape->SetFillingRule(FILL_MODE_NON_ZERO);
|
||||
paint = &svgShape->fill;
|
||||
#if 0 // FIXME filling rule are missing from Shape class
|
||||
if (svgShape->fillRule == NSVG_FILLRULE_EVENODD)
|
||||
shape->SetFillingRule(FILL_MODE_EVEN_ODD);
|
||||
else
|
||||
shape->SetFillingRule(FILL_MODE_NON_ZERO);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
Gradient* gradient = NULL;
|
||||
SVGGradient* g = NULL;
|
||||
const char* url = outline ? attributes.stroke_url : attributes.fill_url;
|
||||
if (url[0] != 0) {
|
||||
g = _FindGradient(url);
|
||||
if (g != NULL)
|
||||
gradient = g->GetGradient(shape->Bounds());
|
||||
}
|
||||
|
||||
ObjectDeleter<Gradient> gradientDeleter(gradient);
|
||||
|
||||
Gradient gradient(true);
|
||||
rgb_color color;
|
||||
|
||||
BGradient::ColorStop* step;
|
||||
if (gradient && (step = gradient->ColorAt(0))) {
|
||||
color.red = step->color.red;
|
||||
color.green = step->color.green;
|
||||
color.blue = step->color.blue;
|
||||
} else {
|
||||
if (outline) {
|
||||
color.red = attributes.stroke_color.r;
|
||||
color.green = attributes.stroke_color.g;
|
||||
color.blue = attributes.stroke_color.b;
|
||||
color.alpha = (uint8)(attributes.stroke_color.a * attributes.opacity);
|
||||
} else {
|
||||
color.red = attributes.fill_color.r;
|
||||
color.green = attributes.fill_color.g;
|
||||
color.blue = attributes.fill_color.b;
|
||||
color.alpha = (uint8)(attributes.fill_color.a * attributes.opacity);
|
||||
switch(paint->type) {
|
||||
case NSVG_PAINT_COLOR:
|
||||
color.red = paint->color & 0xFF;
|
||||
color.green = (paint->color >> 8) & 0xFF;
|
||||
color.blue = (paint->color >> 16) & 0xFF;
|
||||
color.alpha = (paint->color >> 24) & 0xFF;
|
||||
break;
|
||||
case NSVG_PAINT_LINEAR_GRADIENT:
|
||||
{
|
||||
gradient.SetType(GRADIENT_LINEAR);
|
||||
// The base gradient axis in Icon-O-Matic is a horizontal line from
|
||||
// (-64, 0) to (64, 0). The base gradient axis used by nanosvg is
|
||||
// a vertical line from (0, 0) to (0, 1). This initial transform
|
||||
// converts from one space to the other.
|
||||
agg::trans_affine baseTransform(0, 1.0/128.0, -1.0/128.0, 0,
|
||||
-0.5, 0.5);
|
||||
gradient.multiply(baseTransform);
|
||||
break;
|
||||
}
|
||||
case NSVG_PAINT_RADIAL_GRADIENT:
|
||||
{
|
||||
gradient.SetType(GRADIENT_CIRCULAR);
|
||||
agg::trans_affine baseTransform(0, 1.0/64.0, -1.0/64.0, 0,
|
||||
0, 0);
|
||||
gradient.multiply(baseTransform);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (paint->type != NSVG_PAINT_COLOR) {
|
||||
gradient.SetInterpolation(INTERPOLATION_LINEAR);
|
||||
agg::trans_affine gradientTransform(
|
||||
paint->gradient->xform[0], paint->gradient->xform[1],
|
||||
paint->gradient->xform[2], paint->gradient->xform[3],
|
||||
paint->gradient->xform[4], paint->gradient->xform[5]
|
||||
);
|
||||
|
||||
// The transform from nanosvg converts a screen space coordinate into
|
||||
// a gradient offset. It is the inverse of what we need at this stage,
|
||||
// so we just invert it and multiply our base transform with it.
|
||||
gradient.multiply_inv(gradientTransform);
|
||||
|
||||
// Finally, scale the gradient according to the global scaling to fit
|
||||
// the 64x64 box we work in.
|
||||
gradient.Multiply(*shape);
|
||||
|
||||
for (int i = 0; i < paint->gradient->nstops; i++) {
|
||||
rgb_color stopColor;
|
||||
stopColor.red = paint->gradient->stops[i].color & 0xFF;
|
||||
stopColor.green = (paint->gradient->stops[i].color >> 8) & 0xFF;
|
||||
stopColor.blue = (paint->gradient->stops[i].color >> 16) & 0xFF;
|
||||
stopColor.alpha = (paint->gradient->stops[i].color >> 24) & 0xFF;
|
||||
gradient.AddColor(stopColor, paint->gradient->stops[i].offset);
|
||||
}
|
||||
|
||||
BGradient::ColorStop* step = gradient.ColorAt(0);
|
||||
if (step) {
|
||||
color.red = step->color.red;
|
||||
color.green = step->color.green;
|
||||
color.blue = step->color.blue;
|
||||
color.alpha = step->color.alpha;
|
||||
}
|
||||
}
|
||||
|
||||
color.alpha = (uint8)(color.alpha * svgShape->opacity);
|
||||
|
||||
Style* style = new (nothrow) Style(color);
|
||||
if (!style || !icon->Styles()->AddStyle(style)) {
|
||||
delete style;
|
||||
@@ -831,31 +330,22 @@ DocumentBuilder::_AddShape(path_attributes& attributes, bool outline,
|
||||
|
||||
// NOTE: quick hack to freeze all transformations (only works because
|
||||
// paths and styles are not used by multiple shapes!!)
|
||||
// if (modifiers() & B_COMMAND_KEY) {
|
||||
int32 pathCount = shape->Paths()->CountPaths();
|
||||
for (int32 i = 0; i < pathCount; i++) {
|
||||
VectorPath* path = shape->Paths()->PathAtFast(i);
|
||||
path->ApplyTransform(*shape);
|
||||
}
|
||||
if (gradient)
|
||||
gradient->Multiply(*shape);
|
||||
|
||||
if (stroke)
|
||||
stroke->width(stroke->width() * shape->scale());
|
||||
|
||||
shape->Reset();
|
||||
// }
|
||||
|
||||
if (gradient) {
|
||||
style->SetGradient(gradient);
|
||||
style->SetName(g->ID());
|
||||
int32 pathCount = shape->Paths()->CountPaths();
|
||||
for (int32 i = 0; i < pathCount; i++) {
|
||||
VectorPath* path = shape->Paths()->PathAtFast(i);
|
||||
path->ApplyTransform(*shape);
|
||||
}
|
||||
|
||||
if (stroke)
|
||||
stroke->width(stroke->width() * shape->scale());
|
||||
|
||||
if (paint->type != NSVG_PAINT_COLOR)
|
||||
style->SetGradient(&gradient);
|
||||
|
||||
shape->Reset();
|
||||
|
||||
shape->SetStyle(style);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
} // namespace svg
|
||||
} // namespace agg
|
||||
|
||||
|
||||
@@ -6,41 +6,17 @@
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.2
|
||||
// Copyright (C) 2002-2004 Maxim Shemanarev (http://www.antigrain.com)
|
||||
//
|
||||
// Permission to copy, use, modify, sell and distribute this software
|
||||
// is granted provided this copyright notice appears in all copies.
|
||||
// This software is provided "as is" without express or implied
|
||||
// warranty, and with no claim as to its suitability for any purpose.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
// Contact: [email protected]
|
||||
// [email protected]
|
||||
// http://www.antigrain.com
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#ifndef DOCUMENT_BUILD_H
|
||||
#define DOCUMENT_BUILD_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <List.h>
|
||||
#include <Rect.h>
|
||||
#include <String.h>
|
||||
|
||||
#include <agg_array.h>
|
||||
#include <agg_color_rgba.h>
|
||||
#include <agg_conv_transform.h>
|
||||
#include <agg_conv_stroke.h>
|
||||
#include <agg_conv_contour.h>
|
||||
#include <agg_conv_curve.h>
|
||||
#include <agg_path_storage.h>
|
||||
#include <agg_rasterizer_scanline_aa.h>
|
||||
|
||||
#include "IconBuild.h"
|
||||
#include "PathTokenizer.h"
|
||||
#include "nanosvg.h"
|
||||
|
||||
|
||||
class SVGImporter;
|
||||
@@ -52,207 +28,33 @@ _END_ICON_NAMESPACE
|
||||
|
||||
_USING_ICON_NAMESPACE
|
||||
|
||||
namespace agg {
|
||||
namespace svg {
|
||||
|
||||
class SVGGradient;
|
||||
|
||||
// Basic path attributes
|
||||
struct path_attributes {
|
||||
|
||||
unsigned index;
|
||||
rgba8 fill_color;
|
||||
rgba8 stroke_color;
|
||||
double opacity;
|
||||
bool fill_flag;
|
||||
bool stroke_flag;
|
||||
bool even_odd_flag;
|
||||
line_join_e line_join;
|
||||
line_cap_e line_cap;
|
||||
double miter_limit;
|
||||
double stroke_width;
|
||||
trans_affine transform;
|
||||
|
||||
char stroke_url[64];
|
||||
char fill_url[64];
|
||||
|
||||
// Empty constructor
|
||||
path_attributes() :
|
||||
index (0),
|
||||
fill_color (rgba(0,0,0)),
|
||||
stroke_color (rgba(0,0,0)),
|
||||
opacity (1.0),
|
||||
fill_flag (true),
|
||||
stroke_flag (false),
|
||||
even_odd_flag (false),
|
||||
line_join (miter_join),
|
||||
line_cap (butt_cap),
|
||||
miter_limit (4.0),
|
||||
stroke_width (1.0),
|
||||
transform ()
|
||||
{
|
||||
stroke_url[0] = 0;
|
||||
fill_url[0] = 0;
|
||||
}
|
||||
|
||||
// Copy constructor
|
||||
path_attributes(const path_attributes& attr) :
|
||||
index (attr.index),
|
||||
fill_color (attr.fill_color),
|
||||
stroke_color (attr.stroke_color),
|
||||
opacity (attr.opacity),
|
||||
fill_flag (attr.fill_flag),
|
||||
stroke_flag (attr.stroke_flag),
|
||||
even_odd_flag (attr.even_odd_flag),
|
||||
line_join (attr.line_join),
|
||||
line_cap (attr.line_cap),
|
||||
miter_limit (attr.miter_limit),
|
||||
stroke_width (attr.stroke_width),
|
||||
transform (attr.transform)
|
||||
{
|
||||
sprintf(stroke_url, "%s", attr.stroke_url);
|
||||
sprintf(fill_url, "%s", attr.fill_url);
|
||||
}
|
||||
|
||||
// Copy constructor with new index value
|
||||
path_attributes(const path_attributes& attr, unsigned idx) :
|
||||
index (idx),
|
||||
fill_color (attr.fill_color),
|
||||
stroke_color (attr.stroke_color),
|
||||
fill_flag (attr.fill_flag),
|
||||
stroke_flag (attr.stroke_flag),
|
||||
even_odd_flag (attr.even_odd_flag),
|
||||
line_join (attr.line_join),
|
||||
line_cap (attr.line_cap),
|
||||
miter_limit (attr.miter_limit),
|
||||
stroke_width (attr.stroke_width),
|
||||
transform (attr.transform)
|
||||
{
|
||||
sprintf(stroke_url, "%s", attr.stroke_url);
|
||||
sprintf(fill_url, "%s", attr.fill_url);
|
||||
}
|
||||
};
|
||||
|
||||
class DocumentBuilder {
|
||||
public:
|
||||
|
||||
typedef pod_bvector<path_attributes> attr_storage;
|
||||
|
||||
DocumentBuilder();
|
||||
|
||||
void remove_all();
|
||||
|
||||
// Use these functions as follows:
|
||||
// begin_path() when the XML tag <path> comes ("start_element" handler)
|
||||
// parse_path() on "d=" tag attribute
|
||||
// end_path() when parsing of the entire tag is done.
|
||||
void begin_path();
|
||||
void parse_path(PathTokenizer& tok);
|
||||
void end_path();
|
||||
|
||||
// The following functions are essentially a "reflection" of
|
||||
// the respective SVG path commands.
|
||||
void move_to(double x, double y, bool rel = false); // M, m
|
||||
void line_to(double x, double y, bool rel = false); // L, l
|
||||
void hline_to(double x, bool rel = false); // H, h
|
||||
void vline_to(double y, bool rel = false); // V, v
|
||||
void curve3(double x1, double y1, // Q, q
|
||||
double x, double y, bool rel = false);
|
||||
void curve3(double x, double y, bool rel = false); // T, t
|
||||
void curve4(double x1, double y1, // C, c
|
||||
double x2, double y2,
|
||||
double x, double y, bool rel = false);
|
||||
void curve4(double x2, double y2, // S, s
|
||||
double x, double y, bool rel = false);
|
||||
void elliptical_arc(double rx, double ry,
|
||||
double angle,
|
||||
bool large_arc_flag,
|
||||
bool sweep_flag,
|
||||
double x, double y,
|
||||
bool rel = false); // A, a
|
||||
void close_subpath(); // Z, z
|
||||
|
||||
/* template<class VertexSource>
|
||||
void add_path(VertexSource& vs,
|
||||
unsigned path_id = 0,
|
||||
bool solid_path = true)
|
||||
{
|
||||
fPathStorage.add_path(vs, path_id, solid_path);
|
||||
}*/
|
||||
DocumentBuilder(NSVGimage* image);
|
||||
|
||||
void SetTitle(const char* title);
|
||||
void SetDimensions(uint32 width, uint32 height, BRect viewBox);
|
||||
|
||||
|
||||
// Call these functions on <g> tag (start_element, end_element respectively)
|
||||
void push_attr();
|
||||
void pop_attr();
|
||||
|
||||
// Attribute setting functions.
|
||||
void fill(const rgba8& f);
|
||||
void stroke(const rgba8& s);
|
||||
void even_odd(bool flag);
|
||||
void stroke_width(double w);
|
||||
void fill_none();
|
||||
void fill_url(const char* url);
|
||||
void stroke_none();
|
||||
void stroke_url(const char* url);
|
||||
void opacity(double op);
|
||||
void fill_opacity(double op);
|
||||
void stroke_opacity(double op);
|
||||
void line_join(line_join_e join);
|
||||
void line_cap(line_cap_e cap);
|
||||
void miter_limit(double ml);
|
||||
trans_affine& transform();
|
||||
|
||||
/* // Make all polygons CCW-oriented
|
||||
void arrange_orientations()
|
||||
{
|
||||
fPathStorage.arrange_orientations_all_paths(path_flags_ccw);
|
||||
}*/
|
||||
|
||||
unsigned operator [](unsigned idx)
|
||||
{
|
||||
fTransform = fAttributesStorage[idx].transform;
|
||||
return fAttributesStorage[idx].index;
|
||||
}
|
||||
|
||||
status_t GetIcon(Icon* icon,
|
||||
SVGImporter* importer,
|
||||
const char* fallbackName);
|
||||
|
||||
void StartGradient(bool radial = false);
|
||||
void EndGradient();
|
||||
SVGGradient* CurrentGradient() const
|
||||
{ return fCurrentGradient; }
|
||||
|
||||
private:
|
||||
void _AddGradient(SVGGradient* gradient);
|
||||
SVGGradient* _GradientAt(int32 index) const;
|
||||
SVGGradient* _FindGradient(const char* name) const;
|
||||
status_t _AddShape(path_attributes& attributes,
|
||||
status_t _AddShape(NSVGshape* svgShape,
|
||||
bool outline,
|
||||
const Transformable& transform,
|
||||
Icon* icon);
|
||||
|
||||
path_attributes& cur_attr();
|
||||
|
||||
path_storage fPathStorage;
|
||||
attr_storage fAttributesStorage;
|
||||
attr_storage fAttributesStack;
|
||||
|
||||
trans_affine fTransform;
|
||||
|
||||
BList fGradients;
|
||||
SVGGradient* fCurrentGradient;
|
||||
|
||||
uint32 fWidth;
|
||||
uint32 fHeight;
|
||||
BRect fViewBox;
|
||||
BString fTitle;
|
||||
|
||||
NSVGimage* fSource;
|
||||
};
|
||||
|
||||
} // namespace svg
|
||||
} // namespace agg
|
||||
|
||||
#endif // DOCUMENT_BUILD_H
|
||||
|
||||
@@ -1,157 +0,0 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.2
|
||||
// Copyright (C) 2002-2004 Maxim Shemanarev (http://www.antigrain.com)
|
||||
//
|
||||
// Permission to copy, use, modify, sell and distribute this software
|
||||
// is granted provided this copyright notice appears in all copies.
|
||||
// This software is provided "as is" without express or implied
|
||||
// warranty, and with no claim as to its suitability for any purpose.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
// Contact: [email protected]
|
||||
// [email protected]
|
||||
// http://www.antigrain.com
|
||||
|
||||
#include "PathTokenizer.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
namespace agg {
|
||||
namespace svg {
|
||||
|
||||
// globals
|
||||
const char PathTokenizer::sCommands[] = "+-MmZzLlHhVvCcSsQqTtAaFfPp";
|
||||
const char PathTokenizer::sNumeric[] = ".Ee0123456789";
|
||||
const char PathTokenizer::sSeparators[] = " ,\t\n\r";
|
||||
|
||||
// constructor
|
||||
PathTokenizer::PathTokenizer()
|
||||
: fPath(0),
|
||||
fLastNumber(0.0),
|
||||
fLastCommand(0)
|
||||
{
|
||||
init_char_mask(fCommandsMask, sCommands);
|
||||
init_char_mask(fNumericMask, sNumeric);
|
||||
init_char_mask(fSeparatorsMask, sSeparators);
|
||||
}
|
||||
|
||||
// set_path_str
|
||||
void
|
||||
PathTokenizer::set_path_str(const char* str)
|
||||
{
|
||||
fPath = str;
|
||||
fLastCommand = 0;
|
||||
fLastNumber = 0.0;
|
||||
}
|
||||
|
||||
// next
|
||||
bool
|
||||
PathTokenizer::next()
|
||||
{
|
||||
if(fPath == 0) return false;
|
||||
|
||||
// Skip all white spaces and other garbage
|
||||
while (*fPath && !is_command(*fPath) && !isNumeric(*fPath)) {
|
||||
if (!is_separator(*fPath)) {
|
||||
char buf[100];
|
||||
sprintf(buf, "PathTokenizer::next : Invalid Character %c", *fPath);
|
||||
throw exception(buf);
|
||||
}
|
||||
fPath++;
|
||||
}
|
||||
|
||||
if (*fPath == 0) return false;
|
||||
|
||||
if (is_command(*fPath)) {
|
||||
// Check if the command is a numeric sign character
|
||||
if(*fPath == '-' || *fPath == '+')
|
||||
{
|
||||
return parse_number();
|
||||
}
|
||||
fLastCommand = *fPath++;
|
||||
while(*fPath && is_separator(*fPath)) fPath++;
|
||||
if(*fPath == 0) return true;
|
||||
}
|
||||
return parse_number();
|
||||
}
|
||||
|
||||
// next
|
||||
double
|
||||
PathTokenizer::next(char cmd)
|
||||
{
|
||||
if (!next()) throw exception("parse_path: Unexpected end of path");
|
||||
if (last_command() != cmd) {
|
||||
char buf[100];
|
||||
sprintf(buf, "parse_path: Command %c: bad or missing parameters", cmd);
|
||||
throw exception(buf);
|
||||
}
|
||||
return last_number();
|
||||
}
|
||||
|
||||
// init_char_mask
|
||||
void
|
||||
PathTokenizer::init_char_mask(char* mask, const char* char_set)
|
||||
{
|
||||
memset(mask, 0, 256/8);
|
||||
while (*char_set) {
|
||||
unsigned c = unsigned(*char_set++) & 0xFF;
|
||||
mask[c >> 3] |= 1 << (c & 7);
|
||||
}
|
||||
}
|
||||
|
||||
// contains
|
||||
inline bool
|
||||
PathTokenizer::contains(const char* mask, unsigned c) const
|
||||
{
|
||||
return (mask[(c >> 3) & (256 / 8 - 1)] & (1 << (c & 7))) != 0;
|
||||
}
|
||||
|
||||
// is_command
|
||||
inline bool
|
||||
PathTokenizer::is_command(unsigned c) const
|
||||
{
|
||||
return contains(fCommandsMask, c);
|
||||
}
|
||||
|
||||
// isNumeric
|
||||
inline bool
|
||||
PathTokenizer::isNumeric(unsigned c) const
|
||||
{
|
||||
return contains(fNumericMask, c);
|
||||
}
|
||||
|
||||
// is_separator
|
||||
inline bool
|
||||
PathTokenizer::is_separator(unsigned c) const
|
||||
{
|
||||
return contains(fSeparatorsMask, c);
|
||||
}
|
||||
|
||||
// parse_number
|
||||
bool
|
||||
PathTokenizer::parse_number()
|
||||
{
|
||||
char* end;
|
||||
fLastNumber = strtod(fPath, &end);
|
||||
fPath = end;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
} //namespace svg
|
||||
} //namespace agg
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.2
|
||||
// Copyright (C) 2002-2004 Maxim Shemanarev (http://www.antigrain.com)
|
||||
//
|
||||
// Permission to copy, use, modify, sell and distribute this software
|
||||
// is granted provided this copyright notice appears in all copies.
|
||||
// This software is provided "as is" without express or implied
|
||||
// warranty, and with no claim as to its suitability for any purpose.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
// Contact: [email protected]
|
||||
// [email protected]
|
||||
// http://www.antigrain.com
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#ifndef PATH_TOKENIZER_H
|
||||
#define PATH_TOKENIZER_H
|
||||
|
||||
#include "SVGException.h"
|
||||
|
||||
namespace agg {
|
||||
namespace svg {
|
||||
// SVG path tokenizer.
|
||||
// Example:
|
||||
//
|
||||
// agg::svg::PathTokenizer tok;
|
||||
//
|
||||
// tok.set_str("M-122.304 84.285L-122.304 84.285 122.203 86.179 ");
|
||||
// while(tok.next())
|
||||
// {
|
||||
// printf("command='%c' number=%f\n",
|
||||
// tok.last_command(),
|
||||
// tok.last_number());
|
||||
// }
|
||||
//
|
||||
// The tokenizer does all the routine job of parsing the SVG paths.
|
||||
// It doesn't recognize any graphical primitives, it even doesn't know
|
||||
// anything about pairs of coordinates (X,Y). The purpose of this class
|
||||
// is to tokenize the numeric values and commands. SVG paths can
|
||||
// have single numeric values for Horizontal or Vertical line_to commands
|
||||
// as well as more than two coordinates (4 or 6) for Bezier curves
|
||||
// depending on the semantics of the command.
|
||||
// The behaviour is as follows:
|
||||
//
|
||||
// Each call to next() returns true if there's new command or new numeric
|
||||
// value or false when the path ends. How to interpret the result
|
||||
// depends on the sematics of the command. For example, command "C"
|
||||
// (cubic Bezier curve) implies 6 floating point numbers preceded by this
|
||||
// command. If the command assumes no arguments (like z or Z) the
|
||||
// the last_number() values won't change, that is, last_number() always
|
||||
// returns the last recognized numeric value, so does last_command().
|
||||
|
||||
class PathTokenizer {
|
||||
public:
|
||||
PathTokenizer();
|
||||
|
||||
void set_path_str(const char* str);
|
||||
bool next();
|
||||
|
||||
double next(char cmd);
|
||||
|
||||
char last_command() const
|
||||
{ return fLastCommand; }
|
||||
double last_number() const
|
||||
{ return fLastNumber; }
|
||||
|
||||
|
||||
private:
|
||||
static void init_char_mask(char* mask,
|
||||
const char* char_set);
|
||||
|
||||
inline bool contains(const char* mask, unsigned c) const;
|
||||
inline bool is_command(unsigned c) const;
|
||||
inline bool isNumeric(unsigned c) const;
|
||||
inline bool is_separator(unsigned c) const;
|
||||
|
||||
bool parse_number();
|
||||
|
||||
char fSeparatorsMask[256 / 8];
|
||||
char fCommandsMask[256 / 8];
|
||||
char fNumericMask[256 / 8];
|
||||
|
||||
const char* fPath;
|
||||
double fLastNumber;
|
||||
char fLastCommand;
|
||||
|
||||
static const char sCommands[];
|
||||
static const char sNumeric[];
|
||||
static const char sSeparators[];
|
||||
};
|
||||
|
||||
|
||||
|
||||
} //namespace svg
|
||||
} //namespace agg
|
||||
|
||||
|
||||
#endif // PATH_TOKENIZER_H
|
||||
@@ -1,199 +0,0 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "GradientTransformable.h"
|
||||
|
||||
#include "SVGGradients.h"
|
||||
|
||||
namespace agg {
|
||||
namespace svg {
|
||||
|
||||
// constructor
|
||||
SVGGradient::SVGGradient()
|
||||
: BMessage(),
|
||||
fGradient(NULL),
|
||||
fID(""),
|
||||
fGradientUnits(UNSPECIFIED)
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
SVGGradient::~SVGGradient()
|
||||
{
|
||||
}
|
||||
|
||||
// SetID
|
||||
void
|
||||
SVGGradient::SetID(const char* id)
|
||||
{
|
||||
fID = id;
|
||||
}
|
||||
|
||||
// ID
|
||||
const char*
|
||||
SVGGradient::ID() const
|
||||
{
|
||||
return fID.String();
|
||||
}
|
||||
|
||||
// AddStop
|
||||
void
|
||||
SVGGradient::AddStop(float offset, rgba8 color)
|
||||
{
|
||||
if (!fGradient)
|
||||
fGradient = MakeGradient();
|
||||
|
||||
rgb_color c = { color.r, color.g, color.b, color.a };
|
||||
fGradient->AddColor(c, offset);
|
||||
}
|
||||
|
||||
// SetTransformation
|
||||
void
|
||||
SVGGradient::SetTransformation(const trans_affine& transform)
|
||||
{
|
||||
//printf("SVGGradient::SetTransformation()\n");
|
||||
if (!fGradient)
|
||||
fGradient = MakeGradient();
|
||||
|
||||
fGradient->multiply(transform);
|
||||
}
|
||||
|
||||
// GetGradient
|
||||
Gradient*
|
||||
SVGGradient::GetGradient(BRect objectBounds)
|
||||
{
|
||||
if (fGradient) {
|
||||
Gradient* gradient = new Gradient(*fGradient);
|
||||
|
||||
IdentifyGradientUnits();
|
||||
if (fGradientUnits == OBJECT_BOUNDING_BOX) {
|
||||
gradient->FitToBounds(objectBounds);
|
||||
}
|
||||
|
||||
return gradient;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// IdentifyGradientUnits
|
||||
void
|
||||
SVGGradient::IdentifyGradientUnits()
|
||||
{
|
||||
if (fGradientUnits == UNSPECIFIED) {
|
||||
const char* units;
|
||||
if (FindString("gradientUnits", &units) >= B_OK) {
|
||||
if (strcmp(units, "objectBoundingBox") == 0)
|
||||
fGradientUnits = OBJECT_BOUNDING_BOX;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// constructor
|
||||
SVGLinearGradient::SVGLinearGradient()
|
||||
: SVGGradient()
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
SVGLinearGradient::~SVGLinearGradient()
|
||||
{
|
||||
}
|
||||
|
||||
// MakeGradient
|
||||
Gradient*
|
||||
SVGLinearGradient::MakeGradient() const
|
||||
{
|
||||
//printf("SVGLinearGradient::MakeGradient()\n");
|
||||
//PrintToStream();
|
||||
|
||||
Gradient* gradient = new Gradient(true);
|
||||
gradient->SetType(GRADIENT_LINEAR);
|
||||
gradient->SetInterpolation(INTERPOLATION_LINEAR);
|
||||
// setup the gradient transform
|
||||
BPoint start(-64.0, -64.0);
|
||||
BPoint end(64.0, -64.0);
|
||||
BString coordinate;
|
||||
if (FindString("x1", &coordinate) >= B_OK)
|
||||
start.x = atof(coordinate.String());
|
||||
if (FindString("y1", &coordinate) >= B_OK)
|
||||
start.y = atof(coordinate.String());
|
||||
if (FindString("x2", &coordinate) >= B_OK)
|
||||
end.x = atof(coordinate.String());
|
||||
if (FindString("y2", &coordinate) >= B_OK)
|
||||
end.y = atof(coordinate.String());
|
||||
|
||||
// the transformed parallelogram
|
||||
double parl[6];
|
||||
parl[0] = start.x;
|
||||
parl[1] = start.y;
|
||||
parl[2] = end.x;
|
||||
parl[3] = end.y;
|
||||
parl[4] = end.x - (end.y - start.y);
|
||||
parl[5] = end.y + (end.x - start.x);
|
||||
|
||||
trans_affine transform(-64.0, -64.0, 64.0, 64.0, parl);
|
||||
gradient->multiply(transform);
|
||||
|
||||
return gradient;
|
||||
}
|
||||
|
||||
// constructor
|
||||
SVGRadialGradient::SVGRadialGradient()
|
||||
: SVGGradient()
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
SVGRadialGradient::~SVGRadialGradient()
|
||||
{
|
||||
}
|
||||
|
||||
// MakeGradient
|
||||
Gradient*
|
||||
SVGRadialGradient::MakeGradient() const
|
||||
{
|
||||
//printf("SVGRadialGradient::MakeGradient()\n");
|
||||
// TODO: handle userSpaceOnUse/objectBoundingBox
|
||||
Gradient* gradient = new Gradient(true);
|
||||
gradient->SetType(GRADIENT_CIRCULAR);
|
||||
gradient->SetInterpolation(INTERPOLATION_LINEAR);
|
||||
|
||||
double cx = 0.0;
|
||||
double cy = 0.0;
|
||||
double r = 100.0;
|
||||
|
||||
BString value;
|
||||
if (FindString("cx", &value) >= B_OK)
|
||||
cx = atof(value.String());
|
||||
if (FindString("cy", &value) >= B_OK)
|
||||
cy = atof(value.String());
|
||||
if (FindString("r", &value) >= B_OK)
|
||||
r = atof(value.String());
|
||||
|
||||
// the transformed parallelogram
|
||||
double parl[6];
|
||||
parl[0] = cx - r;
|
||||
parl[1] = cy - r;
|
||||
parl[2] = cx + r;
|
||||
parl[3] = cy - r;
|
||||
parl[4] = cx + r;
|
||||
parl[5] = cy + r;
|
||||
|
||||
trans_affine transform(-64.0, -64.0, 64.0, 64.0, parl);
|
||||
gradient->multiply(transform);
|
||||
|
||||
return gradient;
|
||||
}
|
||||
|
||||
} // namespace svg
|
||||
} // namespace agg
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
/*
|
||||
* Copyright 2006-2007, Haiku. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
#ifndef SVG_GRADIENTS_H
|
||||
#define SVG_GRADIENTS_H
|
||||
|
||||
|
||||
#include <agg_color_rgba.h>
|
||||
#include <agg_trans_affine.h>
|
||||
|
||||
#include <Message.h>
|
||||
#include <String.h>
|
||||
|
||||
#include "IconBuild.h"
|
||||
|
||||
|
||||
_BEGIN_ICON_NAMESPACE
|
||||
class Gradient;
|
||||
_END_ICON_NAMESPACE
|
||||
|
||||
namespace agg {
|
||||
namespace svg {
|
||||
|
||||
class SVGGradient : public BMessage {
|
||||
public:
|
||||
SVGGradient();
|
||||
virtual ~SVGGradient();
|
||||
|
||||
void SetID(const char* id);
|
||||
const char* ID() const;
|
||||
|
||||
virtual void AddStop(float offset, rgba8 color);
|
||||
void SetTransformation(const trans_affine& transform);
|
||||
|
||||
Gradient* GetGradient(BRect objectBounds);
|
||||
|
||||
protected:
|
||||
virtual Gradient* MakeGradient() const = 0;
|
||||
void IdentifyGradientUnits();
|
||||
|
||||
private:
|
||||
|
||||
enum {
|
||||
UNSPECIFIED = 0,
|
||||
USER_SPACE_ON_USE,
|
||||
OBJECT_BOUNDING_BOX,
|
||||
};
|
||||
|
||||
Gradient* fGradient;
|
||||
BString fID;
|
||||
uint32 fGradientUnits;
|
||||
};
|
||||
|
||||
class SVGLinearGradient : public SVGGradient {
|
||||
public:
|
||||
SVGLinearGradient();
|
||||
virtual ~SVGLinearGradient();
|
||||
|
||||
protected:
|
||||
virtual Gradient* MakeGradient() const;
|
||||
|
||||
};
|
||||
|
||||
class SVGRadialGradient : public SVGGradient {
|
||||
public:
|
||||
SVGRadialGradient();
|
||||
virtual ~SVGRadialGradient();
|
||||
|
||||
protected:
|
||||
virtual Gradient* MakeGradient() const;
|
||||
|
||||
};
|
||||
|
||||
} // namespace svg
|
||||
} // namespace agg
|
||||
|
||||
#endif // SVG_GRADIENTS_H
|
||||
@@ -18,7 +18,7 @@
|
||||
#include <Path.h>
|
||||
|
||||
#include "DocumentBuilder.h"
|
||||
#include "SVGParser.h"
|
||||
#include "nanosvg.h"
|
||||
|
||||
|
||||
#undef B_TRANSLATION_CONTEXT
|
||||
@@ -69,23 +69,22 @@ SVGImporter::Import(Icon* icon, const entry_ref* ref)
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
try {
|
||||
agg::svg::DocumentBuilder builder;
|
||||
agg::svg::Parser parser(builder);
|
||||
parser.parse(path.Path());
|
||||
ret = builder.GetIcon(icon, this, ref->name);
|
||||
} catch(agg::svg::exception& e) {
|
||||
NSVGimage* svg = nsvgParseFromFile(path.Path(), "px", 96);
|
||||
if (svg == NULL) {
|
||||
char error[1024];
|
||||
sprintf(error, B_TRANSLATE("Failed to open the file '%s' as "
|
||||
"an SVG document.\n\n"
|
||||
"Error: %s"), ref->name, e.msg());
|
||||
"an SVG document.\n\n"), ref->name);
|
||||
BAlert* alert = new BAlert(B_TRANSLATE("load error"),
|
||||
error, B_TRANSLATE("OK"), NULL, NULL,
|
||||
B_WIDTH_AS_USUAL, B_WARNING_ALERT);
|
||||
error, B_TRANSLATE("OK"), NULL, NULL,
|
||||
B_WIDTH_AS_USUAL, B_WARNING_ALERT);
|
||||
alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
|
||||
alert->Go(NULL);
|
||||
ret = B_ERROR;
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
DocumentBuilder builder(svg);
|
||||
ret = builder.GetIcon(icon, this, ref->name);
|
||||
nsvgDelete(svg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,105 +0,0 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.2
|
||||
// Copyright (C) 2002-2004 Maxim Shemanarev (http://www.antigrain.com)
|
||||
//
|
||||
// Permission to copy, use, modify, sell and distribute this software
|
||||
// is granted provided this copyright notice appears in all copies.
|
||||
// This software is provided "as is" without express or implied
|
||||
// warranty, and with no claim as to its suitability for any purpose.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
// Contact: [email protected]
|
||||
// [email protected]
|
||||
// http://www.antigrain.com
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#ifndef SVG_PARSER_H
|
||||
#define SVG_PARSER_H
|
||||
|
||||
#include "PathTokenizer.h"
|
||||
#include "DocumentBuilder.h"
|
||||
|
||||
namespace agg {
|
||||
namespace svg {
|
||||
|
||||
class Parser {
|
||||
enum { buf_size = BUFSIZ };
|
||||
public:
|
||||
|
||||
Parser(DocumentBuilder& builder);
|
||||
virtual ~Parser();
|
||||
|
||||
void parse(const char* pathToFile);
|
||||
const char* title() const
|
||||
{ return fTitle; }
|
||||
|
||||
bool TagsIgnored() const
|
||||
{ return fTagsIgnored; }
|
||||
|
||||
private:
|
||||
// XML event handlers
|
||||
static void start_element(void* data, const char* el,
|
||||
const char** attr);
|
||||
static void end_element(void* data, const char* el);
|
||||
static void content(void* data, const char* s, int len);
|
||||
|
||||
void parse_svg(const char** attr);
|
||||
void parse_attr(const char** attr);
|
||||
void parse_path(const char** attr);
|
||||
void parse_poly(const char** attr, bool close_flag);
|
||||
void parse_circle(const char** attr);
|
||||
void parse_ellipse(const char** attr);
|
||||
void parse_rect(const char** attr);
|
||||
void parse_line(const char** attr);
|
||||
void parse_style(const char* str);
|
||||
trans_affine parse_transform(const char* str);
|
||||
|
||||
void parse_gradient(const char** attr, bool radial);
|
||||
void parse_gradient_stop(const char** attr);
|
||||
|
||||
unsigned parse_matrix(const char* str, trans_affine& transform);
|
||||
unsigned parse_translate(const char* str, trans_affine& transform);
|
||||
unsigned parse_rotate(const char* str, trans_affine& transform);
|
||||
unsigned parse_scale(const char* str, trans_affine& transform);
|
||||
unsigned parse_skew_x(const char* str, trans_affine& transform);
|
||||
unsigned parse_skew_y(const char* str, trans_affine& transform);
|
||||
|
||||
bool parse_attr(const char* name,
|
||||
const char* value);
|
||||
bool parse_name_value(const char* nv_start,
|
||||
const char* nv_end);
|
||||
void copy_name(const char* start, const char* end);
|
||||
void copy_value(const char* start, const char* end);
|
||||
|
||||
private:
|
||||
DocumentBuilder& fBuilder;
|
||||
PathTokenizer fPathTokenizer;
|
||||
char* fBuffer;
|
||||
char* fTitle;
|
||||
unsigned fTitleLength;
|
||||
|
||||
bool fTitleFlag;
|
||||
bool fPathFlag;
|
||||
|
||||
char* fAttrName;
|
||||
char* fAttrValue;
|
||||
unsigned fAttrNameLength;
|
||||
unsigned fAttrValueLength;
|
||||
|
||||
rgba8 fGradientStopColor;
|
||||
|
||||
bool fTagsIgnored;
|
||||
};
|
||||
|
||||
} // namespace svg
|
||||
} // namespace agg
|
||||
|
||||
#endif // SVG_PARSER_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -601,6 +601,8 @@ Gradient::PrintToStream() const
|
||||
step->color.blue,
|
||||
step->color.alpha);
|
||||
}
|
||||
|
||||
Transformable::PrintToStream();
|
||||
}
|
||||
|
||||
// _MakeEmpty
|
||||
|
||||
@@ -319,3 +319,12 @@ Transformable::TransformationChanged()
|
||||
// default implementation doesn't care
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Transformable::PrintToStream() const
|
||||
{
|
||||
double matrix[6];
|
||||
store_to(matrix);
|
||||
printf("Transform:\n%f\t%f\t%f\n%f\t%f\t%f\n",
|
||||
matrix[0], matrix[2], matrix[4], matrix[1], matrix[3], matrix[5]);
|
||||
}
|
||||
|
||||
@@ -70,6 +70,8 @@ class Transformable : public agg::trans_affine {
|
||||
virtual void TransformationChanged();
|
||||
// hook function that is called when the transformation
|
||||
// is changed for some reason
|
||||
|
||||
virtual void PrintToStream() const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user