Allocate span memory for every clipping type, not only for one
[reactos.git] / reactos / subsystems / win32 / win32k / eng / clip.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id$
20 *
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * PURPOSE: GDI Clipping Functions
24 * FILE: subsys/win32k/eng/clip.c
25 * PROGRAMER: Jason Filby
26 * REVISION HISTORY:
27 * 21/8/1999: Created
28 */
29
30 #include <w32k.h>
31
32 #define NDEBUG
33 #include <debug.h>
34
35 static __inline int
36 CompareRightDown(
37 const RECTL *r1,
38 const RECTL *r2)
39 {
40 int Cmp;
41
42 if (r1->top < r2->top)
43 {
44 Cmp = -1;
45 }
46 else if (r2->top < r1->top)
47 {
48 Cmp = +1;
49 }
50 else
51 {
52 ASSERT(r1->bottom == r2->bottom);
53 if (r1->left < r2->left)
54 {
55 Cmp = -1;
56 }
57 else if (r2->left < r1->left)
58 {
59 Cmp = +1;
60 }
61 else
62 {
63 ASSERT(r1->right == r2->right);
64 Cmp = 0;
65 }
66 }
67
68 return Cmp;
69 }
70
71 static __inline int
72 CompareRightUp(
73 const RECTL *r1,
74 const RECTL *r2)
75 {
76 int Cmp;
77
78 if (r1->bottom < r2->bottom)
79 {
80 Cmp = +1;
81 }
82 else if (r2->bottom < r1->bottom)
83 {
84 Cmp = -1;
85 }
86 else
87 {
88 ASSERT(r1->top == r2->top);
89 if (r1->left < r2->left)
90 {
91 Cmp = -1;
92 }
93 else if (r2->left < r1->left)
94 {
95 Cmp = +1;
96 }
97 else
98 {
99 ASSERT(r1->right == r2->right);
100 Cmp = 0;
101 }
102 }
103
104 return Cmp;
105 }
106
107 static __inline int
108 CompareLeftDown(
109 const RECTL *r1,
110 const RECTL *r2)
111 {
112 int Cmp;
113
114 if (r1->top < r2->top)
115 {
116 Cmp = -1;
117 }
118 else if (r2->top < r1->top)
119 {
120 Cmp = +1;
121 }
122 else
123 {
124 ASSERT(r1->bottom == r2->bottom);
125 if (r1->right < r2->right)
126 {
127 Cmp = +1;
128 }
129 else if (r2->right < r1->right)
130 {
131 Cmp = -1;
132 }
133 else
134 {
135 ASSERT(r1->left == r2->left);
136 Cmp = 0;
137 }
138 }
139
140 return Cmp;
141 }
142
143 static __inline int
144 CompareLeftUp(
145 const RECTL *r1,
146 const RECTL *r2)
147 {
148 int Cmp;
149
150 if (r1->bottom < r2->bottom)
151 {
152 Cmp = +1;
153 }
154 else if (r2->bottom < r1->bottom)
155 {
156 Cmp = -1;
157 }
158 else
159 {
160 ASSERT(r1->top == r2->top);
161 if (r1->right < r2->right)
162 {
163 Cmp = +1;
164 }
165 else if (r2->right < r1->right)
166 {
167 Cmp = -1;
168 }
169 else
170 {
171 ASSERT(r1->left == r2->left);
172 Cmp = 0;
173 }
174 }
175 return Cmp;
176 }
177
178 static __inline int
179 CompareSpans(
180 const SPAN *Span1,
181 const SPAN *Span2)
182 {
183 int Cmp;
184
185 if (Span1->Y < Span2->Y)
186 {
187 Cmp = -1;
188 }
189 else if (Span2->Y < Span1->Y)
190 {
191 Cmp = +1;
192 }
193 else
194 {
195 if (Span1->X < Span2->X)
196 {
197 Cmp = -1;
198 }
199 else if (Span2->X < Span1->X)
200 {
201 Cmp = +1;
202 }
203 else
204 {
205 Cmp = 0;
206 }
207 }
208
209 return Cmp;
210 }
211
212 VOID FASTCALL
213 IntEngDeleteClipRegion(CLIPOBJ *ClipObj)
214 {
215 EngFreeMem(ObjToGDI(ClipObj, CLIP));
216 }
217
218 CLIPOBJ* FASTCALL
219 IntEngCreateClipRegion(ULONG count, PRECTL pRect, PRECTL rcBounds)
220 {
221 CLIPGDI *Clip;
222
223 if(count > 1)
224 {
225 RECTL *dest;
226
227 Clip = EngAllocMem(0, sizeof(CLIPGDI) + ((count - 1) * sizeof(RECTL)), TAG_CLIPOBJ);
228
229 if(Clip != NULL)
230 {
231 Clip->EnumRects.c = count;
232 Clip->EnumOrder = CD_ANY;
233 for(dest = Clip->EnumRects.arcl;count > 0; count--, dest++, pRect++)
234 {
235 *dest = *pRect;
236 }
237
238 Clip->ClipObj.iDComplexity = DC_COMPLEX;
239 Clip->ClipObj.iFComplexity = ((Clip->EnumRects.c <= 4) ? FC_RECT4 : FC_COMPLEX);
240 Clip->ClipObj.iMode = TC_RECTANGLES;
241 Clip->ClipObj.rclBounds = *rcBounds;
242
243 return GDIToObj(Clip, CLIP);
244 }
245 }
246 else
247 {
248 Clip = EngAllocMem(0, sizeof(CLIPGDI), TAG_CLIPOBJ);
249
250 if(Clip != NULL)
251 {
252 Clip->EnumRects.c = 1;
253 Clip->EnumOrder = CD_ANY;
254 Clip->EnumRects.arcl[0] = *rcBounds;
255
256 Clip->ClipObj.iDComplexity = (((rcBounds->top == rcBounds->bottom) &&
257 (rcBounds->left == rcBounds->right))
258 ? DC_TRIVIAL : DC_RECT);
259
260 Clip->ClipObj.iFComplexity = FC_RECT;
261 Clip->ClipObj.iMode = TC_RECTANGLES;
262 Clip->ClipObj.rclBounds = *rcBounds;
263
264 return GDIToObj(Clip, CLIP);
265 }
266 }
267
268 return NULL;
269 }
270
271 /*
272 * @implemented
273 */
274 CLIPOBJ * APIENTRY
275 EngCreateClip(VOID)
276 {
277 CLIPGDI *Clip = EngAllocMem(FL_ZERO_MEMORY, sizeof(CLIPGDI), TAG_CLIPOBJ);
278 if(Clip != NULL)
279 {
280 return GDIToObj(Clip, CLIP);
281 }
282
283 return NULL;
284 }
285
286 /*
287 * @implemented
288 */
289 VOID APIENTRY
290 EngDeleteClip(CLIPOBJ *ClipRegion)
291 {
292 EngFreeMem(ObjToGDI(ClipRegion, CLIP));
293 }
294
295 /*
296 * @implemented
297 */
298 ULONG APIENTRY
299 CLIPOBJ_cEnumStart(
300 IN CLIPOBJ* ClipObj,
301 IN BOOL ShouldDoAll,
302 IN ULONG ClipType,
303 IN ULONG BuildOrder,
304 IN ULONG MaxRects)
305 {
306 CLIPGDI *ClipGDI = ObjToGDI(ClipObj, CLIP);
307 SORTCOMP CompareFunc;
308
309 ClipGDI->EnumPos = 0;
310 ClipGDI->EnumMax = (MaxRects > 0) ? MaxRects : ClipGDI->EnumRects.c;
311
312 if (CD_ANY != BuildOrder && ClipGDI->EnumOrder != BuildOrder)
313 {
314 switch (BuildOrder)
315 {
316 case CD_RIGHTDOWN:
317 CompareFunc = (SORTCOMP) CompareRightDown;
318 break;
319
320 case CD_RIGHTUP:
321 CompareFunc = (SORTCOMP) CompareRightUp;
322 break;
323
324 case CD_LEFTDOWN:
325 CompareFunc = (SORTCOMP) CompareLeftDown;
326 break;
327
328 case CD_LEFTUP:
329 CompareFunc = (SORTCOMP) CompareLeftUp;
330 break;
331
332 default:
333 DPRINT1("Invalid BuildOrder %d\n", BuildOrder);
334 BuildOrder = ClipGDI->EnumOrder;
335 CompareFunc = NULL;
336 break;
337 }
338
339 if (NULL != CompareFunc)
340 {
341 EngSort((PBYTE) ClipGDI->EnumRects.arcl, sizeof(RECTL), ClipGDI->EnumRects.c, CompareFunc);
342 }
343
344 ClipGDI->EnumOrder = BuildOrder;
345 }
346
347 /* Return the number of rectangles enumerated */
348 if ((MaxRects > 0) && (ClipGDI->EnumRects.c > MaxRects))
349 {
350 return 0xFFFFFFFF;
351 }
352
353 return ClipGDI->EnumRects.c;
354 }
355
356 /*
357 * @implemented
358 */
359 BOOL APIENTRY
360 CLIPOBJ_bEnum(
361 IN CLIPOBJ* ClipObj,
362 IN ULONG ObjSize,
363 OUT ULONG *EnumRects)
364 {
365 RECTL *dest, *src;
366 CLIPGDI *ClipGDI = ObjToGDI(ClipObj, CLIP);
367 ULONG nCopy, i;
368 ENUMRECTS* pERects = (ENUMRECTS*)EnumRects;
369
370 //calculate how many rectangles we should copy
371 nCopy = min( ClipGDI->EnumMax - ClipGDI->EnumPos,
372 min( ClipGDI->EnumRects.c - ClipGDI->EnumPos,
373 (ObjSize - sizeof(ULONG)) / sizeof(RECTL)));
374
375 if(nCopy == 0)
376 {
377 return FALSE;
378 }
379
380 /* copy rectangles */
381 src = ClipGDI->EnumRects.arcl + ClipGDI->EnumPos;
382 for(i = 0, dest = pERects->arcl; i < nCopy; i++, dest++, src++)
383 {
384 *dest = *src;
385 }
386
387 pERects->c = nCopy;
388
389 ClipGDI->EnumPos+=nCopy;
390
391 return ClipGDI->EnumPos < ClipGDI->EnumRects.c;
392 }
393
394 BOOLEAN FASTCALL
395 ClipobjToSpans(
396 PSPAN *Spans,
397 UINT *Count,
398 CLIPOBJ *ClipRegion,
399 PRECTL Boundary)
400 {
401 BOOL EnumMore;
402 UINT i, NewCount;
403 RECT_ENUM RectEnum;
404 PSPAN NewSpans;
405 RECTL *Rect;
406
407 ASSERT(Boundary->top <= Boundary->bottom && Boundary->left <= Boundary->right);
408
409 *Count = Boundary->bottom - Boundary->top;
410 if (*Count > 0)
411 {
412 *Spans = ExAllocatePoolWithTag(PagedPool, *Count * sizeof(SPAN), TAG_CLIP);
413 if (NULL == *Spans)
414 {
415 *Count = 0;
416 return FALSE;
417 }
418 }
419
420 if (NULL == ClipRegion || DC_TRIVIAL == ClipRegion->iDComplexity)
421 {
422 if (0 != *Count)
423 {
424 for (i = 0; i < Boundary->bottom - Boundary->top; i++)
425 {
426 (*Spans)[i].X = Boundary->left;
427 (*Spans)[i].Y = Boundary->top + i;
428 (*Spans)[i].Width = Boundary->right - Boundary->left;
429 }
430 }
431 return TRUE;
432 }
433
434 *Count = 0;
435 CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, CD_ANY, 0);
436 do
437 {
438 EnumMore = CLIPOBJ_bEnum(ClipRegion, (ULONG) sizeof(RECT_ENUM), (PVOID) &RectEnum);
439
440 NewCount = *Count;
441 for (i = 0; i < RectEnum.c; i++)
442 {
443 NewCount += RectEnum.arcl[i].bottom - RectEnum.arcl[i].top;
444 }
445 if (NewCount != *Count)
446 {
447 NewSpans = ExAllocatePoolWithTag(PagedPool, NewCount * sizeof(SPAN), TAG_CLIP);
448 if (NULL == NewSpans)
449 {
450 if (NULL != *Spans)
451 {
452 ExFreePoolWithTag(*Spans, TAG_CLIP);
453 *Spans = NULL;
454 }
455 *Count = 0;
456 return FALSE;
457 }
458 if (0 != *Count)
459 {
460 PSPAN dest, src;
461 UINT i = *Count;
462 for(dest = NewSpans, src = *Spans;i > 0; i--)
463 {
464 *dest++ = *src++;
465 }
466 ExFreePoolWithTag(*Spans, TAG_CLIP);
467 }
468 *Spans = NewSpans;
469 }
470 for (Rect = RectEnum.arcl; Rect < RectEnum.arcl + RectEnum.c; Rect++)
471 {
472 for (i = 0; i < Rect->bottom - Rect->top; i++)
473 {
474 (*Spans)[*Count].X = Rect->left;
475 (*Spans)[*Count].Y = Rect->top + i;
476 (*Spans)[*Count].Width = Rect->right - Rect->left;
477 (*Count)++;
478 }
479 }
480 ASSERT(*Count == NewCount);
481 }
482 while (EnumMore);
483
484 if (0 != *Count)
485 {
486 EngSort((PBYTE) *Spans, sizeof(SPAN), *Count, (SORTCOMP) CompareSpans);
487 }
488
489 return TRUE;
490 }
491
492 /* EOF */