From f3b182a2facfd52c7bbfee67f207ad765f536beb Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Tue, 14 Oct 2014 13:01:49 +0200 Subject: Merged hatch rendering code (bzr r13611.1.8) --- src/sp-hatch-path.cpp | 290 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 290 insertions(+) create mode 100644 src/sp-hatch-path.cpp (limited to 'src/sp-hatch-path.cpp') diff --git a/src/sp-hatch-path.cpp b/src/sp-hatch-path.cpp new file mode 100644 index 000000000..bdefd32d8 --- /dev/null +++ b/src/sp-hatch-path.cpp @@ -0,0 +1,290 @@ +/** @file + * SVG implementation + *//* + * Author: + * Tomasz Boczkowski + * + * Copyright (C) 2014 Tomasz Boczkowski + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include <2geom/path.h> +#include <2geom/transforms.h> + +#include "svg/svg.h" +#include "display/cairo-utils.h" +#include "display/curve.h" +#include "display/drawing-context.h" +#include "display/drawing-surface.h" +#include "display/drawing.h" +#include "display/drawing-shape.h" +#include "attributes.h" +#include "document-private.h" +#include "uri.h" +#include "style.h" +#include "sp-hatch-path.h" +#include "svg/css-ostringstream.h" +#include "xml/repr.h" + +#include "sp-factory.h" + +namespace { +SPObject* createHatchPath() { + return new SPHatchPath(); +} + +bool hatchRegistered = SPFactory::instance().registerObject("svg:hatchPath", createHatchPath); +} + +SPHatchPath::SPHatchPath() + : _curve(NULL) +{ + offset.unset(); +} + +SPHatchPath::~SPHatchPath() { +} + +void SPHatchPath::setCurve(SPCurve *new_curve, bool owner) { + if (_curve) { + _curve = _curve->unref(); + } + + if (new_curve) { + if (owner) { + _curve = new_curve->ref(); + } else { + _curve = new_curve->copy(); + } + } + + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); +} + +void SPHatchPath::build(SPDocument* doc, Inkscape::XML::Node* repr) { + SPObject::build(doc, repr); + + this->readAttr("d"); + this->readAttr("offset"); + this->readAttr( "style" ); + + style->fill.setNone(); +} + +void SPHatchPath::release() { + for (ViewIterator iter = _display.begin(); iter != _display.end(); iter++) { + delete iter->arenaitem; + iter->arenaitem = NULL; + } + + SPObject::release(); +} + +void SPHatchPath::set(unsigned int key, const gchar* value) { + switch (key) { + case SP_ATTR_D: + if (value) { + Geom::PathVector pv; + _readHatchPathVector(value, pv, _continuous); + SPCurve *curve = new SPCurve(pv); + + if (curve) { + this->setCurve(curve, true); + curve->unref(); + } + } else { + this->setCurve(NULL, true); + } + + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + break; + + case SP_ATTR_OFFSET: + offset.readOrUnset(value); + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + break; + + default: + if (SP_ATTRIBUTE_IS_CSS(key)) { + sp_style_read_from_object(this->style, this); + requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG); + } else { + SPObject::set(key, value); + } + break; + } +} + + +void SPHatchPath::update(SPCtx* ctx, unsigned int flags) { + + if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) { + flags &= ~SP_OBJECT_USER_MODIFIED_FLAG_B; + } + + if (flags & (SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) { + if (this->style->stroke_width.unit == SP_CSS_UNIT_PERCENT) { + SPItemCtx *ictx = (SPItemCtx *) ctx; + double const aw = 1.0 / ictx->i2vp.descrim(); + this->style->stroke_width.computed = this->style->stroke_width.value * aw; + + for (ViewIterator iter = _display.begin(); iter != _display.end(); iter++) { + iter->arenaitem->setStyle(this->style); + } + } + } + + if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_PARENT_MODIFIED_FLAG)) { + for (ViewIterator iter = _display.begin(); iter != _display.end(); iter++) { + _updateView(*iter); + } + } +} + +bool SPHatchPath::isValid() const { + if (_curve && (_repeatLength() <= 0)) { + return false; + } + return true; +} + +Inkscape::DrawingItem *SPHatchPath::show(Inkscape::Drawing &drawing, unsigned int key) { + Inkscape::DrawingShape *s = new Inkscape::DrawingShape(drawing); + _display.push_front(View(s, key)); + + _updateView(_display.front()); + + return s; +} + +void SPHatchPath::hide(unsigned int key) { + for (ViewIterator iter = _display.begin(); iter != _display.end(); iter++) { + if (iter->key == key) { + delete iter->arenaitem; + _display.erase(iter); + return; + } + } + + g_assert_not_reached(); +} + +void SPHatchPath::setStripExtents(unsigned int key, Geom::OptInterval const &extents) { + for (ViewIterator iter = _display.begin(); iter != _display.end(); iter++) { + if (iter->key == key) { + iter->extents = extents; + break; + } + } +} + +gdouble SPHatchPath::_repeatLength() const { + if (!_curve) { + return 0; + } + + if (!_curve->last_point()) { + return 0; + } + + return _curve->last_point()->y(); +} + +void SPHatchPath::_updateView(View &view) { + SPCurve *calculated_curve = new SPCurve; + + if (!view.extents) { + return; + } + + if (!_curve) { + calculated_curve->moveto(0, view.extents->min()); + calculated_curve->lineto(0, view.extents->max()); + //TODO: if hatch has a dasharray defined, adjust line ends + } else { + gdouble repeatLength = _repeatLength(); + if (repeatLength > 0) { + gdouble initial_y = floor(view.extents->min() / repeatLength) * repeatLength; + int segment_cnt = ceil((view.extents->extent()) / repeatLength) + 1; + + SPCurve *segment =_curve->copy(); + segment->transform(Geom::Translate(0, initial_y)); + + Geom::Affine step_transform = Geom::Translate(0, repeatLength); + for (int i = 0; i < segment_cnt; i++) { + if (_continuous) { + calculated_curve->append_continuous(segment, 0.0625); + } else { + calculated_curve->append(segment, false); + } + segment->transform(step_transform); + } + + segment->unref(); + } + } + + Geom::Affine offset_transform = Geom::Translate(offset.computed, 0); + view.arenaitem->setTransform(offset_transform); + style->fill.setNone(); + view.arenaitem->setStyle(this->style); + view.arenaitem->setPath(calculated_curve); + + calculated_curve->unref(); +} + +void SPHatchPath::_readHatchPathVector(char const *str, Geom::PathVector &pathv, bool &continous_join) { + if (!str) { + return; + } + + pathv = sp_svg_read_pathv(str); + + if (!pathv.empty()) { + continous_join = false; + } else { + Glib::ustring str2 = Glib::ustring::compose("M0,0 %1", str); + pathv = sp_svg_read_pathv(str2.c_str()); + if (pathv.empty()) { + return; + } + + gdouble last_point_x = pathv.back().finalPoint().x(); + Inkscape::CSSOStringStream stream; + stream << last_point_x; + Glib::ustring str3 = Glib::ustring::compose("M%1,0 %2", stream.str(), str); + Geom::PathVector pathv3 = sp_svg_read_pathv(str3.c_str()); + + //Path can be composed of relative commands only. In this case final point + //coordinates would depend on first point position. If this happens, fall + //back to using 0,0 as first path point + if (pathv3.back().finalPoint().y() == pathv.back().finalPoint().y()) { + pathv = pathv3; + } + continous_join = true; + } +} + +SPHatchPath::View::View(Inkscape::DrawingShape *arenaitem, int key) + : arenaitem(arenaitem), key(key) +{ +} + + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: + */ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : -- cgit v1.2.3 From bf11ecdfe29082801833fa565f0a1710f6fcd281 Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Tue, 14 Oct 2014 13:30:31 +0200 Subject: Merged hatch pdf and png export code (bzr r13611.1.9) --- src/sp-hatch-path.cpp | 61 ++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 51 insertions(+), 10 deletions(-) (limited to 'src/sp-hatch-path.cpp') diff --git a/src/sp-hatch-path.cpp b/src/sp-hatch-path.cpp index bdefd32d8..f7138fac2 100644 --- a/src/sp-hatch-path.cpp +++ b/src/sp-hatch-path.cpp @@ -25,6 +25,7 @@ #include "display/drawing-surface.h" #include "display/drawing.h" #include "display/drawing-shape.h" +#include "helper/geom.h" #include "attributes.h" #include "document-private.h" #include "uri.h" @@ -45,6 +46,7 @@ bool hatchRegistered = SPFactory::instance().registerObject("svg:hatchPath", cre SPHatchPath::SPHatchPath() : _curve(NULL) + , _continuous(false) { offset.unset(); } @@ -131,6 +133,8 @@ void SPHatchPath::update(SPCtx* ctx, unsigned int flags) { if (flags & (SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) { if (this->style->stroke_width.unit == SP_CSS_UNIT_PERCENT) { + //TODO: Check specification + SPItemCtx *ictx = (SPItemCtx *) ctx; double const aw = 1.0 / ictx->i2vp.descrim(); this->style->stroke_width.computed = this->style->stroke_width.value * aw; @@ -155,9 +159,10 @@ bool SPHatchPath::isValid() const { return true; } -Inkscape::DrawingItem *SPHatchPath::show(Inkscape::Drawing &drawing, unsigned int key) { +Inkscape::DrawingItem *SPHatchPath::show(Inkscape::Drawing &drawing, unsigned int key, Geom::OptInterval extents) { Inkscape::DrawingShape *s = new Inkscape::DrawingShape(drawing); _display.push_front(View(s, key)); + _display.front().extents = extents; _updateView(_display.front()); @@ -185,6 +190,36 @@ void SPHatchPath::setStripExtents(unsigned int key, Geom::OptInterval const &ext } } +Geom::Interval SPHatchPath::bounds() const { + Geom::OptRect bbox; + Geom::Interval result; + + Geom::Affine transform = Geom::Translate(offset.computed, 0); + if (!this->_curve) { + SPCurve test_curve; + test_curve.moveto(Geom::Point(0, 0)); + test_curve.moveto(Geom::Point(0, 1)); + bbox = bounds_exact_transformed(test_curve.get_pathvector(), transform); + } else { + bbox = bounds_exact_transformed(this->_curve->get_pathvector(), transform); + } + + gdouble stroke_width = style->stroke_width.computed; + result.setMin(bbox->left() - stroke_width / 2); + result.setMax(bbox->right() + stroke_width / 2); + return result; +} + +SPCurve *SPHatchPath::calculateRenderCurve(unsigned key) const { + for (ConstViewIterator iter = _display.begin(); iter != _display.end(); iter++) { + if (iter->key == key) { + return _calculateRenderCurve(*iter); + } + } + g_assert_not_reached(); + return NULL; +} + gdouble SPHatchPath::_repeatLength() const { if (!_curve) { return 0; @@ -198,10 +233,22 @@ gdouble SPHatchPath::_repeatLength() const { } void SPHatchPath::_updateView(View &view) { + SPCurve *calculated_curve = _calculateRenderCurve(view); + + Geom::Affine offset_transform = Geom::Translate(offset.computed, 0); + view.arenaitem->setTransform(offset_transform); + style->fill.setNone(); + view.arenaitem->setStyle(this->style); + view.arenaitem->setPath(calculated_curve); + + calculated_curve->unref(); +} + +SPCurve *SPHatchPath::_calculateRenderCurve(View const &view) const { SPCurve *calculated_curve = new SPCurve; if (!view.extents) { - return; + return calculated_curve; } if (!_curve) { @@ -230,16 +277,10 @@ void SPHatchPath::_updateView(View &view) { segment->unref(); } } - - Geom::Affine offset_transform = Geom::Translate(offset.computed, 0); - view.arenaitem->setTransform(offset_transform); - style->fill.setNone(); - view.arenaitem->setStyle(this->style); - view.arenaitem->setPath(calculated_curve); - - calculated_curve->unref(); + return calculated_curve; } + void SPHatchPath::_readHatchPathVector(char const *str, Geom::PathVector &pathv, bool &continous_join) { if (!str) { return; -- cgit v1.2.3 From 74d18f102cb65a67ac5d8640085878284362eaeb Mon Sep 17 00:00:00 2001 From: "Jon A. Cruz" Date: Fri, 17 Oct 2014 17:03:52 -0700 Subject: Refactoring hatch to remove memory leaks (bad GTKish casting macros) and uninitialized value. (bzr r13622) --- src/sp-hatch-path.cpp | 140 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 85 insertions(+), 55 deletions(-) (limited to 'src/sp-hatch-path.cpp') diff --git a/src/sp-hatch-path.cpp b/src/sp-hatch-path.cpp index f7138fac2..8558b67f2 100644 --- a/src/sp-hatch-path.cpp +++ b/src/sp-hatch-path.cpp @@ -1,8 +1,11 @@ -/** @file +/** + * @file * SVG implementation - *//* + */ +/* * Author: * Tomasz Boczkowski + * Jon A. Cruz * * Copyright (C) 2014 Tomasz Boczkowski * @@ -37,24 +40,31 @@ #include "sp-factory.h" namespace { -SPObject* createHatchPath() { + +SPObject* createHatchPath() +{ return new SPHatchPath(); } bool hatchRegistered = SPFactory::instance().registerObject("svg:hatchPath", createHatchPath); -} + +} // namespace SPHatchPath::SPHatchPath() - : _curve(NULL) - , _continuous(false) + : offset(), + _display(), + _curve(NULL), + _continuous(false) { offset.unset(); } -SPHatchPath::~SPHatchPath() { +SPHatchPath::~SPHatchPath() +{ } -void SPHatchPath::setCurve(SPCurve *new_curve, bool owner) { +void SPHatchPath::setCurve(SPCurve *new_curve, bool owner) +{ if (_curve) { _curve = _curve->unref(); } @@ -67,21 +77,23 @@ void SPHatchPath::setCurve(SPCurve *new_curve, bool owner) { } } - this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); } -void SPHatchPath::build(SPDocument* doc, Inkscape::XML::Node* repr) { +void SPHatchPath::build(SPDocument* doc, Inkscape::XML::Node* repr) +{ SPObject::build(doc, repr); - this->readAttr("d"); - this->readAttr("offset"); - this->readAttr( "style" ); + readAttr("d"); + readAttr("offset"); + readAttr( "style" ); style->fill.setNone(); } -void SPHatchPath::release() { - for (ViewIterator iter = _display.begin(); iter != _display.end(); iter++) { +void SPHatchPath::release() +{ + for (ViewIterator iter = _display.begin(); iter != _display.end(); ++iter) { delete iter->arenaitem; iter->arenaitem = NULL; } @@ -89,7 +101,8 @@ void SPHatchPath::release() { SPObject::release(); } -void SPHatchPath::set(unsigned int key, const gchar* value) { +void SPHatchPath::set(unsigned int key, const gchar* value) +{ switch (key) { case SP_ATTR_D: if (value) { @@ -98,24 +111,24 @@ void SPHatchPath::set(unsigned int key, const gchar* value) { SPCurve *curve = new SPCurve(pv); if (curve) { - this->setCurve(curve, true); + setCurve(curve, true); curve->unref(); } } else { - this->setCurve(NULL, true); + setCurve(NULL, true); } - this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_OFFSET: offset.readOrUnset(value); - this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; default: if (SP_ATTRIBUTE_IS_CSS(key)) { - sp_style_read_from_object(this->style, this); + sp_style_read_from_object(style, this); requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG); } else { SPObject::set(key, value); @@ -125,41 +138,44 @@ void SPHatchPath::set(unsigned int key, const gchar* value) { } -void SPHatchPath::update(SPCtx* ctx, unsigned int flags) { - +void SPHatchPath::update(SPCtx* ctx, unsigned int flags) +{ if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) { flags &= ~SP_OBJECT_USER_MODIFIED_FLAG_B; } if (flags & (SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) { - if (this->style->stroke_width.unit == SP_CSS_UNIT_PERCENT) { + if (style->stroke_width.unit == SP_CSS_UNIT_PERCENT) { //TODO: Check specification - SPItemCtx *ictx = (SPItemCtx *) ctx; - double const aw = 1.0 / ictx->i2vp.descrim(); - this->style->stroke_width.computed = this->style->stroke_width.value * aw; + SPItemCtx *ictx = static_cast(ctx); + double const aw = (ictx) ? 1.0 / ictx->i2vp.descrim() : 1.0; + style->stroke_width.computed = style->stroke_width.value * aw; - for (ViewIterator iter = _display.begin(); iter != _display.end(); iter++) { - iter->arenaitem->setStyle(this->style); + for (ViewIterator iter = _display.begin(); iter != _display.end(); ++iter) { + iter->arenaitem->setStyle(style); } } } if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_PARENT_MODIFIED_FLAG)) { - for (ViewIterator iter = _display.begin(); iter != _display.end(); iter++) { + for (ViewIterator iter = _display.begin(); iter != _display.end(); ++iter) { _updateView(*iter); } } } -bool SPHatchPath::isValid() const { +bool SPHatchPath::isValid() const +{ if (_curve && (_repeatLength() <= 0)) { return false; + } else { + return true; } - return true; } -Inkscape::DrawingItem *SPHatchPath::show(Inkscape::Drawing &drawing, unsigned int key, Geom::OptInterval extents) { +Inkscape::DrawingItem *SPHatchPath::show(Inkscape::Drawing &drawing, unsigned int key, Geom::OptInterval extents) +{ Inkscape::DrawingShape *s = new Inkscape::DrawingShape(drawing); _display.push_front(View(s, key)); _display.front().extents = extents; @@ -169,8 +185,9 @@ Inkscape::DrawingItem *SPHatchPath::show(Inkscape::Drawing &drawing, unsigned in return s; } -void SPHatchPath::hide(unsigned int key) { - for (ViewIterator iter = _display.begin(); iter != _display.end(); iter++) { +void SPHatchPath::hide(unsigned int key) +{ + for (ViewIterator iter = _display.begin(); iter != _display.end(); ++iter) { if (iter->key == key) { delete iter->arenaitem; _display.erase(iter); @@ -181,8 +198,9 @@ void SPHatchPath::hide(unsigned int key) { g_assert_not_reached(); } -void SPHatchPath::setStripExtents(unsigned int key, Geom::OptInterval const &extents) { - for (ViewIterator iter = _display.begin(); iter != _display.end(); iter++) { +void SPHatchPath::setStripExtents(unsigned int key, Geom::OptInterval const &extents) +{ + for (ViewIterator iter = _display.begin(); iter != _display.end(); ++iter) { if (iter->key == key) { iter->extents = extents; break; @@ -190,18 +208,19 @@ void SPHatchPath::setStripExtents(unsigned int key, Geom::OptInterval const &ext } } -Geom::Interval SPHatchPath::bounds() const { +Geom::Interval SPHatchPath::bounds() const +{ Geom::OptRect bbox; Geom::Interval result; Geom::Affine transform = Geom::Translate(offset.computed, 0); - if (!this->_curve) { + if (!_curve) { SPCurve test_curve; test_curve.moveto(Geom::Point(0, 0)); test_curve.moveto(Geom::Point(0, 1)); bbox = bounds_exact_transformed(test_curve.get_pathvector(), transform); } else { - bbox = bounds_exact_transformed(this->_curve->get_pathvector(), transform); + bbox = bounds_exact_transformed(_curve->get_pathvector(), transform); } gdouble stroke_width = style->stroke_width.computed; @@ -210,8 +229,9 @@ Geom::Interval SPHatchPath::bounds() const { return result; } -SPCurve *SPHatchPath::calculateRenderCurve(unsigned key) const { - for (ConstViewIterator iter = _display.begin(); iter != _display.end(); iter++) { +SPCurve *SPHatchPath::calculateRenderCurve(unsigned key) const +{ + for (ConstViewIterator iter = _display.begin(); iter != _display.end(); ++iter) { if (iter->key == key) { return _calculateRenderCurve(*iter); } @@ -220,31 +240,32 @@ SPCurve *SPHatchPath::calculateRenderCurve(unsigned key) const { return NULL; } -gdouble SPHatchPath::_repeatLength() const { - if (!_curve) { - return 0; - } +gdouble SPHatchPath::_repeatLength() const +{ + gdouble val = 0; - if (!_curve->last_point()) { - return 0; + if (_curve && _curve->last_point()) { + val = _curve->last_point()->y(); } - return _curve->last_point()->y(); + return val; } -void SPHatchPath::_updateView(View &view) { +void SPHatchPath::_updateView(View &view) +{ SPCurve *calculated_curve = _calculateRenderCurve(view); Geom::Affine offset_transform = Geom::Translate(offset.computed, 0); view.arenaitem->setTransform(offset_transform); style->fill.setNone(); - view.arenaitem->setStyle(this->style); + view.arenaitem->setStyle(style); view.arenaitem->setPath(calculated_curve); calculated_curve->unref(); } -SPCurve *SPHatchPath::_calculateRenderCurve(View const &view) const { +SPCurve *SPHatchPath::_calculateRenderCurve(View const &view) const +{ SPCurve *calculated_curve = new SPCurve; if (!view.extents) { @@ -265,7 +286,7 @@ SPCurve *SPHatchPath::_calculateRenderCurve(View const &view) const { segment->transform(Geom::Translate(0, initial_y)); Geom::Affine step_transform = Geom::Translate(0, repeatLength); - for (int i = 0; i < segment_cnt; i++) { + for (int i = 0; i < segment_cnt; ++i) { if (_continuous) { calculated_curve->append_continuous(segment, 0.0625); } else { @@ -281,7 +302,8 @@ SPCurve *SPHatchPath::_calculateRenderCurve(View const &view) const { } -void SPHatchPath::_readHatchPathVector(char const *str, Geom::PathVector &pathv, bool &continous_join) { +void SPHatchPath::_readHatchPathVector(char const *str, Geom::PathVector &pathv, bool &continous_join) +{ if (!str) { return; } @@ -314,8 +336,16 @@ void SPHatchPath::_readHatchPathVector(char const *str, Geom::PathVector &pathv, } SPHatchPath::View::View(Inkscape::DrawingShape *arenaitem, int key) - : arenaitem(arenaitem), key(key) + : arenaitem(arenaitem), + extents(), + key(key) +{ +} + +SPHatchPath::View::~View() { + // remember, do not delete arenaitem here + arenaitem = NULL; } -- cgit v1.2.3