From 1667116521643e2475184b048e0abb77a2aa9735 Mon Sep 17 00:00:00 2001 From: miklosh Date: Mon, 13 Aug 2007 16:48:30 +0000 Subject: [PATCH] Added a clip path stack for PdfParser and a node stack for SvgBuilder needed for mask support later --- .../internal/pdfinput/pdf-parser.cpp | 92 ++++++++++++++++--- src/extension/internal/pdfinput/pdf-parser.h | 31 ++++++- .../internal/pdfinput/svg-builder.cpp | 52 ++++++++--- src/extension/internal/pdfinput/svg-builder.h | 6 +- 4 files changed, 148 insertions(+), 33 deletions(-) diff --git a/src/extension/internal/pdfinput/pdf-parser.cpp b/src/extension/internal/pdfinput/pdf-parser.cpp index a9cf2ad2b..bc6190b82 100644 --- a/src/extension/internal/pdfinput/pdf-parser.cpp +++ b/src/extension/internal/pdfinput/pdf-parser.cpp @@ -296,9 +296,9 @@ PdfParser::PdfParser(XRef *xrefA, Inkscape::Extension::Internal::SvgBuilder *bui // initialize state = new GfxState(72.0, 72.0, cropBox, rotate, gTrue); + clipHistory = new ClipHistoryEntry(); fontChanged = gFalse; clip = clipNone; - lastClipPath = NULL; ignoreUndef = 0; operatorHistory = NULL; builder = builderA; @@ -329,6 +329,7 @@ PdfParser::PdfParser(XRef *xrefA, Inkscape::Extension::Internal::SvgBuilder *bui state->lineTo(cropBox->x1, cropBox->y2); state->closePath(); state->clip(); + clipHistory->setClip(state->getPath(), clipNormal); builder->setClipPath(state); state->clearPath(); } @@ -352,9 +353,9 @@ PdfParser::PdfParser(XRef *xrefA, Inkscape::Extension::Internal::SvgBuilder *bui operatorHistory = NULL; builder = builderA; state = new GfxState(72, 72, box, 0, gFalse); + clipHistory = new ClipHistoryEntry(); fontChanged = gFalse; clip = clipNone; - lastClipPath = NULL; ignoreUndef = 0; for (i = 0; i < 6; ++i) { baseMatrix[i] = state->getCTM()[i]; @@ -375,8 +376,8 @@ PdfParser::~PdfParser() { if (state) { delete state; } - if (lastClipPath) { - delete lastClipPath; + if (clipHistory) { + delete clipHistory; } } @@ -1633,9 +1634,9 @@ void PdfParser::opShFill(Object args[], int numArgs) { break; case 2: case 3: - if (lastClipPath) { - builder->addShadedFill(shading, matrix, lastClipPath, - lastClipType == clipEO ? true : false); + if (clipHistory->getClipPath()) { + builder->addShadedFill(shading, matrix, clipHistory->getClipPath(), + clipHistory->getClipType() == clipEO ? true : false); } break; case 4: @@ -1986,8 +1987,10 @@ void PdfParser::doEndPath() { if (state->isCurPt() && clip != clipNone) { state->clip(); if (clip == clipNormal) { + clipHistory->setClip(state->getPath(), clipNormal); builder->clip(state); } else { + clipHistory->setClip(state->getPath(), clipEO); builder->clip(state, true); } } @@ -2001,18 +2004,10 @@ void PdfParser::doEndPath() { void PdfParser::opClip(Object args[], int numArgs) { clip = clipNormal; - lastClipType = clipNormal; - if (lastClipPath) - delete lastClipPath; - lastClipPath = state->getPath()->copy(); } void PdfParser::opEOClip(Object args[], int numArgs) { clip = clipEO; - lastClipType = clipEO; - if (lastClipPath) - delete lastClipPath; - lastClipPath = state->getPath()->copy(); } //------------------------------------------------------------------------ @@ -2834,6 +2829,7 @@ void PdfParser::doForm1(Object *str, Dict *resDict, double *matrix, double *bbox state->lineTo(bbox[0], bbox[3]); state->closePath(); state->clip(); + clipHistory->setClip(state->getPath()); builder->clip(state); state->clearPath(); @@ -3033,9 +3029,11 @@ void PdfParser::opMarkPoint(Object args[], int numArgs) { void PdfParser::saveState() { builder->saveState(); state = state->save(); + clipHistory = clipHistory->save(); } void PdfParser::restoreState() { + clipHistory = clipHistory->restore(); state = state->restore(); builder->restoreState(); } @@ -3052,4 +3050,68 @@ void PdfParser::popResources() { res = resPtr; } +//------------------------------------------------------------------------ +// ClipHistoryEntry +//------------------------------------------------------------------------ + +ClipHistoryEntry::ClipHistoryEntry(GfxPath *clipPathA, GfxClipType clipTypeA) { + if (clipPathA) { + clipPath = clipPathA->copy(); + } else { + clipPath = NULL; + } + clipType = clipTypeA; + saved = NULL; +} + +ClipHistoryEntry::~ClipHistoryEntry() { + if (clipPath) { + delete clipPath; + } +} + +void ClipHistoryEntry::setClip(GfxPath *clipPathA, GfxClipType clipTypeA) { + // Free previous clip path + if (clipPath) { + delete clipPath; + } + if (clipPathA) { + clipPath = clipPathA->copy(); + clipType = clipTypeA; + } else { + clipPath = NULL; + } +} + +ClipHistoryEntry *ClipHistoryEntry::save() { + ClipHistoryEntry *newEntry = new ClipHistoryEntry(this); + newEntry->saved = this; + + return newEntry; +} + +ClipHistoryEntry *ClipHistoryEntry::restore() { + ClipHistoryEntry *oldEntry; + + if (saved) { + oldEntry = saved; + saved = NULL; + delete this; + } else { + oldEntry = this; + } + + return oldEntry; +} + +ClipHistoryEntry::ClipHistoryEntry(ClipHistoryEntry *other) { + if (other->clipPath) { + this->clipPath = other->clipPath->copy(); + this->clipType = other->clipType; + } else { + this->clipPath = NULL; + } + saved = NULL; +} + #endif /* HAVE_POPPLER */ diff --git a/src/extension/internal/pdfinput/pdf-parser.h b/src/extension/internal/pdfinput/pdf-parser.h index 404574537..dc119cbf9 100644 --- a/src/extension/internal/pdfinput/pdf-parser.h +++ b/src/extension/internal/pdfinput/pdf-parser.h @@ -101,6 +101,34 @@ struct OpHistoryEntry { unsigned depth; // total number of entries descending from this }; +//------------------------------------------------------------------------ +// ClipHistoryEntry +//------------------------------------------------------------------------ + +class ClipHistoryEntry { +public: + + ClipHistoryEntry(GfxPath *clipPath=NULL, GfxClipType clipType=clipNormal); + ~ClipHistoryEntry(); + + // Manipulate clip path stack + ClipHistoryEntry *save(); + ClipHistoryEntry *restore(); + GBool hasSaves() { return saved != NULL; } + void setClip(GfxPath *newClipPath, GfxClipType newClipType=clipNormal); + GfxPath *getClipPath() { return clipPath; } + GfxClipType getClipType() { return clipType; } + +private: + + ClipHistoryEntry *saved; // next clip path on stack + + GfxPath *clipPath; // used as the path to be filled for an 'sh' operator + GfxClipType clipType; + + ClipHistoryEntry(ClipHistoryEntry *other); +}; + //------------------------------------------------------------------------ // PdfParser //------------------------------------------------------------------------ @@ -150,12 +178,11 @@ private: static PdfOperator opTab[]; // table of operators + ClipHistoryEntry *clipHistory; // clip path stack OpHistoryEntry *operatorHistory; // list containing the last N operators void pushOperator(const char *name); OpHistoryEntry *popOperator(); const char *getPreviousOperator(unsigned int look_back=1); // returns the nth previous operator's name - GfxPath *lastClipPath; // Used as the path to be filled for an 'sh' operator - GfxClipType lastClipType; void go(GBool topLevel); void execOp(Object *cmd, Object args[], int numArgs); diff --git a/src/extension/internal/pdfinput/svg-builder.cpp b/src/extension/internal/pdfinput/svg-builder.cpp index 7a63ba415..b4aaefd23 100644 --- a/src/extension/internal/pdfinput/svg-builder.cpp +++ b/src/extension/internal/pdfinput/svg-builder.cpp @@ -60,15 +60,6 @@ namespace Internal { * */ -SvgBuilder::SvgBuilder() { - _in_text_object = false; - _need_font_update = true; - _invalidated_style = true; - _font_style = NULL; - _current_font = NULL; - _current_state = NULL; -} - SvgBuilder::SvgBuilder(SPDocument *document, gchar *docname, XRef *xref) { _is_top_level = true; _doc = document; @@ -77,7 +68,7 @@ SvgBuilder::SvgBuilder(SPDocument *document, gchar *docname, XRef *xref) { _xml_doc = sp_document_repr_doc(_doc); _container = _root = _doc->rroot; _root->setAttribute("xml:space", "preserve"); - SvgBuilder(); + _init(); } SvgBuilder::SvgBuilder(SvgBuilder *parent, Inkscape::XML::Node *root) { @@ -87,12 +78,23 @@ SvgBuilder::SvgBuilder(SvgBuilder *parent, Inkscape::XML::Node *root) { _xref = parent->_xref; _xml_doc = parent->_xml_doc; _container = this->_root = root; - SvgBuilder(); + _init(); } SvgBuilder::~SvgBuilder() { } +void SvgBuilder::_init() { + _in_text_object = false; + _need_font_update = true; + _invalidated_style = true; + _font_style = NULL; + _current_font = NULL; + _current_state = NULL; + + _node_stack.push_back(_container); +} + void SvgBuilder::setDocumentSize(double width, double height) { sp_repr_set_svg_double(_root, "width", width); sp_repr_set_svg_double(_root, "height", height); @@ -122,10 +124,30 @@ void SvgBuilder::restoreState() { _group_depth.pop_back(); } -Inkscape::XML::Node *SvgBuilder::pushGroup() { - Inkscape::XML::Node *node = _xml_doc->createElement("svg:g"); - _container->appendChild(node); +Inkscape::XML::Node *SvgBuilder::pushNode(const char *name) { + Inkscape::XML::Node *node = _xml_doc->createElement(name); + _node_stack.push_back(node); _container = node; + return node; +} + +Inkscape::XML::Node *SvgBuilder::popNode() { + Inkscape::XML::Node *node = NULL; + if ( _node_stack.size() > 1 ) { + node = _node_stack.back(); + _node_stack.pop_back(); + _container = _node_stack.back(); // Re-set container + } else { + TRACE(("popNode() called when stack is empty\n")); + node = _root; + } + return node; +} + +Inkscape::XML::Node *SvgBuilder::pushGroup() { + Inkscape::XML::Node *saved_container = _container; + Inkscape::XML::Node *node = pushNode("svg:g"); + saved_container->appendChild(node); Inkscape::GC::release(node); _group_depth.back()++; // Set as a layer if this is a top-level group @@ -145,7 +167,7 @@ Inkscape::XML::Node *SvgBuilder::pushGroup() { Inkscape::XML::Node *SvgBuilder::popGroup() { if (_container != _root) { // Pop if the current container isn't root - _container = _container->parent(); + popNode(); _group_depth[_group_depth.size()-1] = --_group_depth.back(); } diff --git a/src/extension/internal/pdfinput/svg-builder.h b/src/extension/internal/pdfinput/svg-builder.h index 6a5d94ee2..8a3687e6d 100644 --- a/src/extension/internal/pdfinput/svg-builder.h +++ b/src/extension/internal/pdfinput/svg-builder.h @@ -143,7 +143,7 @@ public: bool getTransform(double *transform); private: - SvgBuilder(); + void _init(); // Pattern creation gchar *_createPattern(GfxPattern *pattern, GfxState *state, bool is_stroke=false); @@ -166,6 +166,10 @@ private: void _flushText(); // Write buffered text into doc + // Handling of node stack + Inkscape::XML::Node *pushNode(const char* name); + Inkscape::XML::Node *popNode(); + std::vector _node_stack; std::vector _group_depth; // Depth of nesting groups SPCSSAttr *_font_style; // Current font style -- 2.30.2