Code

Added a clip path stack for PdfParser and a node stack for SvgBuilder needed for...
authormiklosh <miklosh@users.sourceforge.net>
Mon, 13 Aug 2007 16:48:30 +0000 (16:48 +0000)
committermiklosh <miklosh@users.sourceforge.net>
Mon, 13 Aug 2007 16:48:30 +0000 (16:48 +0000)
src/extension/internal/pdfinput/pdf-parser.cpp
src/extension/internal/pdfinput/pdf-parser.h
src/extension/internal/pdfinput/svg-builder.cpp
src/extension/internal/pdfinput/svg-builder.h

index a9cf2ad2ba5c19618e719d79be9aeece3d3d5c6c..bc6190b827a8282dfd539de380912ecb5fbb5398 100644 (file)
@@ -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 */
index 40457453729ba14af273071ce0ff87ecb78f34b1..dc119cbf9abd245f90ffc976ea9a2eee7e454900 100644 (file)
@@ -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);
index 7a63ba41510a4a9d27c5529e07bf97f7dc59c606..b4aaefd235acf532f19a3d4cb35dc06d77cb6148 100644 (file)
@@ -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();
     }
 
index 6a5d94ee26b8d87db8bc7410dc7752e73f4f2d41..8a3687e6d03dc74c7ed8fedce9e7598c0af18ee0 100644 (file)
@@ -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<Inkscape::XML::Node *> _node_stack;
     std::vector<int> _group_depth;    // Depth of nesting groups
 
     SPCSSAttr *_font_style;          // Current font style