From 307e5bbe5490413426d817bd5cb1f35a07956609 Mon Sep 17 00:00:00 2001 From: Martin Gieseking Date: Fri, 27 Oct 2017 16:13:56 +0200 Subject: [PATCH] replaced raw XMLNode pointers with unique_ptrs which helps to ensure proper ownership and simplifies deleting the corresponding objects --- src/DVIToSVG.cpp | 2 +- src/DVIToSVGActions.cpp | 18 ++-- src/DVIToSVGActions.hpp | 8 +- src/DvisvgmSpecialHandler.cpp | 13 +-- src/EPSToSVG.cpp | 3 +- src/EPSToSVG.hpp | 12 +-- src/EmSpecialHandler.cpp | 8 +- src/HyperlinkManager.cpp | 21 ++--- src/PSPattern.cpp | 75 ++++++++-------- src/PSPattern.hpp | 27 +++--- src/PsSpecialHandler.cpp | 75 ++++++++-------- src/SVGCharHandler.cpp | 30 ++++--- src/SVGCharHandler.hpp | 5 +- src/SVGCharPathHandler.cpp | 17 ++-- src/SVGCharTspanTextHandler.cpp | 7 +- src/SVGSingleCharTextHandler.cpp | 4 +- src/SVGTree.cpp | 114 ++++++++++++------------- src/SVGTree.hpp | 12 +-- src/ShadingPatch.hpp | 6 +- src/SpecialActions.hpp | 23 +++-- src/TpicSpecialHandler.cpp | 28 +++--- src/XMLDocument.cpp | 16 ++-- src/XMLDocument.hpp | 11 +-- src/XMLNode.cpp | 74 ++++++++-------- src/XMLNode.hpp | 27 +++--- src/utility.hpp | 6 ++ tests/DvisvgmSpecialTest.cpp | 33 ++++---- tests/EmSpecialTest.cpp | 31 +++---- tests/TpicSpecialTest.cpp | 20 ++--- tests/XMLNodeTest.cpp | 141 ++++++++++++++++--------------- 30 files changed, 439 insertions(+), 428 deletions(-) diff --git a/src/DVIToSVG.cpp b/src/DVIToSVG.cpp index 0f8ff989..3958690a 100644 --- a/src/DVIToSVG.cpp +++ b/src/DVIToSVG.cpp @@ -173,7 +173,7 @@ void DVIToSVG::enterBeginPage (unsigned pageno, const vector &c) { if (pageno != (unsigned)c[0]) // Does page number shown on page differ from physical page number? Message::mstream(false) << " [" << c[0] << ']'; Message::mstream().indent(1); - _svg.appendToDoc(new XMLCommentNode(" This file was generated by dvisvgm " + string(PROGRAM_VERSION) + " ")); + _svg.appendToDoc(util::make_unique(" This file was generated by dvisvgm " + string(PROGRAM_VERSION) + " ")); } } diff --git a/src/DVIToSVGActions.cpp b/src/DVIToSVGActions.cpp index c1f35ef0..da8d9edd 100644 --- a/src/DVIToSVGActions.cpp +++ b/src/DVIToSVGActions.cpp @@ -158,7 +158,7 @@ void DVIToSVGActions::setChar (double x, double y, unsigned c, bool vertical, co * @param[in] width length of the horizontal edges */ void DVIToSVGActions::setRule (double x, double y, double height, double width) { // (x,y) is the lower left corner of the rectangle - XMLElementNode *rect = new XMLElementNode("rect"); + auto rect = util::make_unique("rect"); rect->addAttribute("x", x); rect->addAttribute("y", y-height); rect->addAttribute("height", height); @@ -167,7 +167,7 @@ void DVIToSVGActions::setRule (double x, double y, double height, double width) rect->addAttribute("transform", getMatrix().getSVG()); if (getColor() != Color::BLACK) rect->addAttribute("fill", _svg.getColor().svgColorString()); - _svg.appendToPage(rect); + _svg.appendToPage(std::move(rect)); // update bounding box BoundingBox bb(x, y-height, x+width, y); @@ -225,13 +225,13 @@ void DVIToSVGActions::endPage (unsigned pageno) { _svg.transformPage(matrix); if (_bgcolor != Color::TRANSPARENT) { // create a rectangle filled with the background color - XMLElementNode *r = new XMLElementNode("rect"); - r->addAttribute("x", _bbox.minX()); - r->addAttribute("y", _bbox.minY()); - r->addAttribute("width", _bbox.width()); - r->addAttribute("height", _bbox.height()); - r->addAttribute("fill", _bgcolor.svgColorString()); - _svg.prependToPage(r); + auto rect = util::make_unique("rect"); + rect->addAttribute("x", _bbox.minX()); + rect->addAttribute("y", _bbox.minY()); + rect->addAttribute("width", _bbox.width()); + rect->addAttribute("height", _bbox.height()); + rect->addAttribute("fill", _bgcolor.svgColorString()); + _svg.prependToPage(std::move(rect)); } } diff --git a/src/DVIToSVGActions.hpp b/src/DVIToSVGActions.hpp index 2b7bb223..d188c972 100644 --- a/src/DVIToSVGActions.hpp +++ b/src/DVIToSVGActions.hpp @@ -54,10 +54,10 @@ class DVIToSVGActions : public DVIActions, public SpecialActions { Color getColor () const override {return _svg.getColor();} int getDVIStackDepth() const override {return _dvireader->stackDepth();} unsigned getCurrentPageNumber() const override {return _dvireader->currentPageNumber();} - void appendToPage (XMLNode *node) override {_svg.appendToPage(node);} - void appendToDefs (XMLNode *node) override {_svg.appendToDefs(node);} - void prependToPage (XMLNode *node) override {_svg.prependToPage(node);} - void pushContextElement (XMLElementNode *node) override {_svg.pushContextElement(node);} + void appendToPage(std::unique_ptr &&node) override {_svg.appendToPage(std::move(node));} + void appendToDefs(std::unique_ptr &&node) override {_svg.appendToDefs(std::move(node));} + void prependToPage(std::unique_ptr &&node) override {_svg.prependToPage(std::move(node));} + void pushContextElement (std::unique_ptr &&node) override {_svg.pushContextElement(std::move(node));} void popContextElement () override {_svg.popContextElement();} void setTextOrientation(bool vertical) override {_svg.setVertical(vertical);} void moveToX (double x) override; diff --git a/src/DvisvgmSpecialHandler.cpp b/src/DvisvgmSpecialHandler.cpp index 0db5ee22..1d678345 100644 --- a/src/DvisvgmSpecialHandler.cpp +++ b/src/DvisvgmSpecialHandler.cpp @@ -26,6 +26,7 @@ #include "InputReader.hpp" #include "Length.hpp" #include "SpecialActions.hpp" +#include "utility.hpp" #include "XMLNode.hpp" #include "XMLString.hpp" @@ -190,7 +191,7 @@ void DvisvgmSpecialHandler::processRaw (InputReader &ir, SpecialActions &actions string str = ir.getLine(); if (!str.empty()) { expand_constants(str, actions); - actions.appendToPage(new XMLTextNode(str)); + actions.appendToPage(util::make_unique(str)); } } } @@ -201,7 +202,7 @@ void DvisvgmSpecialHandler::processRawDef (InputReader &ir, SpecialActions &acti string str = ir.getLine(); if (!str.empty()) { expand_constants(str, actions); - actions.appendToDefs(new XMLTextNode(str)); + actions.appendToDefs(util::make_unique(str)); } } } @@ -233,9 +234,9 @@ void DvisvgmSpecialHandler::processRawPut (InputReader &ir, SpecialActions &acti if ((type == 'P' || type == 'D') && !def.empty()) { expand_constants(def, actions); if (type == 'P') - actions.appendToPage(new XMLTextNode(def)); + actions.appendToPage(util::make_unique(def)); else { // type == 'D' - actions.appendToDefs(new XMLTextNode(def)); + actions.appendToDefs(util::make_unique(def)); type = 'L'; // locked } } @@ -321,7 +322,7 @@ void DvisvgmSpecialHandler::processImg (InputReader &ir, SpecialActions &actions Length h = read_length(ir); string f = ir.getString(); update_bbox(w, h, 0, actions); - XMLElementNode *img = new XMLElementNode("image"); + auto img = util::make_unique("image"); img->addAttribute("x", actions.getX()); img->addAttribute("y", actions.getY()); img->addAttribute("width", w.bp()); @@ -329,7 +330,7 @@ void DvisvgmSpecialHandler::processImg (InputReader &ir, SpecialActions &actions img->addAttribute("xlink:href", f); if (!actions.getMatrix().isIdentity()) img->addAttribute("transform", actions.getMatrix().getSVG()); - actions.appendToPage(img); + actions.appendToPage(std::move(img)); } catch (const UnitException &e) { throw SpecialException(string("dvisvgm:img: ") + e.what()); diff --git a/src/EPSToSVG.cpp b/src/EPSToSVG.cpp index e4f40274..a80039bf 100644 --- a/src/EPSToSVG.cpp +++ b/src/EPSToSVG.cpp @@ -28,6 +28,7 @@ #include "PsSpecialHandler.hpp" #include "SVGOutput.hpp" #include "System.hpp" +#include "utility.hpp" #include "version.hpp" using namespace std; @@ -68,7 +69,7 @@ void EPSToSVG::convert () { // output SVG file _svg.removeRedundantElements(); _svg.setBBox(_bbox); - _svg.appendToDoc(new XMLCommentNode(" This file was generated by dvisvgm " + string(PROGRAM_VERSION) + " ")); + _svg.appendToDoc(util::make_unique(" This file was generated by dvisvgm " + string(PROGRAM_VERSION) + " ")); bool success = _svg.write(_out.getPageStream(1, 1)); string svgfname = _out.filename(1, 1); if (svgfname.empty()) diff --git a/src/EPSToSVG.hpp b/src/EPSToSVG.hpp index 5d3172d2..732baa93 100644 --- a/src/EPSToSVG.hpp +++ b/src/EPSToSVG.hpp @@ -21,14 +21,14 @@ #ifndef EPSTOSVG_HPP #define EPSTOSVG_HPP +#include #include #include "SpecialActions.hpp" #include "SVGTree.hpp" struct SVGOutputBase; -class EPSToSVG : protected SpecialActions -{ +class EPSToSVG : protected SpecialActions { public: EPSToSVG (const std::string &fname, SVGOutputBase &out) : _fname(fname), _out(out), _x(0), _y(0) {} void convert (); @@ -48,10 +48,10 @@ class EPSToSVG : protected SpecialActions const Matrix& getMatrix () const override {return _svg.getMatrix();} void getPageTransform (Matrix &matrix) const override {} void setBgColor (const Color &color) override {} - void appendToPage (XMLNode *node) override {_svg.appendToPage(node);} - void appendToDefs (XMLNode *node) override {_svg.appendToDefs(node);} - void prependToPage (XMLNode *node) override {_svg.prependToPage(node);} - void pushContextElement (XMLElementNode *node) override {_svg.pushContextElement(node);} + void appendToPage(std::unique_ptr &&node) override {_svg.appendToPage(std::move(node));} + void appendToDefs(std::unique_ptr &&node) override {_svg.appendToDefs(std::move(node));} + void prependToPage(std::unique_ptr &&node) override {_svg.prependToPage(std::move(node));} + void pushContextElement (std::unique_ptr &&node) override {_svg.pushContextElement(std::move(node));} void popContextElement () override {_svg.popContextElement();} void embed (const BoundingBox &bbox) override {_bbox.embed(bbox);} void embed (const DPair &p, double r=0) override {if (r==0) _bbox.embed(p); else _bbox.embed(p, r);} diff --git a/src/EmSpecialHandler.cpp b/src/EmSpecialHandler.cpp index eb2d1639..29b1331c 100644 --- a/src/EmSpecialHandler.cpp +++ b/src/EmSpecialHandler.cpp @@ -78,11 +78,11 @@ static DPair cut_vector (char cuttype, const DPair &linedir, double linewidth) { * @param[in] lw line width in PS point units * @param[in] actions object providing the actions that can be performed by the SpecialHandler */ static void create_line (const DPair &p1, const DPair &p2, char c1, char c2, double lw, SpecialActions &actions) { - XMLElementNode *node=0; + unique_ptr node; DPair dir = p2-p1; if (dir.x() == 0 || dir.y() == 0 || (c1 == 'p' && c2 == 'p')) { // draw regular line - node = new XMLElementNode("line"); + node = util::make_unique("line"); node->addAttribute("x1", p1.x()); node->addAttribute("y1", p1.y()); node->addAttribute("x2", p2.x()); @@ -107,7 +107,7 @@ static void create_line (const DPair &p1, const DPair &p2, char c1, char c2, dou << XMLString(q12.x()) << ',' << XMLString(q12.y()) << ' ' << XMLString(q22.x()) << ',' << XMLString(q22.y()) << ' ' << XMLString(q21.x()) << ',' << XMLString(q21.y()); - node = new XMLElementNode("polygon"); + node = util::make_unique("polygon"); node->addAttribute("points", oss.str()); if (actions.getColor() != Color::BLACK) node->addAttribute("fill", actions.getColor().svgColorString()); @@ -117,7 +117,7 @@ static void create_line (const DPair &p1, const DPair &p2, char c1, char c2, dou actions.embed(q21); actions.embed(q22); } - actions.appendToPage(node); + actions.appendToPage(std::move(node)); } diff --git a/src/HyperlinkManager.cpp b/src/HyperlinkManager.cpp index 7efb7c06..0b7894aa 100644 --- a/src/HyperlinkManager.cpp +++ b/src/HyperlinkManager.cpp @@ -23,6 +23,7 @@ #include "Message.hpp" #include "SpecialActions.hpp" #include "SVGTree.hpp" +#include "utility.hpp" #include "XMLNode.hpp" using namespace std; @@ -105,10 +106,10 @@ void HyperlinkManager::createLink (string uri, SpecialActions &actions) { uri = "/" + uri; uri = _base + uri; } - XMLElementNode *anchor = new XMLElementNode("a"); - anchor->addAttribute("xlink:href", uri); - anchor->addAttribute("xlink:title", XMLString(name.empty() ? uri : name, false)); - actions.pushContextElement(anchor); + auto anchorNode = util::make_unique("a"); + anchorNode->addAttribute("xlink:href", uri); + anchorNode->addAttribute("xlink:title", XMLString(name.empty() ? uri : name, false)); + actions.pushContextElement(std::move(anchorNode)); actions.bbox("{anchor}", true); // start computing the bounding box of the linked area _depthThreshold = actions.getDVIStackDepth(); _anchorType = AnchorType::HREF; @@ -147,7 +148,7 @@ void HyperlinkManager::markLinkedBox (SpecialActions &actions) { if (bbox.width() > 0 && bbox.height() > 0) { // does the bounding box extend in both dimensions? if (MARKER_TYPE != MarkerType::NONE) { const double linewidth = _linewidth >= 0 ? _linewidth : min(0.5, bbox.height()/15); - XMLElementNode *rect = new XMLElementNode("rect"); + auto rect = util::make_unique("rect"); double x = bbox.minX(); double y = bbox.maxY()+linewidth; double w = bbox.width(); @@ -178,7 +179,7 @@ void HyperlinkManager::markLinkedBox (SpecialActions &actions) { rect->addAttribute("y", y); rect->addAttribute("width", w); rect->addAttribute("height", h); - actions.prependToPage(rect); + actions.prependToPage(std::move(rect)); if (MARKER_TYPE == MarkerType::BOX || MARKER_TYPE == MarkerType::BGCOLOR) { // slightly enlarge the boxed area x -= linewidth; @@ -191,14 +192,14 @@ void HyperlinkManager::markLinkedBox (SpecialActions &actions) { // Create an invisible rectangle around the linked area so that it's easier to access. // This is only necessary when using paths rather than real text elements together with fonts. if (!SVGTree::USE_FONTS) { - XMLElementNode *rect = new XMLElementNode("rect"); + auto rect = util::make_unique("rect"); rect->addAttribute("x", bbox.minX()); rect->addAttribute("y", bbox.minY()); rect->addAttribute("width", bbox.width()); rect->addAttribute("height", bbox.height()); rect->addAttribute("fill", "white"); rect->addAttribute("fill-opacity", 0); - actions.appendToPage(rect); + actions.appendToPage(std::move(rect)); } } } @@ -212,10 +213,10 @@ void HyperlinkManager::createViews (unsigned pageno, SpecialActions &actions) { ostringstream oss; oss << pagebox.minX() << ' ' << stranchorpair.second.pos << ' ' << pagebox.width() << ' ' << pagebox.height(); - XMLElementNode *view = new XMLElementNode("view"); + auto view = util::make_unique("view"); view->addAttribute("id", "loc"+XMLString(stranchorpair.second.id)); view->addAttribute("viewBox", oss.str()); - actions.appendToDefs(view); + actions.appendToDefs(std::move(view)); } } closeAnchor(actions); diff --git a/src/PSPattern.cpp b/src/PSPattern.cpp index 938fecb6..879e851f 100644 --- a/src/PSPattern.cpp +++ b/src/PSPattern.cpp @@ -18,12 +18,14 @@ ** along with this program; if not, see . ** *************************************************************************/ +#include #include #include #include "BoundingBox.hpp" #include "PSPattern.hpp" #include "SpecialActions.hpp" #include "SVGTree.hpp" +#include "utility.hpp" #include "XMLNode.hpp" using namespace std; @@ -36,31 +38,34 @@ string PSPattern::svgID () const { /** Appends the definition of this pattern to the "def" section of the SVG tree. */ void PSPattern::apply (SpecialActions &actions) { - if (XMLElementNode *pattern = createPatternNode()) - actions.appendToDefs(pattern); + if (auto pattern = createPatternNode()) + actions.appendToDefs(std::move(pattern)); } ///////////////////////////////////////////////////////////////////////////// PSTilingPattern::PSTilingPattern (int id, BoundingBox &bbox, Matrix &matrix, double xstep, double ystep) - : PSPattern(id), _bbox(bbox), _matrix(matrix), _xstep(xstep), _ystep(ystep), _groupNode(0) + : PSPattern(id), _bbox(bbox), _matrix(matrix), _xstep(xstep), _ystep(ystep) { _groupNode = PSTilingPattern::createGroupNode(); + _groupNodePtr = _groupNode.get(); } -PSTilingPattern::~PSTilingPattern () { - delete _groupNode; +/** Assigns a new group element. */ +void PSTilingPattern::setGroupNode (unique_ptr &&node) { + _groupNode = std::move(node); + _groupNodePtr = _groupNode.get(); } /** Creates a new pattern element representing the pattern defined in the PS code. */ -XMLElementNode* PSTilingPattern::createPatternNode () const { +unique_ptr PSTilingPattern::createPatternNode () const { if (!_groupNode) - return 0; + return nullptr; BoundingBox box(_bbox.minX(), _bbox.minY(), _bbox.minX()+_xstep, _bbox.minY()+_ystep); - XMLElementNode *pattern = new XMLElementNode("pattern"); + auto pattern = util::make_unique("pattern"); pattern->addAttribute("id", svgID()); pattern->addAttribute("x", box.minX()); pattern->addAttribute("y", box.minY()); @@ -74,41 +79,42 @@ XMLElementNode* PSTilingPattern::createPatternNode () const { // disable clipping at the tile borders => tiles become "transparent" pattern->addAttribute("overflow", "visible"); } - if (XMLElementNode *clip=createClipNode()) - pattern->append(clip); - pattern->append(_groupNode); - return pattern; + if (auto clip = createClipNode()) + pattern->append(std::move(clip)); + pattern->append(std::move(_groupNode)); + _groupNode.reset(); + return std::move(pattern); } /** Creates a new clip element restricting the drawing area to the * dimensions given in the definition of the pattern. */ -XMLElementNode* PSTilingPattern::createClipNode() const { - XMLElementNode *clip = new XMLElementNode("clipPath"); +unique_ptr PSTilingPattern::createClipNode() const { + auto clip = util::make_unique("clipPath"); clip->addAttribute("id", "pc"+XMLString(psID())); - XMLElementNode *rect = new XMLElementNode("rect"); + auto rect = util::make_unique("rect"); rect->addAttribute("x", _bbox.minX()); rect->addAttribute("y", _bbox.minY()); rect->addAttribute("width", _bbox.width()); rect->addAttribute("height", _bbox.height()); - clip->append(rect); - return clip; + clip->append(std::move(rect)); + return std::move(clip); } /** Creates a new group element that contains all "drawing" elements that * define the pattern graphic. */ -XMLElementNode* PSTilingPattern::createGroupNode () const { +unique_ptr PSTilingPattern::createGroupNode () const { // add all succeeding path elements to this group - XMLElementNode *group = new XMLElementNode("g"); + auto group = util::make_unique("g"); group->addAttribute("clip-path", XMLString("url(#pc")+XMLString(psID())+")"); - return group; + return std::move(group); } void PSTilingPattern::apply (SpecialActions &actions) { PSPattern::apply(actions); - _groupNode = 0; + _groupNode.reset(); } @@ -123,17 +129,11 @@ PSColoredTilingPattern::PSColoredTilingPattern (int id, BoundingBox &bbox, Matri ///////////////////////////////////////////////////////////////////////////// PSUncoloredTilingPattern::PSUncoloredTilingPattern (int id, BoundingBox &bbox, Matrix &matrix, double xstep, double ystep) - : PSTilingPattern(id, bbox, matrix, xstep, ystep), _applied(false) + : PSTilingPattern(id, bbox, matrix, xstep, ystep), _applied() { } -PSUncoloredTilingPattern::~PSUncoloredTilingPattern () { - if (_applied) - setGroupNode(0); // prevent deleting the group node in the parent destructor -} - - /** Returns an SVG id value that identifies this pattern with the current color applied. */ string PSUncoloredTilingPattern::svgID () const { ostringstream oss; @@ -148,15 +148,16 @@ void PSUncoloredTilingPattern::apply (SpecialActions &actions) { set::iterator it=_colors.find(_currentColor); if (it == _colors.end()) { if (_applied) - setGroupNode(static_cast(getGroupNode()->clone())); + setGroupNode(util::static_unique_ptr_cast(getGroupNode()->clone())); // assign current color to the pattern graphic vector colored_elems; - const char *attribs[] = {"fill", "stroke"}; - for (int i=0; i < 2; i++) { - getGroupNode()->getDescendants(0, attribs[i], colored_elems); - for (XMLElementNode *elem : colored_elems) - if (string(elem->getAttributeValue(attribs[i])) != "none") - elem->addAttribute(attribs[i], _currentColor.svgColorString()); + const array attribs = {{"fill", "stroke"}}; + for (const char *attrib : attribs) { + getGroupNode()->getDescendants(nullptr, attrib, colored_elems); + for (XMLElementNode *elem : colored_elems) { + if (string(elem->getAttributeValue(attrib)) != "none") + elem->addAttribute(attrib, _currentColor.svgColorString()); + } colored_elems.clear(); } PSPattern::apply(actions); @@ -166,9 +167,9 @@ void PSUncoloredTilingPattern::apply (SpecialActions &actions) { } -XMLElementNode* PSUncoloredTilingPattern::createClipNode() const { +unique_ptr PSUncoloredTilingPattern::createClipNode() const { // only the first instance of this patterns get a clip element if (_colors.empty()) return PSTilingPattern::createClipNode(); - return 0; + return nullptr; } diff --git a/src/PSPattern.hpp b/src/PSPattern.hpp index c4614284..bd2b0317 100644 --- a/src/PSPattern.hpp +++ b/src/PSPattern.hpp @@ -21,11 +21,13 @@ #ifndef PSPATTERN_HPP #define PSPATTERN_HPP +#include #include #include #include "BoundingBox.hpp" #include "Color.hpp" #include "Matrix.hpp" +#include "XMLNode.hpp" class SpecialActions; @@ -41,7 +43,7 @@ class PSPattern { protected: PSPattern (int id) : _id(id) {} - virtual XMLElementNode* createPatternNode () const =0; + virtual std::unique_ptr createPatternNode () const =0; private: int _id; ///< PostSCript ID of this pattern @@ -50,42 +52,41 @@ class PSPattern { class PSTilingPattern : public PSPattern { public: - ~PSTilingPattern (); - virtual XMLElementNode* getContainerNode () {return _groupNode;} + virtual XMLElementNode* getContainerNode () {return _groupNode.get();} void apply (SpecialActions &actions) override; protected: PSTilingPattern (int id, BoundingBox &bbox, Matrix &matrix, double xstep, double ystep); - XMLElementNode* createPatternNode () const override; - virtual XMLElementNode* createClipNode () const; - virtual XMLElementNode* createGroupNode () const; - virtual XMLElementNode* getGroupNode () const {return _groupNode;} - virtual void setGroupNode (XMLElementNode *node) {_groupNode = node;} + std::unique_ptr createPatternNode () const override; + virtual std::unique_ptr createClipNode () const; + virtual std::unique_ptr createGroupNode () const; + virtual XMLElementNode* getGroupNode () const {return _groupNodePtr;} + virtual void setGroupNode (std::unique_ptr &&node); private: BoundingBox _bbox; ///< bounding box of the tile graphics Matrix _matrix; ///< tile transformation double _xstep, _ystep; ///< horizontal and vertical distance between neighboured tiles - XMLElementNode *_groupNode; ///< group containing the drawing elements + mutable std::unique_ptr _groupNode; ///< group containing the drawing elements + XMLElementNode *_groupNodePtr; ///< keeps a pointer to the group node even after moving _groupNode to the SVGTree }; -class PSColoredTilingPattern : public PSTilingPattern { +class PSColoredTilingPattern final : public PSTilingPattern { public: PSColoredTilingPattern (int id, BoundingBox &bbox, Matrix &matrix, double xstep, double ystep); }; -class PSUncoloredTilingPattern : public PSTilingPattern { +class PSUncoloredTilingPattern final : public PSTilingPattern { public: PSUncoloredTilingPattern (int id, BoundingBox &bbox, Matrix &matrix, double xstep, double ystep); - ~PSUncoloredTilingPattern (); std::string svgID () const override; void setColor (Color color) {_currentColor = color;} void apply (SpecialActions &actions) override; protected: - XMLElementNode* createClipNode () const override; + std::unique_ptr createClipNode () const override; private: std::set _colors; ///< colors this pattern has already been drawn with diff --git a/src/PsSpecialHandler.cpp b/src/PsSpecialHandler.cpp index 6b171c95..c8d69eb0 100644 --- a/src/PsSpecialHandler.cpp +++ b/src/PsSpecialHandler.cpp @@ -52,13 +52,13 @@ int PsSpecialHandler::SHADING_SEGMENT_SIZE = 20; double PsSpecialHandler::SHADING_SIMPLIFY_DELTA = 0.01; -PsSpecialHandler::PsSpecialHandler () : _psi(this), _actions(0), _previewFilter(_psi), _psSection(PS_NONE), _xmlnode(0) +PsSpecialHandler::PsSpecialHandler () : _psi(this), _actions(), _previewFilter(_psi), _psSection(PS_NONE), _xmlnode(), _savenode() { } PsSpecialHandler::~PsSpecialHandler () { - _psi.setActions(0); // ensure no further PS actions are performed + _psi.setActions(nullptr); // ensure no further PS actions are performed } @@ -84,10 +84,10 @@ void PsSpecialHandler::initgraphics () { _linewidth = 1; _linecap = _linejoin = 0; // butt end caps and miter joins _miterlimit = 4; - _xmlnode = _savenode = 0; + _xmlnode = _savenode = nullptr; _opacityalpha = 1; // fully opaque _sx = _sy = _cos = 1.0; - _pattern = 0; + _pattern = nullptr; _currentcolor = Color::BLACK; _dashoffset = 0; _dashpattern.clear(); @@ -328,26 +328,25 @@ void PsSpecialHandler::psfile (const string &fname, const unordered_mapgetMatrix()*DPair(urx, -ury); DPair dviposTrans = _actions->getMatrix()*DPair(x, y); - _xmlnode = new XMLElementNode("g"); // append following elements to this group + auto groupNode = util::make_unique("g"); // append following elements to this group + _xmlnode = groupNode.get(); _psi.execute("\n@beginspecial @setspecial "); // enter \special environment EPSFile epsfile(filepath); _psi.limit(epsfile.pslength()); // limit the number of bytes going to be processed _psi.execute(epsfile.istream()); // process EPS file _psi.limit(0); // disable limitation _psi.execute("\n@endspecial "); // leave special environment - if (_xmlnode->empty()) // nothing been drawn? - delete _xmlnode; // => don't need to add empty group node - else { // has anything been drawn? + if (!groupNode->empty()) { // has anything been drawn? Matrix matrix(1); matrix.rotate(angle).scale(hscale/100, vscale/100).translate(hoffset, voffset); matrix.translate(-llTrans); matrix.scale(sx, sy); // resize image to width "rwi" and height "rhi" matrix.translate(dviposTrans); // move image to current DVI position if (!matrix.isIdentity()) - _xmlnode->addAttribute("transform", matrix.getSVG()); - _actions->appendToPage(_xmlnode); + groupNode->addAttribute("transform", matrix.getSVG()); + _actions->appendToPage(std::move(groupNode)); } - _xmlnode = 0; // append following elements to page group again + _xmlnode = nullptr; // append following elements to page group again // restore DVI position _actions->setX(x); @@ -531,14 +530,14 @@ void PsSpecialHandler::stroke (vector &p) { } if (_clipStack.clippathLoaded() && _clipStack.top()) _path.prepend(*_clipStack.top()); - XMLElementNode *path=0; + unique_ptr path; Pair point; if (_path.isDot(point)) { // zero-length path? if (_linecap == 1) { // round line ends? => draw dot double x = point.x(); double y = point.y(); double r = _linewidth/2.0; - path = new XMLElementNode("circle"); + path = util::make_unique("circle"); path->addAttribute("cx", x); path->addAttribute("cy", y); path->addAttribute("r", r); @@ -553,7 +552,7 @@ void PsSpecialHandler::stroke (vector &p) { ostringstream oss; _path.writeSVG(oss, SVGTree::RELATIVE_PATH_CMDS); - path = new XMLElementNode("path"); + path = util::make_unique("path"); path->addAttribute("d", oss.str()); path->addAttribute("stroke", _actions->getColor().svgColorString()); path->addAttribute("fill", "none"); @@ -588,9 +587,9 @@ void PsSpecialHandler::stroke (vector &p) { _clipStack.setClippathLoaded(false); } if (_xmlnode) - _xmlnode->append(path); + _xmlnode->append(std::move(path)); else { - _actions->appendToPage(path); + _actions->appendToPage(std::move(path)); _actions->embed(bbox); } _path.clear(); @@ -618,7 +617,7 @@ void PsSpecialHandler::fill (vector &p, bool evenodd) { ostringstream oss; _path.writeSVG(oss, SVGTree::RELATIVE_PATH_CMDS); - XMLElementNode *path = new XMLElementNode("path"); + unique_ptr path = util::make_unique("path"); path->addAttribute("d", oss.str()); if (_pattern) path->addAttribute("fill", XMLString("url(#")+_pattern->svgID()+")"); @@ -637,9 +636,9 @@ void PsSpecialHandler::fill (vector &p, bool evenodd) { if (_opacityalpha < 1) path->addAttribute("fill-opacity", _opacityalpha); if (_xmlnode) - _xmlnode->append(path); + _xmlnode->append(std::move(path)); else { - _actions->appendToPage(path); + _actions->appendToPage(std::move(path)); _actions->embed(bbox); } _path.clear(); @@ -688,7 +687,7 @@ void PsSpecialHandler::makepattern (vector &p) { // pattern definition completed if (_savenode) { _xmlnode = _savenode; - _savenode = 0; + _savenode = nullptr; } break; case 1: { // tiling pattern @@ -705,9 +704,9 @@ void PsSpecialHandler::makepattern (vector &p) { pattern = util::make_unique(id, bbox, matrix, xstep, ystep); else pattern = util::make_unique(id, bbox, matrix, xstep, ystep); - _patterns[id] = std::move(pattern); _savenode = _xmlnode; _xmlnode = pattern->getContainerNode(); // insert the following SVG elements into this node + _patterns[id] = std::move(pattern); break; } case 2: { @@ -722,18 +721,18 @@ void PsSpecialHandler::makepattern (vector &p) { * 1-3: (optional) RGB values for uncolored tiling patterns * further parameters depend on the pattern type */ void PsSpecialHandler::setpattern (vector &p) { - int pattern_id = static_cast(p[0]); + int patternID = static_cast(p[0]); Color color; if (p.size() == 4) color.setRGB(p[1], p[2], p[3]); - auto it = _patterns.find(pattern_id); + auto it = _patterns.find(patternID); if (it == _patterns.end()) - _pattern = 0; + _pattern = nullptr; else { - if (PSUncoloredTilingPattern *pattern = dynamic_cast(it->second.get())) + if (auto *pattern = dynamic_cast(it->second.get())) pattern->setColor(color); it->second->apply(*_actions); - if (PSTilingPattern *pattern = dynamic_cast(it->second.get())) + if (auto *pattern = dynamic_cast(it->second.get())) _pattern = pattern; else _pattern = nullptr; @@ -801,19 +800,19 @@ void PsSpecialHandler::clip (Path &path, bool evenodd) { intersectedPath.writeSVG(oss, SVGTree::RELATIVE_PATH_CMDS); } - XMLElementNode *pathElem = new XMLElementNode("path"); + auto pathElem = util::make_unique("path"); pathElem->addAttribute("d", oss.str()); if (evenodd) pathElem->addAttribute("clip-rule", "evenodd"); int newID = _clipStack.topID(); - XMLElementNode *clipElem = new XMLElementNode("clipPath"); + auto clipElem = util::make_unique("clipPath"); clipElem->addAttribute("id", XMLString("clip")+XMLString(newID)); if (!COMPUTE_CLIPPATHS_INTERSECTIONS && oldID) clipElem->addAttribute("clip-path", XMLString("url(#clip")+XMLString(oldID)+")"); - clipElem->append(pathElem); - _actions->appendToDefs(clipElem); + clipElem->append(std::move(pathElem)); + _actions->appendToDefs(std::move(clipElem)); } @@ -924,12 +923,14 @@ static void read_patch_data (ShadingPatch &patch, int edgeflag, class ShadingCallback : public ShadingPatch::Callback { public: ShadingCallback (SpecialActions &actions, XMLElementNode *parent, int clippathID) - : _actions(actions), _group(new XMLElementNode("g")) + : _actions(actions) { + auto group = util::make_unique("g"); + _group = group.get(); if (parent) - parent->append(_group); + parent->append(std::move(group)); else - actions.appendToPage(_group); + actions.appendToPage(std::move(group)); if (clippathID > 0) _group->addAttribute("clip-path", XMLString("url(#clip")+XMLString(clippathID)+")"); } @@ -941,10 +942,10 @@ class ShadingCallback : public ShadingPatch::Callback { // draw a single patch segment ostringstream oss; path.writeSVG(oss, SVGTree::RELATIVE_PATH_CMDS); - XMLElementNode *pathElem = new XMLElementNode("path"); + auto pathElem = util::make_unique("path"); pathElem->addAttribute("d", oss.str()); pathElem->addAttribute("fill", color.svgColorString()); - _group->append(pathElem); + _group->append(std::move(pathElem)); } private: @@ -961,9 +962,7 @@ void PsSpecialHandler::processSequentialPatchMesh (int shadingTypeID, ColorSpace int edgeflag = static_cast(*it++); vector points; vector colors; - unique_ptr patch; - - patch = unique_ptr(ShadingPatch::create(shadingTypeID, colorSpace)); + unique_ptr patch = ShadingPatch::create(shadingTypeID, colorSpace); read_patch_data(*patch, edgeflag, it, points, colors); patch->setPoints(points, edgeflag, previousPatch.get()); patch->setColors(colors, edgeflag, previousPatch.get()); diff --git a/src/SVGCharHandler.cpp b/src/SVGCharHandler.cpp index 50215d93..264498ff 100644 --- a/src/SVGCharHandler.cpp +++ b/src/SVGCharHandler.cpp @@ -19,6 +19,7 @@ *************************************************************************/ #include "SVGCharHandler.hpp" +#include "utility.hpp" #include "XMLNode.hpp" using namespace std; @@ -30,12 +31,17 @@ void SVGCharHandler::setInitialContextNode (XMLElementNode *node) { } -/** Changes the context element. All following nodes will be appended to this node. */ -void SVGCharHandler::pushContextNode (XMLElementNode *node) { - if (node && (_contextNodeStack.empty() || node != _contextNodeStack.top())) { - contextNode()->append(node); - _contextNodeStack.push(node); +/** Changes the context element. All following nodes will be appended to this node. + * @param[in] node the new context node + * @return bare pointer to the new context node or 0 if context hasn't changed */ +XMLElementNode* SVGCharHandler::pushContextNode (unique_ptr &&node) { + if (node && (_contextNodeStack.empty() || node.get() != _contextNodeStack.top())) { + XMLElementNode *nodeptr = node.get(); + contextNode()->append(std::move(node)); + _contextNodeStack.push(nodeptr); + return nodeptr; } + return nullptr; } @@ -55,15 +61,14 @@ void SVGCharHandler::resetContextNode () { /** Creates and returns a new SVG text element. * @param[in] x current x coordinate * @param[in] y current y coordinate */ -XMLElementNode* SVGCharTextHandler::createTextNode (double x, double y) const { +unique_ptr SVGCharTextHandler::createTextNode (double x, double y) const { const Font *font = _font.get(); if (!font) - return 0; - XMLElementNode *textNode = new XMLElementNode("text"); + return nullptr; + auto textNode = util::make_unique("text"); if (_selectFontByClass) textNode->addAttribute("class", string("f")+XMLString(_fontnum)); else { - textNode->addAttribute("font-family", font->name()); textNode->addAttribute("font-size", XMLString(font->scaledSize())); if (font->color() != Color::BLACK) @@ -72,15 +77,16 @@ XMLElementNode* SVGCharTextHandler::createTextNode (double x, double y) const { if (_vertical) { textNode->addAttribute("writing-mode", "tb"); // align glyphs designed for horizontal layout properly - if (const PhysicalFont *pf = dynamic_cast(font)) + if (const PhysicalFont *pf = dynamic_cast(font)) { if (!pf->getMetrics()->verticalLayout()) { // alphabetic text designed for horizontal layout? x += pf->scaledAscent()/2.5; // move vertical baseline to the right by strikethrough offset textNode->addAttribute("glyph-orientation-vertical", 90); // ensure rotation } + } } textNode->addAttribute("x", x); textNode->addAttribute("y", y); if (!_matrix.get().isIdentity()) textNode->addAttribute("transform", _matrix.get().getSVG()); - return textNode; -} \ No newline at end of file + return std::move(textNode); +} diff --git a/src/SVGCharHandler.hpp b/src/SVGCharHandler.hpp index 5bcd92a6..06ef5016 100644 --- a/src/SVGCharHandler.hpp +++ b/src/SVGCharHandler.hpp @@ -21,6 +21,7 @@ #ifndef SVGCHARHANDLER_HPP #define SVGCHARHANDLER_HPP +#include #include #include "Color.hpp" #include "Font.hpp" @@ -73,7 +74,7 @@ class SVGCharHandler { protected: virtual void resetContextNode (); - void pushContextNode (XMLElementNode *node); + XMLElementNode* pushContextNode (std::unique_ptr &&node); void popContextNode (); XMLElementNode* contextNode () const { @@ -98,7 +99,7 @@ class SVGCharTextHandler : public SVGCharHandler { SVGCharTextHandler (bool selectFontByClass) : _selectFontByClass(selectFontByClass) {} protected: - XMLElementNode* createTextNode (double x, double y) const; + std::unique_ptr createTextNode (double x, double y) const; private: bool _selectFontByClass; diff --git a/src/SVGCharPathHandler.cpp b/src/SVGCharPathHandler.cpp index db6c2aba..09413499 100644 --- a/src/SVGCharPathHandler.cpp +++ b/src/SVGCharPathHandler.cpp @@ -22,6 +22,7 @@ #include "Font.hpp" #include "FontManager.hpp" #include "SVGCharPathHandler.hpp" +#include "utility.hpp" #include "XMLNode.hpp" using namespace std; @@ -68,8 +69,7 @@ void SVGCharPathHandler::appendChar (uint32_t c, double x, double y) { if (color.changed() || _matrix.changed()) { resetContextNode(); if (applyColor || applyMatrix) { - _groupNode = new XMLElementNode("g"); - pushContextNode(_groupNode); + _groupNode = pushContextNode(util::make_unique("g")); if (applyColor) contextNode()->addAttribute("fill", color.get().svgColorString()); if (applyMatrix) @@ -108,15 +108,14 @@ void SVGCharPathHandler::appendChar (uint32_t c, double x, double y) { void SVGCharPathHandler::appendUseElement (uint32_t c, double x, double y, const Matrix &matrix) { - ostringstream oss; - oss << "#g" << FontManager::instance().fontID(_font) << '-' << c; - XMLElementNode *useNode = new XMLElementNode("use"); + string id = "#g" + to_string(FontManager::instance().fontID(_font)) + "-" + to_string(c); + auto useNode = util::make_unique("use"); useNode->addAttribute("x", XMLString(x)); useNode->addAttribute("y", XMLString(y)); - useNode->addAttribute("xlink:href", oss.str()); + useNode->addAttribute("xlink:href", id); if (!matrix.isIdentity()) useNode->addAttribute("transform", matrix.getSVG()); - contextNode()->append(useNode); + contextNode()->append(std::move(useNode)); } @@ -128,10 +127,10 @@ void SVGCharPathHandler::appendPathElement (uint32_t c, double x, double y, cons double sy = -sx; ostringstream oss; glyph.writeSVG(oss, _relativePathCommands, sx, sy, x, y); - XMLElementNode *glyphNode = new XMLElementNode("path"); + auto glyphNode = util::make_unique("path"); glyphNode->addAttribute("d", oss.str()); if (!matrix.isIdentity()) glyphNode->addAttribute("transform", matrix.getSVG()); - contextNode()->append(glyphNode); + contextNode()->append(std::move(glyphNode)); } } diff --git a/src/SVGCharTspanTextHandler.cpp b/src/SVGCharTspanTextHandler.cpp index d9432971..c22eb84e 100644 --- a/src/SVGCharTspanTextHandler.cpp +++ b/src/SVGCharTspanTextHandler.cpp @@ -19,6 +19,7 @@ *************************************************************************/ #include "SVGCharTspanTextHandler.hpp" +#include "utility.hpp" #include "XMLNode.hpp" using namespace std; @@ -34,8 +35,7 @@ void SVGCharTspanTextHandler::appendChar (uint32_t c, double x, double y) { // changes of fonts and transformations require a new text element if (!_textNode || _font.changed() || _matrix.changed() || _vertical.changed()) { resetContextNode(); - _textNode = createTextNode(x, y); - pushContextNode(_textNode); + _textNode = pushContextNode(createTextNode(x, y)); _color.changed(true); // force creating tspan with color attribute if current color differs from font color } if (_tspanNode && (_xchanged || _ychanged || _color.changed())) { @@ -47,8 +47,7 @@ void SVGCharTspanTextHandler::appendChar (uint32_t c, double x, double y) { // Glyphs of non-black fonts (e.g. defined in a XeTeX document) can't change their color. bool applyColor = _color.get() != Color::BLACK && _font.get()->color() == Color::BLACK; if (_xchanged || _ychanged || (_color.changed() && applyColor)) { - _tspanNode = new XMLElementNode("tspan"); - pushContextNode(_tspanNode); + _tspanNode = pushContextNode(util::make_unique("tspan")); if (applyColor) _tspanNode->addAttribute("fill", _color.get().svgColorString()); _color.changed(false); diff --git a/src/SVGSingleCharTextHandler.cpp b/src/SVGSingleCharTextHandler.cpp index af99de0d..8dd1764f 100644 --- a/src/SVGSingleCharTextHandler.cpp +++ b/src/SVGSingleCharTextHandler.cpp @@ -25,7 +25,7 @@ using namespace std; void SVGSingleCharTextHandler::appendChar (uint32_t c, double x, double y) { const Font *font = _font.get(); - XMLElementNode *textNode = createTextNode(x, y); + auto textNode = createTextNode(x, y); textNode->append(XMLString(font->unicode(c), false)); // Apply color changes only if the color differs from black and if the font color itself is black. // Glyphs from non-black fonts (e.g. defined in a XeTeX document) can't change their color. @@ -33,5 +33,5 @@ void SVGSingleCharTextHandler::appendChar (uint32_t c, double x, double y) { textNode->addAttribute("fill", _color.get().svgColorString()); _color.changed(false); } - contextNode()->append(textNode); + contextNode()->append(std::move(textNode)); } diff --git a/src/SVGTree.cpp b/src/SVGTree.cpp index d434fd30..52cd933f 100644 --- a/src/SVGTree.cpp +++ b/src/SVGTree.cpp @@ -57,11 +57,12 @@ SVGTree::SVGTree () { /** Clears the SVG tree and initializes the root element. */ void SVGTree::reset () { _doc.clear(); - _root = new XMLElementNode("svg"); - _root->addAttribute("version", "1.1"); - _root->addAttribute("xmlns", "http://www.w3.org/2000/svg"); - _root->addAttribute("xmlns:xlink", "http://www.w3.org/1999/xlink"); - _doc.setRootNode(_root); + auto rootNode = util::make_unique("svg"); + rootNode->addAttribute("version", "1.1"); + rootNode->addAttribute("xmlns", "http://www.w3.org/2000/svg"); + rootNode->addAttribute("xmlns:xlink", "http://www.w3.org/1999/xlink"); + _root = rootNode.get(); + _doc.setRootNode(std::move(rootNode)); _page = _defs = nullptr; _styleCDataNode = nullptr; } @@ -112,37 +113,39 @@ bool SVGTree::setFontFormat (string formatstr) { /** Starts a new page. * @param[in] pageno number of new page */ void SVGTree::newPage (int pageno) { - _page = new XMLElementNode("g"); + auto pageNode = util::make_unique("g"); if (pageno >= 0) - _page->addAttribute("id", string("page")+XMLString(pageno)); - _root->append(_page); - _charHandler->setInitialContextNode(_page); + pageNode->addAttribute("id", string("page")+XMLString(pageno)); + _charHandler->setInitialContextNode(pageNode.get()); + _page = pageNode.get(); + _root->append(std::move(pageNode)); while (!_contextElementStack.empty()) _contextElementStack.pop(); } -void SVGTree::appendToDefs (XMLNode *node) { +void SVGTree::appendToDefs (unique_ptr &&node) { if (!_defs) { - _defs = new XMLElementNode("defs"); - _root->prepend(_defs); + auto defsNode = util::make_unique("defs"); + _defs = defsNode.get(); + _root->prepend(std::move(defsNode)); } - _defs->append(node); + _defs->append(std::move(node)); } -void SVGTree::appendToPage (XMLNode *node) { +void SVGTree::appendToPage (unique_ptr &&node) { XMLElementNode *parent = _contextElementStack.empty() ? _page : _contextElementStack.top(); - parent->append(node); + parent->append(std::move(node)); _charHandler->setInitialContextNode(parent); } -void SVGTree::prependToPage (XMLNode *node) { +void SVGTree::prependToPage (unique_ptr &&node) { if (_contextElementStack.empty()) - _page->prepend(node); + _page->prepend(std::move(node)); else - _contextElementStack.top()->prepend(node); + _contextElementStack.top()->prepend(std::move(node)); } @@ -157,36 +160,34 @@ void SVGTree::transformPage (const Matrix &usermatrix) { * @param[in] font font to extract the glyph from * @param[in] cb pointer to callback object for sending feedback to the glyph tracer (may be 0) * @return pointer to element node if glyph exists, 0 otherwise */ -static XMLElementNode* createGlyphNode (int c, const PhysicalFont &font, GFGlyphTracer::Callback *cb) { +static unique_ptr createGlyphNode (int c, const PhysicalFont &font, GFGlyphTracer::Callback *cb) { Glyph glyph; if (!font.getGlyph(c, glyph, cb) || (!SVGTree::USE_FONTS && !SVGTree::CREATE_USE_ELEMENTS)) - return 0; + return nullptr; double sx=1.0, sy=1.0; double upem = font.unitsPerEm(); - XMLElementNode *glyph_node=0; + unique_ptr glyphNode; if (SVGTree::USE_FONTS) { double extend = font.style() ? font.style()->extend : 1; - glyph_node = new XMLElementNode("glyph"); - glyph_node->addAttribute("unicode", XMLString(font.unicode(c), false)); - glyph_node->addAttribute("horiz-adv-x", XMLString(font.hAdvance(c)*extend)); - glyph_node->addAttribute("vert-adv-y", XMLString(font.vAdvance(c))); + glyphNode = util::make_unique("glyph"); + glyphNode->addAttribute("unicode", XMLString(font.unicode(c), false)); + glyphNode->addAttribute("horiz-adv-x", XMLString(font.hAdvance(c)*extend)); + glyphNode->addAttribute("vert-adv-y", XMLString(font.vAdvance(c))); string name = font.glyphName(c); if (!name.empty()) - glyph_node->addAttribute("glyph-name", name); + glyphNode->addAttribute("glyph-name", name); } else { - ostringstream oss; - oss << 'g' << FontManager::instance().fontID(&font) << '-' << c; - glyph_node = new XMLElementNode("path"); - glyph_node->addAttribute("id", oss.str()); + glyphNode = util::make_unique("path"); + glyphNode->addAttribute("id", "g"+to_string(FontManager::instance().fontID(&font))+"-"+to_string(c)); sx = font.scaledSize()/upem; sy = -sx; } ostringstream oss; glyph.writeSVG(oss, SVGTree::RELATIVE_PATH_CMDS, sx, sy); - glyph_node->addAttribute("d", oss.str()); - return glyph_node; + glyphNode->addAttribute("d", oss.str()); + return std::move(glyphNode); } @@ -255,24 +256,24 @@ void SVGTree::append (const PhysicalFont &font, const set &chars, GFGlyphTr if (ADD_COMMENTS) { string info = font_info(font); if (!info.empty()) - appendToDefs(new XMLCommentNode(string(" font: ")+info+" ")); + appendToDefs(util::make_unique(string(" font: ")+info+" ")); } - XMLElementNode *fontNode = new XMLElementNode("font"); + auto fontNode = util::make_unique("font"); string fontname = font.name(); fontNode->addAttribute("id", fontname); fontNode->addAttribute("horiz-adv-x", XMLString(font.hAdvance())); - appendToDefs(fontNode); - XMLElementNode *faceNode = new XMLElementNode("font-face"); + auto faceNode = util::make_unique("font-face"); faceNode->addAttribute("font-family", fontname); faceNode->addAttribute("units-per-em", XMLString(font.unitsPerEm())); if (!font.verticalLayout()) { faceNode->addAttribute("ascent", XMLString(font.ascent())); faceNode->addAttribute("descent", XMLString(font.descent())); } - fontNode->append(faceNode); + fontNode->append(std::move(faceNode)); for (int c : chars) fontNode->append(createGlyphNode(c, font, callback)); + appendToDefs(std::move(fontNode)); } } else if (CREATE_USE_ELEMENTS && &font != font.uniqueFont()) { @@ -281,20 +282,13 @@ void SVGTree::append (const PhysicalFont &font, const set &chars, GFGlyphTr // reference the already embedded path together with a transformation attribute and let the SVG renderer // scale the glyphs properly. This is only necessary if we don't want to use font but path elements. for (int c : chars) { - ostringstream oss; - XMLElementNode *use = new XMLElementNode("use"); - oss << 'g' << FontManager::instance().fontID(&font) << '-' << c; - use->addAttribute("id", oss.str()); - oss.str(""); - oss << "#g" << FontManager::instance().fontID(font.uniqueFont()) << '-' << c; - use->addAttribute("xlink:href", oss.str()); + auto useNode = util::make_unique("use"); + useNode->addAttribute("id", "g"+to_string(FontManager::instance().fontID(&font))+"-"+to_string(c)); + useNode->addAttribute("xlink:href", "#g"+to_string(FontManager::instance().fontID(font.uniqueFont()))+"-"+to_string(c)); double scale = font.scaledSize()/font.uniqueFont()->scaledSize(); - if (scale != 1.0) { - oss.str(""); - oss << "scale(" << scale << ')'; - use->addAttribute("transform", oss.str()); - } - appendToDefs(use); + if (scale != 1.0) + useNode->addAttribute("transform", "scale("+XMLString(scale)+")"); + appendToDefs(std::move(useNode)); } } else { @@ -305,13 +299,14 @@ void SVGTree::append (const PhysicalFont &font, const set &chars, GFGlyphTr /** Pushes a new context element that will take all following nodes added to the page. */ -void SVGTree::pushContextElement (XMLElementNode *node) { +void SVGTree::pushContextElement (unique_ptr &&node) { + XMLElementNode *nodePtr = node.get(); if (_contextElementStack.empty()) - _page->append(node); + _page->append(std::move(node)); else - _contextElementStack.top()->append(node); - _contextElementStack.push(node); - _charHandler->setInitialContextNode(node); + _contextElementStack.top()->append(std::move(node)); + _contextElementStack.push(nodePtr); + _charHandler->setInitialContextNode(nodePtr); } @@ -364,11 +359,12 @@ void SVGTree::removeRedundantElements () { XMLCDataNode* SVGTree::styleCDataNode () { if (!_styleCDataNode) { - XMLElementNode *styleNode = new XMLElementNode("style"); + auto styleNode = util::make_unique("style"); styleNode->addAttribute("type", "text/css"); - _root->insertBefore(styleNode, _page); - _styleCDataNode = new XMLCDataNode; - styleNode->append(_styleCDataNode); + auto cdataNode = util::make_unique(); + _styleCDataNode = cdataNode.get(); + styleNode->append(std::move(cdataNode)); + _root->insertBefore(std::move(styleNode), _page); } return _styleCDataNode; } diff --git a/src/SVGTree.hpp b/src/SVGTree.hpp index 7b1e1aad..f659db73 100644 --- a/src/SVGTree.hpp +++ b/src/SVGTree.hpp @@ -46,15 +46,15 @@ class SVGTree { void reset (); bool write (std::ostream &os) const {return bool(_doc.write(os));} void newPage (int pageno); - void appendToDefs (XMLNode *node); - void appendToPage (XMLNode *node); - void prependToPage (XMLNode *node); - void appendToDoc (XMLNode *node) {_doc.append(node);} - void appendToRoot (XMLNode *node) {_root->append(node);} + void appendToDefs (std::unique_ptr &&node); + void appendToPage (std::unique_ptr &&node); + void prependToPage (std::unique_ptr &&node); + void appendToDoc (std::unique_ptr &&node) {_doc.append(std::move(node));} + void appendToRoot (std::unique_ptr &&node) {_root->append(std::move(node));} void appendChar (int c, double x, double y) {_charHandler->appendChar(c, x, y);} void appendFontStyles (const std::unordered_set &fonts); void append (const PhysicalFont &font, const std::set &chars, GFGlyphTracer::Callback *callback=0); - void pushContextElement (XMLElementNode *node); + void pushContextElement (std::unique_ptr &&node); void popContextElement (); void removeRedundantElements (); void setBBox (const BoundingBox &bbox); diff --git a/src/ShadingPatch.hpp b/src/ShadingPatch.hpp index a917791e..ad021186 100644 --- a/src/ShadingPatch.hpp +++ b/src/ShadingPatch.hpp @@ -27,8 +27,7 @@ #include "MessageException.hpp" -class ShadingPatch -{ +class ShadingPatch { public: struct Callback { virtual ~Callback () =default; @@ -63,8 +62,7 @@ class ShadingPatch }; -struct ShadingException : public MessageException -{ +struct ShadingException : public MessageException { ShadingException (const std::string &msg) : MessageException(msg) {} }; diff --git a/src/SpecialActions.hpp b/src/SpecialActions.hpp index 5dfaaa17..f47030f2 100644 --- a/src/SpecialActions.hpp +++ b/src/SpecialActions.hpp @@ -22,6 +22,7 @@ #define SPECIALACTIONS_HPP #include +#include #include "BoundingBox.hpp" #include "Color.hpp" #include "Matrix.hpp" @@ -29,8 +30,7 @@ class XMLNode; class XMLElementNode; -class SpecialActions -{ +class SpecialActions { public: virtual ~SpecialActions () =default; virtual double getX () const =0; @@ -44,10 +44,10 @@ class SpecialActions virtual const Matrix& getMatrix () const =0; virtual void getPageTransform (Matrix &matrix) const =0; virtual void setBgColor (const Color &color) =0; - virtual void appendToPage (XMLNode *node) =0; - virtual void appendToDefs (XMLNode *node) =0; - virtual void prependToPage (XMLNode *node) =0; - virtual void pushContextElement (XMLElementNode *node) =0; + virtual void appendToPage(std::unique_ptr &&node) =0; + virtual void appendToDefs(std::unique_ptr &&node) =0; + virtual void prependToPage(std::unique_ptr &&node) =0; + virtual void pushContextElement (std::unique_ptr &&node) =0; virtual void popContextElement () =0; virtual BoundingBox& bbox () =0; virtual BoundingBox& bbox (const std::string &name, bool reset=false) =0; @@ -63,8 +63,7 @@ class SpecialActions }; -class EmptySpecialActions : public SpecialActions -{ +class EmptySpecialActions : public SpecialActions { public: double getX () const override {return 0;} double getY () const override {return 0;} @@ -77,10 +76,10 @@ class EmptySpecialActions : public SpecialActions void setMatrix (const Matrix &m) override {} const Matrix& getMatrix () const override {return _matrix;} void getPageTransform (Matrix &matrix) const override {} - void appendToPage (XMLNode *node) override {} - void appendToDefs (XMLNode *node) override {} - void prependToPage (XMLNode *node) override {} - void pushContextElement (XMLElementNode *node) override {} + void appendToPage(std::unique_ptr &&node) override {} + void appendToDefs(std::unique_ptr &&node) override {} + void prependToPage(std::unique_ptr &&node) override {} + void pushContextElement (std::unique_ptr &&node) override {} void popContextElement () override {} BoundingBox& bbox () override {return _bbox;} BoundingBox& bbox (const std::string &name, bool reset=false) override {return _bbox;} diff --git a/src/TpicSpecialHandler.cpp b/src/TpicSpecialHandler.cpp index 0ef78901..accf061e 100644 --- a/src/TpicSpecialHandler.cpp +++ b/src/TpicSpecialHandler.cpp @@ -81,9 +81,9 @@ static void add_stroke_attribs (XMLElementNode *elem, double penwidth, Color pen } -static XMLElementNode* create_ellipse_element (double cx, double cy, double rx, double ry) { +static unique_ptr create_ellipse_element (double cx, double cy, double rx, double ry) { bool is_circle = (rx == ry); - XMLElementNode *elem = new XMLElementNode(is_circle ? "circle" : "ellipse"); + auto elem = util::make_unique(is_circle ? "circle" : "ellipse"); elem->addAttribute("cx", XMLString(cx)); elem->addAttribute("cy", XMLString(cy)); if (is_circle) @@ -92,7 +92,7 @@ static XMLElementNode* create_ellipse_element (double cx, double cy, double rx, elem->addAttribute("rx", XMLString(rx)); elem->addAttribute("ry", XMLString(ry)); } - return elem; + return std::move(elem); } @@ -101,7 +101,7 @@ static XMLElementNode* create_ellipse_element (double cx, double cy, double rx, * @param[in] actions object providing the actions that can be performed by the SpecialHandler */ void TpicSpecialHandler::drawLines (double ddist, SpecialActions &actions) { if (!_points.empty() && (_penwidth > 0 || _grayLevel >= 0)) { - XMLElementNode *elem=0; + unique_ptr elem; if (_points.size() == 1) { const DPair &p = _points.back(); elem = create_ellipse_element(p.x()+actions.getX(), p.y()+actions.getY(), _penwidth/2.0, _penwidth/2.0); @@ -109,14 +109,14 @@ void TpicSpecialHandler::drawLines (double ddist, SpecialActions &actions) { } else { if (_points.size() == 2 || (_grayLevel < 0 && _points.front() != _points.back())) { - elem = new XMLElementNode("polyline"); + elem = util::make_unique("polyline"); elem->addAttribute("fill", "none"); elem->addAttribute("stroke-linecap", "round"); } else { while (_points.front() == _points.back()) _points.pop_back(); - elem = new XMLElementNode("polygon"); + elem = util::make_unique("polygon"); elem->addAttribute("fill", _grayLevel < 0 ? "none" : fillColor(false).svgColorString()); } ostringstream oss; @@ -129,9 +129,9 @@ void TpicSpecialHandler::drawLines (double ddist, SpecialActions &actions) { actions.embed(DPair(x, y)); } elem->addAttribute("points", oss.str()); - add_stroke_attribs(elem, _penwidth, Color::BLACK, ddist); + add_stroke_attribs(elem.get(), _penwidth, Color::BLACK, ddist); } - actions.appendToPage(elem); + actions.appendToPage(std::move(elem)); } reset(); } @@ -174,13 +174,13 @@ void TpicSpecialHandler::drawSplines (double ddist, SpecialActions &actions) { path.lineto(p+_points[numPoints-1]); actions.embed(p+_points[numPoints-1]); } - XMLElementNode *pathElem = new XMLElementNode("path"); + auto pathElem = util::make_unique("path"); pathElem->addAttribute("fill", "none"); ostringstream oss; path.writeSVG(oss, SVGTree::RELATIVE_PATH_CMDS); pathElem->addAttribute("d", oss.str()); - add_stroke_attribs(pathElem, _penwidth, _dviColor, ddist); - actions.appendToPage(pathElem); + add_stroke_attribs(pathElem.get(), _penwidth, _dviColor, ddist); + actions.appendToPage(std::move(pathElem)); } } reset(); @@ -209,7 +209,7 @@ void TpicSpecialHandler::drawArc (double cx, double cy, double rx, double ry, do angle2 = -angle2; cx += actions.getX(); cy += actions.getY(); - XMLElementNode *elem=0; + unique_ptr elem; bool closed=true; if (abs(angle2-angle1) >= math::TWO_PI) // closed ellipse? elem = create_ellipse_element(cx, cy, rx, ry); @@ -228,7 +228,7 @@ void TpicSpecialHandler::drawArc (double cx, double cy, double rx, double ry, do oss << 'Z'; else closed = false; - elem = new XMLElementNode("path"); + elem = util::make_unique("path"); elem->addAttribute("d", oss.str()); } if (_penwidth > 0) { @@ -238,7 +238,7 @@ void TpicSpecialHandler::drawArc (double cx, double cy, double rx, double ry, do elem->addAttribute("stroke-linecap", "round"); } elem->addAttribute("fill", _grayLevel < 0 ? "none" : fillColor(true).svgColorString()); - actions.appendToPage(elem); + actions.appendToPage(std::move(elem)); double pw = _penwidth/2.0; actions.embed(BoundingBox(cx-rx-pw, cy-ry-pw, cx+rx+pw, cy+ry+pw)); } diff --git a/src/XMLDocument.cpp b/src/XMLDocument.cpp index 3c6a167f..56457c69 100644 --- a/src/XMLDocument.cpp +++ b/src/XMLDocument.cpp @@ -22,8 +22,8 @@ using namespace std; -XMLDocument::XMLDocument (XMLElementNode *root) - : _rootElement(root) +XMLDocument::XMLDocument (unique_ptr &&root) + : _rootElement(std::move(root)) { } @@ -34,18 +34,18 @@ void XMLDocument::clear () { } -void XMLDocument::append (XMLNode *node) { +void XMLDocument::append (unique_ptr &&node) { if (node) { - if (XMLElementNode *newRoot = dynamic_cast(node)) - _rootElement.reset(newRoot); + if (dynamic_cast(node.get())) + _rootElement = util::static_unique_ptr_cast(std::move(node)); else - _nodes.emplace_back(unique_ptr(node)); + _nodes.emplace_back(std::move(node)); } } -void XMLDocument::setRootNode (XMLElementNode *root) { - _rootElement.reset(root); +void XMLDocument::setRootNode (unique_ptr &&root) { + _rootElement = std::move(root); } diff --git a/src/XMLDocument.hpp b/src/XMLDocument.hpp index d8590b8b..1c402e26 100644 --- a/src/XMLDocument.hpp +++ b/src/XMLDocument.hpp @@ -24,13 +24,14 @@ #include #include "XMLNode.hpp" -class XMLDocument -{ +class XMLDocument { public: - XMLDocument (XMLElementNode *root=0); + XMLDocument () =default; + XMLDocument (std::unique_ptr &&root); void clear (); - void append (XMLNode *node); - void setRootNode (XMLElementNode *root); + void append (std::unique_ptr &&node); + void append (std::unique_ptr &&node); + void setRootNode (std::unique_ptr &&root); const XMLElementNode* getRootElement () const {return _rootElement.get();} std::ostream& write (std::ostream &os) const; diff --git a/src/XMLNode.cpp b/src/XMLNode.cpp index aa9dcae6..7966dcfc 100644 --- a/src/XMLNode.cpp +++ b/src/XMLNode.cpp @@ -53,50 +53,62 @@ void XMLElementNode::clear () { void XMLElementNode::addAttribute (const string &name, const string &value) { - _attributes[name] = value; + _attributes.emplace(name, value); } void XMLElementNode::addAttribute (const string &name, double value) { - _attributes[name] = XMLString(value); + _attributes.emplace(name, XMLString(value)); } -void XMLElementNode::append (XMLNode *child) { +/** Appends a child node to this element. The element also takes the ownership of the child. + * @param[in] child node to be appended + * @return raw pointer to the appended child node */ +XMLNode* XMLElementNode::append (unique_ptr &&child) { if (!child) - return; - XMLTextNode *textNode1 = dynamic_cast(child); + return nullptr; + XMLTextNode *textNode1 = dynamic_cast(child.get()); if (!textNode1 || _children.empty()) - _children.emplace_back(unique_ptr(child)); + _children.emplace_back(std::move(child)); else { if (XMLTextNode *textNode2 = dynamic_cast(_children.back().get())) - textNode2->append(textNode1); // merge two consecutive text nodes + textNode2->append(util::static_unique_ptr_cast(std::move(child))); // merge two consecutive text nodes else - _children.emplace_back(unique_ptr(child)); + _children.emplace_back(std::move(child)); } + return _children.back().get(); } -void XMLElementNode::append (const string &str) { +/** Appends a string to this element. If the last child is a text node, the string is + * appended there, otherwise a new text node is created. + * @param[in] str string to be appended + * @return raw pointer to the text node the string was appended to */ +XMLNode* XMLElementNode::append (const string &str) { if (_children.empty() || !dynamic_cast(_children.back().get())) _children.emplace_back(util::make_unique(str)); else static_cast(_children.back().get())->append(str); + return _children.back().get(); } -void XMLElementNode::prepend (XMLNode *child) { +/** Prepends a child node to this element. The element also takes the ownership of the child. + * @param[in] child node to be prepended + * @return raw pointer to the prepended child node */ +XMLNode* XMLElementNode::prepend (unique_ptr &&child) { if (!child) - return; - XMLTextNode *textNode1 = dynamic_cast(child); - unique_ptr child_uptr(child); + return nullptr; + XMLTextNode *textNode1 = dynamic_cast(child.get()); if (textNode1 && !_children.empty()) { if (XMLTextNode *textNode2 = dynamic_cast(_children.front().get())) { - textNode2->prepend(textNode1); // merge two consecutive text nodes - return; + textNode2->prepend(util::static_unique_ptr_cast(std::move(child))); // merge two consecutive text nodes + return textNode2; } } - _children.emplace_front(std::move(child_uptr)); + _children.emplace_front(std::move(child)); + return _children.front().get(); } @@ -106,13 +118,13 @@ void XMLElementNode::prepend (XMLNode *child) { * @param[in] child node to be inserted * @param[in] sibling following sibling of 'child' * @return true on success */ -bool XMLElementNode::insertBefore (XMLNode *child, XMLNode *sibling) { +bool XMLElementNode::insertBefore (unique_ptr &&child, XMLNode *sibling) { auto it = _children.begin(); while (it != _children.end() && it->get() != sibling) ++it; if (it == _children.end()) return false; - _children.emplace(it, unique_ptr(child)); + _children.emplace(it, std::move(child)); return true; } @@ -123,13 +135,13 @@ bool XMLElementNode::insertBefore (XMLNode *child, XMLNode *sibling) { * @param[in] child node to be inserted * @param[in] sibling preceding sibling of 'child' * @return true on success */ -bool XMLElementNode::insertAfter (XMLNode *child, XMLNode *sibling) { +bool XMLElementNode::insertAfter (unique_ptr &&child, XMLNode *sibling) { auto it = _children.begin(); while (it != _children.end() && it->get() != sibling) ++it; if (it == _children.end()) return false; - _children.emplace(++it, unique_ptr(child)); + _children.emplace(++it, std::move(child)); return true; } @@ -225,25 +237,23 @@ const char* XMLElementNode::getAttributeValue(const std::string& name) const { ////////////////////// -void XMLTextNode::append (XMLNode *node) { +void XMLTextNode::append (unique_ptr &&node) { if (!node) return; - if (XMLTextNode *tn = dynamic_cast(node)) - append(tn); + if (dynamic_cast(node.get())) + append(util::static_unique_ptr_cast(std::move(node))); else { // append text representation of the node ostringstream oss; node->write(oss); append(XMLString(oss.str())); - delete node; } } -void XMLTextNode::append (XMLTextNode *node) { +void XMLTextNode::append (unique_ptr &&node) { if (node) _text += node->_text; - delete node; } @@ -252,16 +262,12 @@ void XMLTextNode::append (const string &str) { } -void XMLTextNode::prepend (XMLNode *node) { - if (XMLTextNode *tn = dynamic_cast(node)) - _text = tn->_text + _text; - else - delete node; +void XMLTextNode::prepend (unique_ptr &&node) { + if (XMLTextNode *textNode = dynamic_cast(node.get())) + _text = textNode->_text + _text; } - -////////////////////// - +///////////////////////////////////////////////////////////////////// ostream& XMLCDataNode::write (ostream &os) const { if (!_data.empty()) diff --git a/src/XMLNode.hpp b/src/XMLNode.hpp index 3352cb89..08ca2ca0 100644 --- a/src/XMLNode.hpp +++ b/src/XMLNode.hpp @@ -27,12 +27,13 @@ #include #include #include +#include "utility.hpp" class XMLNode { public: virtual ~XMLNode () =default; - virtual XMLNode* clone () const =0; + virtual std::unique_ptr clone () const =0; virtual void clear () =0; virtual std::ostream& write (std::ostream &os) const =0; }; @@ -47,16 +48,16 @@ class XMLElementNode : public XMLNode { XMLElementNode (const std::string &name); XMLElementNode (const XMLElementNode &node); XMLElementNode (XMLElementNode &&node); - XMLElementNode* clone () const override {return new XMLElementNode(*this);} + std::unique_ptr clone () const override {return util::make_unique(*this);} void clear () override; void addAttribute (const std::string &name, const std::string &value); void addAttribute (const std::string &name, double value); - void append (XMLNode *child); - void append (const std::string &str); - void prepend (XMLNode *child); + XMLNode* append (std::unique_ptr &&child); + XMLNode* append (const std::string &str); + XMLNode* prepend (std::unique_ptr &&child); void remove (const XMLNode *child); - bool insertAfter (XMLNode *child, XMLNode *sibling); - bool insertBefore (XMLNode *child, XMLNode *sibling); + bool insertAfter (std::unique_ptr &&child, XMLNode *sibling); + bool insertBefore (std::unique_ptr &&child, XMLNode *sibling); bool hasAttribute (const std::string &name) const; const char* getAttributeValue (const std::string &name) const; bool getDescendants (const char *name, const char *attrName, std::vector &descendants) const; @@ -77,12 +78,12 @@ class XMLTextNode : public XMLNode { public: XMLTextNode (const std::string &str) : _text(str) {} XMLTextNode (std::string &&str) : _text(std::move(str)) {} - XMLTextNode* clone () const override {return new XMLTextNode(*this);} + std::unique_ptr clone () const override {return util::make_unique(*this);} void clear () override {_text.clear();} - void append (XMLNode *node); - void append (XMLTextNode *node); + void append (std::unique_ptr &&node); + void append (std::unique_ptr &&node); void append (const std::string &str); - void prepend (XMLNode *child); + void prepend (std::unique_ptr &&node); std::ostream& write (std::ostream &os) const override {return os << _text;} const std::string& getText () const {return _text;} @@ -95,7 +96,7 @@ class XMLCommentNode : public XMLNode { public: XMLCommentNode (const std::string &str) : _text(str) {} XMLCommentNode (std::string &&str) : _text(std::move(str)) {} - XMLCommentNode* clone () const override {return new XMLCommentNode(*this);} + std::unique_ptr clone () const override {return util::make_unique(*this);} void clear () override {_text.clear();} std::ostream& write (std::ostream &os) const override {return os << "";} @@ -109,7 +110,7 @@ class XMLCDataNode : public XMLNode { XMLCDataNode () =default; XMLCDataNode (const std::string &d) : _data(d) {} XMLCDataNode (std::string &&d) : _data(std::move(d)) {} - XMLCDataNode* clone () const override {return new XMLCDataNode(*this);} + std::unique_ptr clone () const override {return util::make_unique(*this);} void clear () override {_data.clear();} void append (std::string &&str); std::ostream& write (std::ostream &os) const override; diff --git a/src/utility.hpp b/src/utility.hpp index d302a783..c9bd2002 100644 --- a/src/utility.hpp +++ b/src/utility.hpp @@ -94,6 +94,12 @@ std::unique_ptr make_unique (Args&&... args) { return std::unique_ptr(new T(std::forward(args)...)); } + +template +std::unique_ptr static_unique_ptr_cast (std::unique_ptr &&old){ + return std::unique_ptr{static_cast(old.release())}; +} + } // namespace util #endif diff --git a/tests/DvisvgmSpecialTest.cpp b/tests/DvisvgmSpecialTest.cpp index d7c14cc8..901b2b2f 100644 --- a/tests/DvisvgmSpecialTest.cpp +++ b/tests/DvisvgmSpecialTest.cpp @@ -27,8 +27,7 @@ using namespace std; -class MyDvisvgmSpecialHandler : public DvisvgmSpecialHandler -{ +class MyDvisvgmSpecialHandler : public DvisvgmSpecialHandler { public: void finishPreprocessing () {dviPreprocessingFinished();} void finishPage () {dviEndPage(0, emptyActions);} @@ -38,25 +37,23 @@ class MyDvisvgmSpecialHandler : public DvisvgmSpecialHandler }; -class DvisvgmSpecialTest : public ::testing::Test -{ +class DvisvgmSpecialTest : public ::testing::Test { protected: - class ActionsRecorder : public EmptySpecialActions - { + class ActionsRecorder : public EmptySpecialActions { public: ActionsRecorder () : defs(""), page("") {} - void appendToDefs (XMLNode *node) {defs.append(node);} - void appendToPage (XMLNode *node) {page.append(node);} - void embed (const BoundingBox &bb) {bbox.embed(bb);} - double getX () const {return 0;} - double getY () const {return 0;} - void clear () {defs.clear(); page.clear(); bbox=BoundingBox(0, 0, 0, 0);} - bool defsEquals (const string &str) const {return defs.getText() == str;} - bool pageEquals (const string &str) const {return page.getText() == str;} - bool bboxEquals (const string &str) const {return bbox.toSVGViewBox() == str;} - const Matrix& getMatrix () const {static Matrix m(1); return m;} - string bboxString () const {return bbox.toSVGViewBox();} - string pageString () const {return page.getText();} + void appendToDefs(unique_ptr &&node) override {defs.append(std::move(node));} + void appendToPage(unique_ptr &&node) override {page.append(std::move(node));} + void embed (const BoundingBox &bb) override {bbox.embed(bb);} + double getX () const override {return 0;} + double getY () const override {return 0;} + void clear () {defs.clear(); page.clear(); bbox=BoundingBox(0, 0, 0, 0);} + bool defsEquals (const string &str) const {return defs.getText() == str;} + bool pageEquals (const string &str) const {return page.getText() == str;} + bool bboxEquals (const string &str) const {return bbox.toSVGViewBox() == str;} + const Matrix& getMatrix () const override {static Matrix m(1); return m;} + string bboxString () const {return bbox.toSVGViewBox();} + string pageString () const {return page.getText();} void write (ostream &os) const { os << "defs: " << defs.getText() << '\n' diff --git a/tests/EmSpecialTest.cpp b/tests/EmSpecialTest.cpp index 36e698ae..fcb48977 100644 --- a/tests/EmSpecialTest.cpp +++ b/tests/EmSpecialTest.cpp @@ -28,24 +28,22 @@ using namespace std; -class EmSpecialTest : public ::testing::Test -{ +class EmSpecialTest : public ::testing::Test { protected: - class ActionsRecorder : public EmptySpecialActions - { + class ActionsRecorder : public EmptySpecialActions { public: ActionsRecorder () : page("page") {} - void appendToPage (XMLNode *node) {page.append(node);} - void embed (const BoundingBox &bb) {bbox.embed(bb);} - void setX (double xx) {x = xx;} - void setY (double yy) {x = yy;} - double getX () const {return x;} - double getY () const {return y;} - Color getColor () const {return color;} - void setColor (const Color &c) {color = c;} - void clear () {page.clear(); bbox=BoundingBox(0, 0, 0, 0);} - string getPageXML () const {ostringstream oss; oss << page; return oss.str();} - const Matrix& getMatrix () const {static Matrix m(1); return m;} + void appendToPage(unique_ptr &&node) {page.append(std::move(node));} + void embed (const BoundingBox &bb) {bbox.embed(bb);} + void setX (double xx) {x = xx;} + void setY (double yy) {x = yy;} + double getX () const {return x;} + double getY () const {return y;} + Color getColor () const {return color;} + void setColor (const Color &c) {color = c;} + void clear () {page.clear(); bbox=BoundingBox(0, 0, 0, 0);} + string getPageXML () const {ostringstream oss; oss << page; return oss.str();} + const Matrix& getMatrix () const {static Matrix m(1); return m;} void write (ostream &os) const { os << "page: " << page << '\n' @@ -60,8 +58,7 @@ class EmSpecialTest : public ::testing::Test }; - class MyEmSpecialHandler : public EmSpecialHandler - { + class MyEmSpecialHandler : public EmSpecialHandler { public: MyEmSpecialHandler (SpecialActions &a) : actions(a) {} void finishPage () {dviEndPage(0, actions);} diff --git a/tests/TpicSpecialTest.cpp b/tests/TpicSpecialTest.cpp index 04505937..261f0153 100644 --- a/tests/TpicSpecialTest.cpp +++ b/tests/TpicSpecialTest.cpp @@ -34,16 +34,16 @@ class TpicSpecialTest : public ::testing::Test { class ActionsRecorder : public EmptySpecialActions { public: ActionsRecorder () : page("page") {} - void appendToPage (XMLNode *node) {page.append(node);} - void embed (const BoundingBox &bb) {bbox.embed(bb);} - void setX (double xx) {x = xx;} - void setY (double yy) {x = yy;} - double getX () const {return x;} - double getY () const {return y;} - Color getColor () const {return color;} - void setColor (const Color &c) {color = c;} - void clear () {page.clear(); bbox=BoundingBox(0, 0, 0, 0);} - const Matrix& getMatrix () const {static Matrix m(1); return m;} + void appendToPage(unique_ptr &&node) {page.append(std::move(node));} + void embed (const BoundingBox &bb) {bbox.embed(bb);} + void setX (double xx) {x = xx;} + void setY (double yy) {x = yy;} + double getX () const {return x;} + double getY () const {return y;} + Color getColor () const {return color;} + void setColor (const Color &c) {color = c;} + void clear () {page.clear(); bbox=BoundingBox(0, 0, 0, 0);} + const Matrix& getMatrix () const {static Matrix m(1); return m;} string getXMLSnippet () const { ostringstream oss; for (const auto &child : page.children()) diff --git a/tests/XMLNodeTest.cpp b/tests/XMLNodeTest.cpp index 8603380b..aaf56236 100644 --- a/tests/XMLNodeTest.cpp +++ b/tests/XMLNodeTest.cpp @@ -22,6 +22,7 @@ #include #include #include +#include "utility.hpp" #include "XMLNode.hpp" using namespace std; @@ -29,8 +30,8 @@ using namespace std; TEST(XMLNodeTest, appendElement) { XMLElementNode root("root"); - root.append(new XMLElementNode("child1")); - root.append(new XMLElementNode("child2")); + root.append(util::make_unique("child1")); + root.append(util::make_unique("child2")); EXPECT_EQ(root.children().size(), 2u); EXPECT_FALSE(root.empty()); XMLElementNode *child1 = dynamic_cast(root.children().front().get()); @@ -46,8 +47,8 @@ TEST(XMLNodeTest, appendElement) { TEST(XMLNodeTest, prependElement) { XMLElementNode root("root"); - root.prepend(new XMLElementNode("child1")); - root.prepend(new XMLElementNode("child2")); + root.prepend(util::make_unique("child1")); + root.prepend(util::make_unique("child2")); EXPECT_EQ(root.children().size(), 2u); XMLElementNode *child1 = dynamic_cast(root.children().front().get()); XMLElementNode *child2 = dynamic_cast(root.children().back().get()); @@ -60,13 +61,13 @@ TEST(XMLNodeTest, prependElement) { TEST(XMLNodeTest, appendText) { XMLElementNode root("root"); - root.append(new XMLTextNode("first string")); + root.append(util::make_unique("first string")); EXPECT_EQ(root.children().size(), 1u); XMLTextNode *lastChild = dynamic_cast(root.children().back().get()); ASSERT_NE(lastChild, nullptr); EXPECT_EQ(lastChild->getText(), "first string"); - root.append(new XMLTextNode(",second string")); + root.append(util::make_unique(",second string")); EXPECT_EQ(root.children().size(), 1u); lastChild = dynamic_cast(root.children().back().get()); ASSERT_NE(lastChild, nullptr); @@ -78,14 +79,14 @@ TEST(XMLNodeTest, appendText) { ASSERT_NE(lastChild, nullptr); EXPECT_EQ(lastChild->getText(), "first string,second string,third string"); - root.append(new XMLElementNode("separator")); + root.append(util::make_unique("separator")); root.append(",fourth string"); lastChild = dynamic_cast(root.children().back().get()); ASSERT_NE(lastChild, nullptr); EXPECT_EQ(lastChild->getText(), ",fourth string"); - root.append(new XMLElementNode("separator")); - root.append(new XMLTextNode(",fifth string")); + root.append(util::make_unique("separator")); + root.append(util::make_unique(",fifth string")); lastChild = dynamic_cast(root.children().back().get()); ASSERT_NE(lastChild, nullptr); EXPECT_EQ(lastChild->getText(), ",fifth string"); @@ -97,20 +98,20 @@ TEST(XMLNodeTest, appendText) { TEST(XMLNodeTest, prependText) { XMLElementNode root("root"); - root.prepend(new XMLTextNode("first string")); + root.prepend(util::make_unique("first string")); EXPECT_EQ(root.children().size(), 1u); XMLTextNode *firstChild = dynamic_cast(root.children().front().get()); ASSERT_NE(firstChild, nullptr); EXPECT_EQ(firstChild->getText(), "first string"); - root.prepend(new XMLTextNode("second string,")); + root.prepend(util::make_unique("second string,")); EXPECT_EQ(root.children().size(), 1u); firstChild = dynamic_cast(root.children().front().get()); ASSERT_NE(firstChild, nullptr); EXPECT_EQ(firstChild->getText(), "second string,first string"); - root.prepend(new XMLElementNode("separator")); - root.prepend(new XMLTextNode("third string,")); + root.prepend(util::make_unique("separator")); + root.prepend(util::make_unique("third string,")); firstChild = dynamic_cast(root.children().front().get()); ASSERT_NE(firstChild, nullptr); EXPECT_EQ(firstChild->getText(), "third string,"); @@ -140,7 +141,7 @@ TEST(XMLNodeTest, clone) { root.addAttribute("integer", 42); root.addAttribute("double", 42.24); root.append("text"); - unique_ptr clone(root.clone()); + unique_ptr clone = util::static_unique_ptr_cast(root.clone()); EXPECT_EQ(clone->children().size(), 1u); EXPECT_STREQ(clone->getAttributeValue("string"), "text"); EXPECT_STREQ(clone->getAttributeValue("integer"), "42"); @@ -150,18 +151,18 @@ TEST(XMLNodeTest, clone) { TEST(XMLNodeTest, insertBefore) { XMLElementNode root("root"); - XMLElementNode *child1 = new XMLElementNode("child1"); - XMLElementNode *child2 = new XMLElementNode("child2"); - root.append(child1); - root.append(child2); - unique_ptr node(new XMLElementNode("node")); - EXPECT_FALSE(root.insertBefore(child1, node.get())); + auto child1 = util::make_unique("child1"); + auto child2 = util::make_unique("child2"); + XMLNode* child1Ptr = root.append(std::move(child1)); + XMLNode* child2Ptr = root.append(std::move(child2)); + auto node = util::make_unique("node"); + EXPECT_FALSE(root.insertBefore(util::make_unique("dummy"), node.get())); EXPECT_EQ(root.children().size(), 2u); - EXPECT_TRUE(root.insertBefore(new XMLElementNode("child3"), child1)); + EXPECT_TRUE(root.insertBefore(util::make_unique("child3"), child1Ptr)); EXPECT_EQ(root.children().size(), 3u); XMLElementNode *child = dynamic_cast(root.children().front().get()); EXPECT_EQ(child->getName(), "child3"); - EXPECT_TRUE(root.insertBefore(new XMLElementNode("child4"), child2)); + EXPECT_TRUE(root.insertBefore(util::make_unique("child4"), child2Ptr)); const char *names[] = {"child3", "child1", "child4", "child2"}; const char **p = names; for (const auto &node : root.children()) { @@ -174,15 +175,15 @@ TEST(XMLNodeTest, insertBefore) { TEST(XMLNodeTest, insertAfter) { XMLElementNode root("root"); - XMLElementNode *child1 = new XMLElementNode("child1"); - XMLElementNode *child2 = new XMLElementNode("child2"); - root.append(child1); - root.append(child2); - unique_ptr node(new XMLElementNode("node")); - EXPECT_FALSE(root.insertAfter(child1, node.get())); + auto child1 = util::make_unique("child1"); + auto child2 = util::make_unique("child2"); + XMLNode *child1Ptr = root.append(std::move(child1)); + XMLNode *child2Ptr =root.append(std::move(child2)); + auto node = util::make_unique("node"); + EXPECT_FALSE(root.insertAfter(util::make_unique("dummy"), node.get())); EXPECT_EQ(root.children().size(), 2u); - EXPECT_TRUE(root.insertAfter(new XMLElementNode("child3"), child1)); - EXPECT_TRUE(root.insertAfter(new XMLElementNode("child4"), child2)); + EXPECT_TRUE(root.insertAfter(util::make_unique("child3"), child1Ptr)); + EXPECT_TRUE(root.insertAfter(util::make_unique("child4"), child2Ptr)); EXPECT_EQ(root.children().size(), 4u); const char *names[] = {"child1", "child3", "child2", "child4"}; const char **p = names; @@ -196,23 +197,23 @@ TEST(XMLNodeTest, insertAfter) { TEST(XMLNodeTest, getDescendants) { XMLElementNode root("root"); - XMLElementNode *child1 = new XMLElementNode("child"); - XMLElementNode *child2 = new XMLElementNode("childX"); - XMLElementNode *child3 = new XMLElementNode("child"); - XMLElementNode *child4 = new XMLElementNode("child"); - root.append(child1); + auto child1 = util::make_unique("child"); + auto child2 = util::make_unique("childX"); + auto child3 = util::make_unique("child"); + auto child4 = util::make_unique("child"); child1->addAttribute("attr", "value"); - child1->append(child2); child2->addAttribute("attr", "value"); - child2->append(child3); child3->addAttribute("attr", "value"); child3->append("text"); - root.append(child4); + XMLElementNode *child3Ptr = static_cast(child2->append(std::move(child3))); + XMLElementNode *child2Ptr = static_cast(child1->append(std::move(child2))); + XMLElementNode *child1Ptr = static_cast(root.append(std::move(child1))); + XMLElementNode *child4Ptr = static_cast(root.append(std::move(child4))); vector elements; - root.getDescendants("child", 0, elements); + root.getDescendants("child", nullptr, elements); EXPECT_EQ(elements.size(), 3u); { - XMLElementNode *nodes[] = {child1, child3, child4}; + XMLElementNode *nodes[] = {child1Ptr, child3Ptr, child4Ptr}; XMLElementNode **p = nodes; for (const XMLElementNode *elem : elements) EXPECT_EQ(elem, *p++); @@ -220,15 +221,15 @@ TEST(XMLNodeTest, getDescendants) { elements.clear(); root.getDescendants("child", "attr", elements); EXPECT_EQ(elements.size(), 2u); - XMLElementNode *nodes[] = {child1, child3}; + XMLElementNode *nodes[] = {child1Ptr, child3Ptr}; XMLElementNode **p = nodes; for (const XMLElementNode *elem : elements) EXPECT_EQ(elem, *p++); }{ elements.clear(); - root.getDescendants(0, "attr", elements); + root.getDescendants(nullptr, "attr", elements); EXPECT_EQ(elements.size(), 3u); - XMLElementNode *nodes[] = {child1, child2, child3}; + XMLElementNode *nodes[] = {child1Ptr, child2Ptr, child3Ptr}; XMLElementNode **p = nodes; for (const XMLElementNode *elem : elements) EXPECT_EQ(elem, *p++); @@ -238,42 +239,42 @@ TEST(XMLNodeTest, getDescendants) { TEST(XMLNodeTest, getFirstDescendant) { XMLElementNode root("root"); - XMLElementNode *child1 = new XMLElementNode("child"); - XMLElementNode *child2 = new XMLElementNode("childX"); - XMLElementNode *child3 = new XMLElementNode("child"); - XMLElementNode *child4 = new XMLElementNode("child"); - root.append(child1); + auto child1 = util::make_unique("child"); + auto child2 = util::make_unique("childX"); + auto child3 = util::make_unique("child"); + auto child4 = util::make_unique("child"); child1->addAttribute("attr", "valueX"); - child1->append(child2); child2->addAttribute("attr", "value"); - child2->append(child3); child3->addAttribute("attrX", "value"); child3->append("text"); - root.append(child4); - EXPECT_EQ(root.getFirstDescendant("child", 0, 0), child1); - EXPECT_EQ(root.getFirstDescendant("child", "attr", 0), child1); - EXPECT_EQ(root.getFirstDescendant("child", "attrX", 0), child3); - EXPECT_EQ(root.getFirstDescendant("child", "attrX", "value"), child3); - EXPECT_EQ(root.getFirstDescendant(0, "attrX", "value"), child3); - EXPECT_EQ(root.getFirstDescendant(0, "attrX", 0), child3); + XMLNode *child3Ptr = child2->append(std::move(child3)); + child1->append(std::move(child2)); + XMLNode *child1Ptr = root.append(std::move(child1)); + root.append(std::move(child4)); + EXPECT_EQ(root.getFirstDescendant("child", nullptr, nullptr), child1Ptr); + EXPECT_EQ(root.getFirstDescendant("child", "attr", nullptr), child1Ptr); + EXPECT_EQ(root.getFirstDescendant("child", "attrX", nullptr), child3Ptr); + EXPECT_EQ(root.getFirstDescendant("child", "attrX", "value"), child3Ptr); + EXPECT_EQ(root.getFirstDescendant(0, "attrX", "value"), child3Ptr); + EXPECT_EQ(root.getFirstDescendant(0, "attrX", nullptr), child3Ptr); EXPECT_EQ(root.getFirstDescendant("child", "attr", "value"), nullptr); } TEST(XMLNodeTest, write) { XMLElementNode root("root"); - XMLElementNode *child1 = new XMLElementNode("child"); - XMLElementNode *child2 = new XMLElementNode("childX"); - XMLElementNode *child3 = new XMLElementNode("child"); - XMLElementNode *child4 = new XMLElementNode("child"); - root.append(child1); + auto child1 = util::make_unique("child"); + auto child2 = util::make_unique("childX"); + auto child3 = util::make_unique("child"); + auto child4 = util::make_unique("child"); child1->addAttribute("attr", "valueX"); - child1->append(child2); child2->addAttribute("attr", "value"); - child2->append(child3); child3->addAttribute("attrX", "value"); child3->append("text"); - root.append(child4); + child2->append(std::move(child3)); + child1->append(std::move(child2)); + root.append(std::move(child1)); + root.append(std::move(child4)); ostringstream oss; root.write(oss); string str = oss.str(); @@ -284,17 +285,17 @@ TEST(XMLNodeTest, write) { TEST(XMLNodeTest, cdata) { XMLElementNode root("root"); - XMLCDataNode *cdataNode = new XMLCDataNode("text & "); - root.append(cdataNode); - root.append(new XMLElementNode("element")); - root.append(cdataNode->clone()); + auto cdataNode = util::make_unique("text & "); + XMLNode *cdataNodePtr = root.append(std::move(cdataNode)); + root.append(util::make_unique("element")); + root.append(cdataNodePtr->clone()); ostringstream oss; root.write(oss); string str = oss.str(); str.erase(remove(str.begin(), str.end(), '\n'), str.end()); EXPECT_EQ(str, "]]>]]>"); - cdataNode->clear(); + cdataNodePtr->clear(); oss.str(""); root.write(oss); str = oss.str();