xref: /reactos/win32ss/gdi/eng/clip.c (revision c2c66aff)
1 /*
2  * COPYRIGHT:         See COPYING in the top level directory
3  * PROJECT:           ReactOS kernel
4  * PURPOSE:           GDI Clipping Functions
5  * FILE:              win32ss/gdi/eng/clip.c
6  * PROGRAMER:         Jason Filby
7  */
8 
9 #include <win32k.h>
10 DBG_DEFAULT_CHANNEL(EngClip);
11 
12 
13 static __inline int
CompareRightDown(const RECTL * r1,const RECTL * r2)14 CompareRightDown(
15     const RECTL *r1,
16     const RECTL *r2)
17 {
18     int Cmp;
19 
20     if (r1->top < r2->top)
21     {
22         Cmp = -1;
23     }
24     else if (r2->top < r1->top)
25     {
26         Cmp = +1;
27     }
28     else
29     {
30         ASSERT(r1->bottom == r2->bottom);
31         if (r1->left < r2->left)
32         {
33             Cmp = -1;
34         }
35         else if (r2->left < r1->left)
36         {
37             Cmp = +1;
38         }
39         else
40         {
41             ASSERT(r1->right == r2->right);
42             Cmp = 0;
43         }
44     }
45 
46     return Cmp;
47 }
48 
49 static __inline int
CompareRightUp(const RECTL * r1,const RECTL * r2)50 CompareRightUp(
51     const RECTL *r1,
52     const RECTL *r2)
53 {
54     int Cmp;
55 
56     if (r1->bottom < r2->bottom)
57     {
58         Cmp = +1;
59     }
60     else if (r2->bottom < r1->bottom)
61     {
62         Cmp = -1;
63     }
64     else
65     {
66         ASSERT(r1->top == r2->top);
67         if (r1->left < r2->left)
68         {
69             Cmp = -1;
70         }
71         else if (r2->left < r1->left)
72         {
73             Cmp = +1;
74         }
75         else
76         {
77             ASSERT(r1->right == r2->right);
78             Cmp = 0;
79         }
80     }
81 
82     return Cmp;
83 }
84 
85 static __inline int
CompareLeftDown(const RECTL * r1,const RECTL * r2)86 CompareLeftDown(
87     const RECTL *r1,
88     const RECTL *r2)
89 {
90     int Cmp;
91 
92     if (r1->top < r2->top)
93     {
94         Cmp = -1;
95     }
96     else if (r2->top < r1->top)
97     {
98         Cmp = +1;
99     }
100     else
101     {
102         ASSERT(r1->bottom == r2->bottom);
103         if (r1->right < r2->right)
104         {
105             Cmp = +1;
106         }
107         else if (r2->right < r1->right)
108         {
109             Cmp = -1;
110         }
111         else
112         {
113             ASSERT(r1->left == r2->left);
114             Cmp = 0;
115         }
116     }
117 
118     return Cmp;
119 }
120 
121 static __inline int
CompareLeftUp(const RECTL * r1,const RECTL * r2)122 CompareLeftUp(
123     const RECTL *r1,
124     const RECTL *r2)
125 {
126     int Cmp;
127 
128     if (r1->bottom < r2->bottom)
129     {
130         Cmp = +1;
131     }
132     else if (r2->bottom < r1->bottom)
133     {
134         Cmp = -1;
135     }
136     else
137     {
138         ASSERT(r1->top == r2->top);
139         if (r1->right < r2->right)
140         {
141             Cmp = +1;
142         }
143         else if (r2->right < r1->right)
144         {
145             Cmp = -1;
146         }
147         else
148         {
149             ASSERT(r1->left == r2->left);
150             Cmp = 0;
151         }
152     }
153     return Cmp;
154 }
155 
156 VOID
157 FASTCALL
IntEngInitClipObj(XCLIPOBJ * Clip)158 IntEngInitClipObj(XCLIPOBJ *Clip)
159 {
160     Clip->Rects = &Clip->rclBounds;
161 }
162 
163 VOID FASTCALL
IntEngFreeClipResources(XCLIPOBJ * Clip)164 IntEngFreeClipResources(XCLIPOBJ *Clip)
165 {
166     if (Clip->Rects != &Clip->rclBounds)
167         EngFreeMem(Clip->Rects);
168 }
169 
170 
171 VOID
172 FASTCALL
IntEngUpdateClipRegion(XCLIPOBJ * Clip,ULONG count,const RECTL * pRect,const RECTL * rcBounds)173 IntEngUpdateClipRegion(
174     XCLIPOBJ* Clip,
175     ULONG count,
176     const RECTL* pRect,
177     const RECTL* rcBounds)
178 {
179     if(count > 1)
180     {
181         RECTL* NewRects = EngAllocMem(0, FIELD_OFFSET(ENUMRECTS, arcl[count]), GDITAG_CLIPOBJ);
182 
183         if(NewRects != NULL)
184         {
185             Clip->RectCount = count;
186             Clip->iDirection = CD_ANY;
187             RtlCopyMemory(NewRects, pRect, count * sizeof(RECTL));
188 
189             Clip->iDComplexity = DC_COMPLEX;
190             Clip->iFComplexity = ((Clip->RectCount <= 4) ? FC_RECT4 : FC_COMPLEX);
191             Clip->iMode = TC_RECTANGLES;
192             Clip->rclBounds = *rcBounds;
193 
194             if (Clip->Rects != &Clip->rclBounds)
195                 EngFreeMem(Clip->Rects);
196             Clip->Rects = NewRects;
197         }
198     }
199     else
200     {
201         Clip->iDirection = CD_ANY;
202 
203         Clip->iDComplexity = (((rcBounds->top == rcBounds->bottom) &&
204                                      (rcBounds->left == rcBounds->right))
205                                      ? DC_TRIVIAL : DC_RECT);
206 
207         Clip->iFComplexity = FC_RECT;
208         Clip->iMode = TC_RECTANGLES;
209         Clip->rclBounds = *rcBounds;
210         Clip->RectCount = 1;
211         if (Clip->Rects != &Clip->rclBounds)
212             EngFreeMem(Clip->Rects);
213         Clip->Rects = &Clip->rclBounds;
214     }
215 }
216 
217 /*
218  * @implemented
219  */
220 CLIPOBJ *
221 APIENTRY
EngCreateClip(VOID)222 EngCreateClip(VOID)
223 {
224     XCLIPOBJ *Clip = EngAllocMem(FL_ZERO_MEMORY, sizeof(XCLIPOBJ), GDITAG_CLIPOBJ);
225     if(Clip != NULL)
226     {
227         IntEngInitClipObj(Clip);
228         TRACE("Created Clip Obj %p.\n", Clip);
229         return (CLIPOBJ *)Clip;
230     }
231 
232     ERR("Clip object allocation failed!\n");
233     return NULL;
234 }
235 
236 /*
237  * @implemented
238  */
239 VOID
240 APIENTRY
EngDeleteClip(_In_ _Post_ptr_invalid_ CLIPOBJ * pco)241 EngDeleteClip(
242     _In_ _Post_ptr_invalid_ CLIPOBJ *pco)
243 {
244     XCLIPOBJ* pxco = (XCLIPOBJ *)pco;
245     TRACE("Deleting %p.\n", pco);
246     IntEngFreeClipResources(pxco);
247     EngFreeMem(pxco);
248 }
249 
250 /*
251  * @implemented
252  */
253 ULONG
254 APIENTRY
CLIPOBJ_cEnumStart(_Inout_ CLIPOBJ * pco,_In_ BOOL bAll,_In_ ULONG iType,_In_ ULONG iDirection,_In_ ULONG cMaxRects)255 CLIPOBJ_cEnumStart(
256     _Inout_ CLIPOBJ *pco,
257     _In_ BOOL bAll,
258     _In_ ULONG iType,
259     _In_ ULONG iDirection,
260     _In_ ULONG cMaxRects)
261 {
262     XCLIPOBJ* Clip = (XCLIPOBJ *)pco;
263     SORTCOMP CompareFunc;
264 
265     Clip->bAll    = bAll;
266     Clip->iType   = iType;
267     Clip->EnumPos = 0;
268     Clip->EnumMax = (cMaxRects > 0) ? cMaxRects : Clip->RectCount;
269 
270     if (CD_ANY != iDirection && Clip->iDirection != iDirection)
271     {
272         switch (iDirection)
273         {
274             case CD_RIGHTDOWN:
275                 CompareFunc = (SORTCOMP) CompareRightDown;
276                 break;
277 
278             case CD_RIGHTUP:
279                 CompareFunc = (SORTCOMP) CompareRightUp;
280                 break;
281 
282             case CD_LEFTDOWN:
283                 CompareFunc = (SORTCOMP) CompareLeftDown;
284                 break;
285 
286             case CD_LEFTUP:
287                 CompareFunc = (SORTCOMP) CompareLeftUp;
288                 break;
289 
290             default:
291                 ERR("Invalid iDirection %lu\n", iDirection);
292                 iDirection = Clip->iDirection;
293                 CompareFunc = NULL;
294                 break;
295         }
296 
297         if (NULL != CompareFunc)
298         {
299             EngSort((PBYTE) Clip->Rects, sizeof(RECTL), Clip->RectCount, CompareFunc);
300         }
301 
302         Clip->iDirection = iDirection;
303     }
304 
305     /* Return the number of rectangles enumerated */
306     if ((cMaxRects > 0) && (Clip->RectCount > cMaxRects))
307     {
308         return 0xFFFFFFFF;
309     }
310 
311     return Clip->RectCount;
312 }
313 
314 /*
315  * @implemented
316  */
317 BOOL
318 APIENTRY
CLIPOBJ_bEnum(_In_ CLIPOBJ * pco,_In_ ULONG cj,_Out_bytecap_ (cj)ULONG * pulEnumRects)319 CLIPOBJ_bEnum(
320     _In_ CLIPOBJ *pco,
321     _In_ ULONG cj,
322     _Out_bytecap_(cj) ULONG *pulEnumRects)
323 {
324     const RECTL* src;
325     XCLIPOBJ* Clip = (XCLIPOBJ *)pco;
326     ULONG nCopy;
327     ENUMRECTS* pERects = (ENUMRECTS*)pulEnumRects;
328 
329     // Calculate how many rectangles we should copy
330     nCopy = min( Clip->EnumMax - Clip->EnumPos,
331             min( Clip->RectCount - Clip->EnumPos,
332             (cj - sizeof(ULONG)) / sizeof(RECTL)));
333 
334     if(nCopy == 0)
335     {
336         return FALSE;
337     }
338 
339     /* Copy rectangles */
340     src = &Clip->Rects[Clip->EnumPos];
341     RtlCopyMemory(pERects->arcl, src, nCopy * sizeof(RECTL));
342 
343     pERects->c = nCopy;
344 
345     Clip->EnumPos+=nCopy;
346 
347     return Clip->EnumPos < Clip->RectCount;
348 }
349 
350 /* EOF */
351