- Sync up Mm interface with WinLdr branch (introduce the concept of a memory type...
[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(const PRECT r1, const PRECT r2)
37 {
38 int Cmp;
39
40 if (r1->top < r2->top)
41 {
42 Cmp = -1;
43 }
44 else if (r2->top < r1->top)
45 {
46 Cmp = +1;
47 }
48 else
49 {
50 ASSERT(r1->bottom == r2->bottom);
51 if (r1->left < r2->left)
52 {
53 Cmp = -1;
54 }
55 else if (r2->left < r1->left)
56 {
57 Cmp = +1;
58 }
59 else
60 {
61 ASSERT(r1->right == r2->right);
62 Cmp = 0;
63 }
64 }
65
66 return Cmp;
67 }
68
69 static __inline int
70 CompareRightUp(const PRECT r1, const PRECT r2)
71 {
72 int Cmp;
73
74 if (r1->bottom < r2->bottom)
75 {
76 Cmp = +1;
77 }
78 else if (r2->bottom < r1->bottom)
79 {
80 Cmp = -1;
81 }
82 else
83 {
84 ASSERT(r1->top == r2->top);
85 if (r1->left < r2->left)
86 {
87 Cmp = -1;
88 }
89 else if (r2->left < r1->left)
90 {
91 Cmp = +1;
92 }
93 else
94 {
95 ASSERT(r1->right == r2->right);
96 Cmp = 0;
97 }
98 }
99
100 return Cmp;
101 }
102
103 static __inline int
104 CompareLeftDown(const PRECT r1, const PRECT r2)
105 {
106 int Cmp;
107
108 if (r1->top < r2->top)
109 {
110 Cmp = -1;
111 }
112 else if (r2->top < r1->top)
113 {
114 Cmp = +1;
115 }
116 else
117 {
118 ASSERT(r1->bottom == r2->bottom);
119 if (r1->right < r2->right)
120 {
121 Cmp = +1;
122 }
123 else if (r2->right < r1->right)
124 {
125 Cmp = -1;
126 }
127 else
128 {
129 ASSERT(r1->left == r2->left);
130 Cmp = 0;
131 }
132 }
133
134 return Cmp;
135 }
136
137 static __inline int
138 CompareLeftUp(const PRECT r1, const PRECT r2)
139 {
140 int Cmp;
141
142 if (r1->bottom < r2->bottom)
143 {
144 Cmp = +1;
145 }
146 else if (r2->bottom < r1->bottom)
147 {
148 Cmp = -1;
149 }
150 else
151 {
152 ASSERT(r1->top == r2->top);
153 if (r1->right < r2->right)
154 {
155 Cmp = +1;
156 }
157 else if (r2->right < r1->right)
158 {
159 Cmp = -1;
160 }
161 else
162 {
163 ASSERT(r1->left == r2->left);
164 Cmp = 0;
165 }
166 }
167
168 return Cmp;
169 }
170
171 static __inline int
172 CompareSpans(const PSPAN Span1, const PSPAN Span2)
173 {
174 int Cmp;
175
176 if (Span1->Y < Span2->Y)
177 {
178 Cmp = -1;
179 }
180 else if (Span2->Y < Span1->Y)
181 {
182 Cmp = +1;
183 }
184 else
185 {
186 if (Span1->X < Span2->X)
187 {
188 Cmp = -1;
189 }
190 else if (Span2->X < Span1->X)
191 {
192 Cmp = +1;
193 }
194 else
195 {
196 Cmp = 0;
197 }
198 }
199
200 return Cmp;
201 }
202
203 VOID FASTCALL
204 IntEngDeleteClipRegion(CLIPOBJ *ClipObj)
205 {
206 EngFreeMem(ObjToGDI(ClipObj, CLIP));
207 }
208
209 CLIPOBJ* FASTCALL
210 IntEngCreateClipRegion(ULONG count, PRECTL pRect, PRECTL rcBounds)
211 {
212 CLIPGDI *Clip;
213
214 if(count > 1)
215 {
216 RECTL *dest;
217
218 Clip = EngAllocMem(0, sizeof(CLIPGDI) + ((count - 1) * sizeof(RECTL)), TAG_CLIPOBJ);
219
220 if(Clip != NULL)
221 {
222 Clip->EnumRects.c = count;
223 Clip->EnumOrder = CD_ANY;
224 for(dest = Clip->EnumRects.arcl;
225 count > 0;
226 count--, dest++, pRect++)
227 {
228 *dest = *pRect;
229 }
230
231 Clip->ClipObj.iDComplexity = DC_COMPLEX;
232 Clip->ClipObj.iFComplexity = ((Clip->EnumRects.c <= 4) ? FC_RECT4 : FC_COMPLEX);
233 Clip->ClipObj.iMode = TC_RECTANGLES;
234 Clip->ClipObj.rclBounds = *rcBounds;
235
236 return GDIToObj(Clip, CLIP);
237 }
238 }
239 else
240 {
241 Clip = EngAllocMem(0, sizeof(CLIPGDI), TAG_CLIPOBJ);
242
243 if(Clip != NULL)
244 {
245 Clip->EnumRects.c = 1;
246 Clip->EnumOrder = CD_ANY;
247 Clip->EnumRects.arcl[0] = *rcBounds;
248
249 Clip->ClipObj.iDComplexity = (((rcBounds->top == rcBounds->bottom) &&
250 (rcBounds->left == rcBounds->right))
251 ? DC_TRIVIAL : DC_RECT);
252 Clip->ClipObj.iFComplexity = FC_RECT;
253 Clip->ClipObj.iMode = TC_RECTANGLES;
254 Clip->ClipObj.rclBounds = *rcBounds;
255
256 return GDIToObj(Clip, CLIP);
257 }
258 }
259
260 return NULL;
261 }
262
263 /*
264 * @implemented
265 */
266 CLIPOBJ * STDCALL
267 EngCreateClip(VOID)
268 {
269 CLIPGDI *Clip = EngAllocMem(FL_ZERO_MEMORY, sizeof(CLIPOBJ), TAG_CLIPOBJ);
270 if(Clip != NULL)
271 {
272 return GDIToObj(Clip, CLIP);
273 }
274
275 return NULL;
276 }
277
278 /*
279 * @implemented
280 */
281 VOID STDCALL
282 EngDeleteClip(CLIPOBJ *ClipRegion)
283 {
284 EngFreeMem(ObjToGDI(ClipRegion, CLIP));
285 }
286
287 /*
288 * @implemented
289 */
290 ULONG STDCALL
291 CLIPOBJ_cEnumStart(IN CLIPOBJ* ClipObj,
292 IN BOOL ShouldDoAll,
293 IN ULONG ClipType,
294 IN ULONG BuildOrder,
295 IN ULONG MaxRects)
296 {
297 CLIPGDI *ClipGDI = ObjToGDI(ClipObj, CLIP);
298 SORTCOMP CompareFunc;
299
300 ClipGDI->EnumPos = 0;
301 ClipGDI->EnumMax = (MaxRects > 0) ? MaxRects : ClipGDI->EnumRects.c;
302
303 if (CD_ANY != BuildOrder && ClipGDI->EnumOrder != BuildOrder)
304 {
305 switch (BuildOrder)
306 {
307 case CD_RIGHTDOWN:
308 CompareFunc = (SORTCOMP) CompareRightDown;
309 break;
310 case CD_RIGHTUP:
311 CompareFunc = (SORTCOMP) CompareRightUp;
312 break;
313 case CD_LEFTDOWN:
314 CompareFunc = (SORTCOMP) CompareLeftDown;
315 break;
316 case CD_LEFTUP:
317 CompareFunc = (SORTCOMP) CompareLeftUp;
318 break;
319 default:
320 DPRINT1("Invalid BuildOrder %d\n", BuildOrder);
321 BuildOrder = ClipGDI->EnumOrder;
322 CompareFunc = NULL;
323 break;
324 }
325
326 if (NULL != CompareFunc)
327 {
328 EngSort((PBYTE) ClipGDI->EnumRects.arcl, sizeof(RECTL), ClipGDI->EnumRects.c,
329 CompareFunc);
330 }
331
332 ClipGDI->EnumOrder = BuildOrder;
333 }
334
335 /* Return the number of rectangles enumerated */
336 if ((MaxRects > 0) && (ClipGDI->EnumRects.c > MaxRects))
337 {
338 return 0xFFFFFFFF;
339 }
340
341 return ClipGDI->EnumRects.c;
342 }
343
344 /*
345 * @implemented
346 */
347 BOOL STDCALL
348 CLIPOBJ_bEnum(IN CLIPOBJ* ClipObj,
349 IN ULONG ObjSize,
350 OUT ULONG *EnumRects)
351 {
352 RECTL *dest, *src;
353 CLIPGDI *ClipGDI = ObjToGDI(ClipObj, CLIP);
354 ULONG nCopy, i;
355 ENUMRECTS* pERects = (ENUMRECTS*)EnumRects;
356
357 //calculate how many rectangles we should copy
358 nCopy = min( ClipGDI->EnumMax - ClipGDI->EnumPos,
359 min( ClipGDI->EnumRects.c - ClipGDI->EnumPos,
360 (ObjSize - sizeof(ULONG)) / sizeof(RECTL)));
361 if(nCopy == 0)
362 {
363 return FALSE;
364 }
365
366 /* copy rectangles */
367 src = ClipGDI->EnumRects.arcl + ClipGDI->EnumPos;
368 for(i = 0, dest = pERects->arcl;
369 i < nCopy;
370 i++, dest++, src++)
371 {
372 *dest = *src;
373 }
374
375 pERects->c = nCopy;
376
377 ClipGDI->EnumPos+=nCopy;
378
379 return ClipGDI->EnumPos < ClipGDI->EnumRects.c;
380 }
381
382 BOOLEAN FASTCALL
383 ClipobjToSpans(PSPAN *Spans, UINT *Count, CLIPOBJ *ClipRegion, PRECTL Boundary)
384 {
385 BOOL EnumMore;
386 UINT i, NewCount;
387 RECT_ENUM RectEnum;
388 PSPAN NewSpans;
389 RECTL *Rect;
390
391 ASSERT(Boundary->top <= Boundary->bottom && Boundary->left <= Boundary->right);
392
393 *Spans = NULL;
394 if (NULL == ClipRegion || DC_TRIVIAL == ClipRegion->iDComplexity)
395 {
396 *Count = Boundary->bottom - Boundary->top;
397 if (0 != *Count)
398 {
399 *Spans = ExAllocatePoolWithTag(PagedPool, *Count * sizeof(SPAN), TAG_CLIP);
400 if (NULL == *Spans)
401 {
402 *Count = 0;
403 return FALSE;
404 }
405 for (i = 0; i < Boundary->bottom - Boundary->top; i++)
406 {
407 (*Spans)[i].X = Boundary->left;
408 (*Spans)[i].Y = Boundary->top + i;
409 (*Spans)[i].Width = Boundary->right - Boundary->left;
410 }
411 }
412
413 return TRUE;
414 }
415
416 *Count = 0;
417 CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, CD_ANY, 0);
418 do
419 {
420 EnumMore = CLIPOBJ_bEnum(ClipRegion, (ULONG) sizeof(RECT_ENUM), (PVOID) &RectEnum);
421
422 NewCount = *Count;
423 for (i = 0; i < RectEnum.c; i++)
424 {
425 NewCount += RectEnum.arcl[i].bottom - RectEnum.arcl[i].top;
426 }
427 if (NewCount != *Count)
428 {
429 NewSpans = ExAllocatePoolWithTag(PagedPool, NewCount * sizeof(SPAN), TAG_CLIP);
430 if (NULL == NewSpans)
431 {
432 if (NULL != *Spans)
433 {
434 ExFreePool(*Spans);
435 *Spans = NULL;
436 }
437 *Count = 0;
438 return FALSE;
439 }
440 if (0 != *Count)
441 {
442 PSPAN dest, src;
443 UINT i = *Count;
444 for(dest = NewSpans, src = *Spans;
445 i > 0;
446 i--)
447 {
448 *dest++ = *src++;
449 }
450 ExFreePool(*Spans);
451 }
452 *Spans = NewSpans;
453 }
454 for (Rect = RectEnum.arcl; Rect < RectEnum.arcl + RectEnum.c; Rect++)
455 {
456 for (i = 0; i < Rect->bottom - Rect->top; i++)
457 {
458 (*Spans)[*Count].X = Rect->left;
459 (*Spans)[*Count].Y = Rect->top + i;
460 (*Spans)[*Count].Width = Rect->right - Rect->left;
461 (*Count)++;
462 }
463 }
464 ASSERT(*Count == NewCount);
465 }
466 while (EnumMore);
467
468 if (0 != *Count)
469 {
470 EngSort((PBYTE) *Spans, sizeof(SPAN), *Count, (SORTCOMP) CompareSpans);
471 }
472
473 return TRUE;
474 }
475
476 /* EOF */