]> www.fi.muni.cz Git - evince.git/blob - pdf/splash/SplashClip.cc
Fix CAN-2005-0064
[evince.git] / pdf / splash / SplashClip.cc
1 //========================================================================
2 //
3 // SplashClip.cc
4 //
5 //========================================================================
6
7 #include <aconf.h>
8
9 #ifdef USE_GCC_PRAGMAS
10 #pragma implementation
11 #endif
12
13 #include <stdlib.h>
14 #include <string.h>
15 #include "gmem.h"
16 #include "SplashErrorCodes.h"
17 #include "SplashMath.h"
18 #include "SplashPath.h"
19 #include "SplashXPath.h"
20 #include "SplashXPathScanner.h"
21 #include "SplashClip.h"
22
23 //------------------------------------------------------------------------
24 // SplashClip.flags
25 //------------------------------------------------------------------------
26
27 #define splashClipEO       0x01 // use even-odd rule
28
29 //------------------------------------------------------------------------
30 // SplashClip
31 //------------------------------------------------------------------------
32
33 SplashClip::SplashClip(SplashCoord x0, SplashCoord y0,
34                        SplashCoord x1, SplashCoord y1) {
35   if (x0 < x1) {
36     xMin = splashFloor(x0);
37     xMax = splashFloor(x1);
38   } else {
39     xMin = splashFloor(x1);
40     xMax = splashFloor(x0);
41   }
42   if (y0 < y1) {
43     yMin = splashFloor(y0);
44     yMax = splashFloor(y1);
45   } else {
46     yMin = splashFloor(y1);
47     yMax = splashFloor(y0);
48   }
49   paths = NULL;
50   flags = NULL;
51   scanners = NULL;
52   length = size = 0;
53 }
54
55 SplashClip::SplashClip(SplashClip *clip) {
56   int i;
57
58   xMin = clip->xMin;
59   yMin = clip->yMin;
60   xMax = clip->xMax;
61   yMax = clip->yMax;
62   length = clip->length;
63   size = clip->size;
64   paths = (SplashXPath **)gmalloc(size * sizeof(SplashXPath *));
65   flags = (Guchar *)gmalloc(size * sizeof(Guchar));
66   scanners = (SplashXPathScanner **)
67                  gmalloc(size * sizeof(SplashXPathScanner *));
68   for (i = 0; i < length; ++i) {
69     paths[i] = clip->paths[i]->copy();
70     flags[i] = clip->flags[i];
71     scanners[i] = new SplashXPathScanner(paths[i], flags[i] & splashClipEO);
72   }
73 }
74
75 SplashClip::~SplashClip() {
76   int i;
77
78   for (i = 0; i < length; ++i) {
79     delete paths[i];
80     delete scanners[i];
81   }
82   gfree(paths);
83   gfree(flags);
84   gfree(scanners);
85 }
86
87 void SplashClip::grow(int nPaths) {
88   if (length + nPaths > size) {
89     if (size == 0) {
90       size = 32;
91     }
92     while (size < length + nPaths) {
93       size *= 2;
94     }
95     paths = (SplashXPath **)grealloc(paths, size * sizeof(SplashXPath *));
96     flags = (Guchar *)grealloc(flags, size * sizeof(Guchar));
97     scanners = (SplashXPathScanner **)
98                    grealloc(scanners, size * sizeof(SplashXPathScanner *));
99   }
100 }
101
102 void SplashClip::resetToRect(SplashCoord x0, SplashCoord y0,
103                              SplashCoord x1, SplashCoord y1) {
104   int i;
105
106   for (i = 0; i < length; ++i) {
107     delete paths[i];
108     delete scanners[i];
109   }
110   gfree(paths);
111   gfree(flags);
112   gfree(scanners);
113   paths = NULL;
114   flags = NULL;
115   scanners = NULL;
116   length = size = 0;
117
118   if (x0 < x1) {
119     xMin = splashFloor(x0);
120     xMax = splashFloor(x1);
121   } else {
122     xMin = splashFloor(x1);
123     xMax = splashFloor(x0);
124   }
125   if (y0 < y1) {
126     yMin = splashFloor(y0);
127     yMax = splashFloor(y1);
128   } else {
129     yMin = splashFloor(y1);
130     yMax = splashFloor(y0);
131   }
132 }
133
134 SplashError SplashClip::clipToRect(SplashCoord x0, SplashCoord y0,
135                                    SplashCoord x1, SplashCoord y1) {
136   int x0I, y0I, x1I, y1I;
137
138   if (x0 < x1) {
139     x0I = splashFloor(x0);
140     x1I = splashFloor(x1);
141   } else {
142     x0I = splashFloor(x1);
143     x1I = splashFloor(x0);
144   }
145   if (x0I > xMin) {
146     xMin = x0I;
147   }
148   if (x1I < xMax) {
149     xMax = x1I;
150   }
151   if (y0 < y1) {
152     y0I = splashFloor(y0);
153     y1I = splashFloor(y1);
154   } else {
155     y0I = splashFloor(y1);
156     y1I = splashFloor(y0);
157   }
158   if (y0I > yMin) {
159     yMin = y0I;
160   }
161   if (y1I < yMax) {
162     yMax = y1I;
163   }
164   return splashOk;
165 }
166
167 SplashError SplashClip::clipToPath(SplashPath *path, SplashCoord flatness,
168                                    GBool eo) {
169   SplashXPath *xPath;
170
171   xPath = new SplashXPath(path, flatness, gTrue);
172
173   // check for an empty path
174   if (xPath->length == 0) {
175     xMax = xMin - 1;
176     yMax = yMin - 1;
177     delete xPath;
178
179   // check for a rectangle
180   } else if (xPath->length == 4 &&
181       ((xPath->segs[0].x0 == xPath->segs[0].x1 &&
182         xPath->segs[0].x0 == xPath->segs[1].x0 &&
183         xPath->segs[0].x0 == xPath->segs[3].x1 &&
184         xPath->segs[2].x0 == xPath->segs[2].x1 &&
185         xPath->segs[2].x0 == xPath->segs[1].x1 &&
186         xPath->segs[2].x0 == xPath->segs[3].x0 &&
187         xPath->segs[1].y0 == xPath->segs[1].y1 &&
188         xPath->segs[1].y0 == xPath->segs[0].y1 &&
189         xPath->segs[1].y0 == xPath->segs[2].y0 &&
190         xPath->segs[3].y0 == xPath->segs[3].y1 &&
191         xPath->segs[3].y0 == xPath->segs[0].y0 &&
192         xPath->segs[3].y0 == xPath->segs[2].y1) ||
193        (xPath->segs[0].y0 == xPath->segs[0].y1 &&
194         xPath->segs[0].y0 == xPath->segs[1].y0 &&
195         xPath->segs[0].y0 == xPath->segs[3].y1 &&
196         xPath->segs[2].y0 == xPath->segs[2].y1 &&
197         xPath->segs[2].y0 == xPath->segs[1].y1 &&
198         xPath->segs[2].y0 == xPath->segs[3].y0 &&
199         xPath->segs[1].x0 == xPath->segs[1].x1 &&
200         xPath->segs[1].x0 == xPath->segs[0].x1 &&
201         xPath->segs[1].x0 == xPath->segs[2].x0 &&
202         xPath->segs[3].x0 == xPath->segs[3].x1 &&
203         xPath->segs[3].x0 == xPath->segs[0].x0 &&
204         xPath->segs[3].x0 == xPath->segs[2].x1))) {
205     clipToRect(xPath->segs[0].x0, xPath->segs[0].y0,
206                xPath->segs[2].x0, xPath->segs[2].y0);
207     delete xPath;
208
209   } else {
210     grow(1);
211     xPath->sort();
212     paths[length] = xPath;
213     flags[length] = eo ? splashClipEO : 0;
214     scanners[length] = new SplashXPathScanner(xPath, eo);
215     ++length;
216   }
217
218   return splashOk;
219 }
220
221 GBool SplashClip::test(int x, int y) {
222   int i;
223
224   // check the rectangle
225   if (x < xMin || x > xMax || y < yMin || y > yMax) {
226     return gFalse;
227   }
228
229   // check the paths
230   for (i = 0; i < length; ++i) {
231     if (!scanners[i]->test(x, y)) {
232       return gFalse;
233     }
234   }
235
236   return gTrue;
237 }
238
239 SplashClipResult SplashClip::testRect(int rectXMin, int rectYMin,
240                                       int rectXMax, int rectYMax) {
241   if (rectXMax < xMin || rectXMin > xMax ||
242       rectYMax < yMin || rectYMin > yMax) {
243     return splashClipAllOutside;
244   }
245   if (rectXMin >= xMin && rectXMax <= xMax &&
246       rectYMin >= yMin && rectYMax <= yMax &&
247       length == 0) {
248     return splashClipAllInside;
249   }
250   return splashClipPartial;
251 }
252
253 SplashClipResult SplashClip::testSpan(int spanXMin, int spanXMax, int spanY) {
254   int i;
255
256   if (spanXMax < xMin || spanXMin > xMax ||
257       spanY < yMin || spanY > yMax) {
258     return splashClipAllOutside;
259   }
260   if (!(spanXMin >= xMin && spanXMax <= xMax &&
261         spanY >= yMin && spanY <= yMax)) {
262     return splashClipPartial;
263   }
264   for (i = 0; i < length; ++i) {
265     if (!scanners[i]->testSpan(xMin, xMax, spanY)) {
266       return splashClipPartial;
267     }
268   }
269   return splashClipAllInside;
270 }