1 /* This file is part of the GNU plotutils package.  Copyright (C) 1995,
2    1996, 1997, 1998, 1999, 2000, 2005, 2008, Free Software Foundation, Inc.
3 
4    The GNU plotutils package is free software.  You may redistribute it
5    and/or modify it under the terms of the GNU General Public License as
6    published by the Free Software foundation; either version 2, or (at your
7    option) any later version.
8 
9    The GNU plotutils package is distributed in the hope that it will be
10    useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    General Public License for more details.
13 
14    You should have received a copy of the GNU General Public License along
15    with the GNU plotutils package; see the file COPYING.  If not, write to
16    the Free Software Foundation, Inc., 51 Franklin St., Fifth Floor,
17    Boston, MA 02110-1301, USA. */
18 
19 /* This file contains the savestate method, which is a GNU extension to
20    libplot.  It creates a new drawing state and pushes it onto the stack of
21    drawing states.  By definition, a `drawing state' comprises the set of
22    drawing attributes, and the state of any path being incrementally drawn.
23 
24    The new state will have the same drawing attributes as the old state.
25    If a path was being drawn incrementally in the old state, the new state
26    will not contain it.  The old state may be returned to by invoking the
27    restorestate routine, which pops drawing states off the stack.  If the
28    incremental drawing of a path was in progress, it may be returned to at
29    that time.
30 
31    This version of savestate() assumes that the device-specific part of the
32    drawing state contains no strings.  Plotter objects for which this is
33    not true must supplement this by defining push_state() appropriately,
34    since they need to call malloc() to allocate space for the string in the
35    new state. */
36 
37 /* This file also contains the restorestate method, which is a GNU
38    extension to libplot.  It pops off the drawing state on the top of the
39    stack of drawing states.  Drawing states (other than the one which is
40    always present, and may not be popped off) are created and pushed onto
41    the stack by invoking the savestate() routine.
42 
43    This version of restorestate() assumes that the device-specific part of
44    the state contains no strings or other dynamically allocated data.
45    Versions of libplot in which this is not true must supplement this by
46    defining pop_state() appropriately, since they need to call free() to
47    deallocate space for the strings. */
48 
49 /* N.B. The drawing state stack, during user use of libplot, always
50    contains at least one drawing state.  The first state is added by
51    openpl() and deleted by closepl(). */
52 
53 #include "sys-defines.h"
54 #include "extern.h"
55 
56 int
_API_savestate(S___ (Plotter * _plotter))57 _API_savestate(S___(Plotter *_plotter))
58 {
59   plDrawState *oldstate = _plotter->drawstate; /* non-NULL */
60   plDrawState *drawstate;
61   char *fill_rule, *line_mode, *join_mode, *cap_mode;
62   char *font_name, *true_font_name;
63 
64   if (!_plotter->data->open)
65     {
66       _plotter->error (R___(_plotter)
67 		       "savestate: invalid operation");
68       return -1;
69     }
70 
71   /* create a new state */
72   drawstate = (plDrawState *)_pl_xmalloc (sizeof(plDrawState));
73 
74   /* copy from old state */
75   memcpy (drawstate, oldstate, sizeof(plDrawState));
76 
77   /* elements of state that are strings are treated specially */
78   fill_rule = (char *)_pl_xmalloc (strlen (oldstate->fill_rule) + 1);
79   line_mode = (char *)_pl_xmalloc (strlen (oldstate->line_mode) + 1);
80   join_mode = (char *)_pl_xmalloc (strlen (oldstate->join_mode) + 1);
81   cap_mode = (char *)_pl_xmalloc (strlen (oldstate->cap_mode) + 1);
82   strcpy (fill_rule, oldstate->fill_rule);
83   strcpy (line_mode, oldstate->line_mode);
84   strcpy (join_mode, oldstate->join_mode);
85   strcpy (cap_mode, oldstate->cap_mode);
86   drawstate->fill_rule = fill_rule;
87   drawstate->line_mode = line_mode;
88   drawstate->join_mode = join_mode;
89   drawstate->cap_mode = cap_mode;
90 
91   /* dash array, if non-empty, is treated specially too */
92   if (oldstate->dash_array_len > 0)
93     {
94       int i;
95       double *dash_array;
96 
97       dash_array = (double *)_pl_xmalloc (oldstate->dash_array_len * sizeof(double));
98       for (i = 0; i < oldstate->dash_array_len; i++)
99 	dash_array[i] = oldstate->dash_array[i];
100       drawstate->dash_array = dash_array;
101     }
102 
103   /* The font_name, true_font_name, font_type, typeface_index, and
104      font_index fields are special, since for the initial drawing state
105      they're Plotter-dependent.
106 
107      For later drawing states, we just copy them from the previous state.
108      Since only the first two (font_name and true_font_name) are strings,
109      for later states we don't worry about the other three: they've already
110      been copied.
111 
112      The fill_rule_type field is also treated specially in the initial
113      drawing state, because not all Plotters support both types of filling
114      (odd vs. nonzero winding number). */
115 
116   font_name = (char *)_pl_xmalloc (strlen (oldstate->font_name) + 1);
117   strcpy (font_name, oldstate->font_name);
118   drawstate->font_name = font_name;
119 
120   true_font_name = (char *)_pl_xmalloc (strlen (oldstate->true_font_name) + 1);
121   strcpy (true_font_name, oldstate->true_font_name);
122   drawstate->true_font_name = true_font_name;
123 
124   /* Our memcpy copied the pointer to the compound path under construction
125      (if any).  So we knock it out, to start afresh */
126   drawstate->path = (plPath *)NULL;
127   drawstate->paths = (plPath **)NULL;
128   drawstate->num_paths = 0;
129 
130   /* install new state at head of the state list */
131   drawstate->previous = oldstate;
132   _plotter->drawstate = drawstate;
133 
134   /* add any device-dependent fields to new state */
135   _plotter->push_state (S___(_plotter));
136 
137   return 0;
138 }
139 
140 int
_API_restorestate(S___ (Plotter * _plotter))141 _API_restorestate(S___(Plotter *_plotter))
142 {
143   plDrawState *oldstate = _plotter->drawstate->previous;
144 
145   if (!_plotter->data->open)
146     {
147       _plotter->error (R___(_plotter)
148 		       "restorestate: invalid operation");
149       return -1;
150     }
151 
152   if (_plotter->drawstate->previous == NULL)
153     /* this is an attempt to pop the lowest state off the stack */
154     {
155       _plotter->error (R___(_plotter)
156 		       "restorestate: invalid operation");
157       return -1;
158     }
159 
160   _API_endpath (S___(_plotter)); /* flush path if any */
161 
162   /* tear down any device-dependent fields in state */
163   _plotter->pop_state (S___(_plotter));
164 
165   /* elements of current state that are strings are first freed */
166   free ((char *)_plotter->drawstate->fill_rule);
167   free ((char *)_plotter->drawstate->line_mode);
168   free ((char *)_plotter->drawstate->join_mode);
169   free ((char *)_plotter->drawstate->cap_mode);
170   free ((char *)_plotter->drawstate->true_font_name);
171   free ((char *)_plotter->drawstate->font_name);
172 
173   /* free dash array too, if nonempty */
174   if (_plotter->drawstate->dash_array_len > 0)
175     free ((double *)_plotter->drawstate->dash_array);
176 
177   /* pop state off the stack */
178   free (_plotter->drawstate);
179   _plotter->drawstate = oldstate;
180 
181   return 0;
182 }
183 
184 void
_pl_g_push_state(S___ (Plotter * _plotter))185 _pl_g_push_state (S___(Plotter *_plotter))
186 {
187   return;
188 }
189 
190 void
_pl_g_pop_state(S___ (Plotter * _plotter))191 _pl_g_pop_state (S___(Plotter *_plotter))
192 {
193   return;
194 }
195 
196