1 /*
2 Copyright 2005-2017 Jay Sorg
3 
4 Permission to use, copy, modify, distribute, and sell this software and its
5 documentation for any purpose is hereby granted without fee, provided that
6 the above copyright notice appear in all copies and that both that
7 copyright notice and this permission notice appear in supporting
8 documentation.
9 
10 The above copyright notice and this permission notice shall be included in
11 all copies or substantial portions of the Software.
12 
13 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
16 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
17 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 
20 misc draw calls
21 
22 */
23 
24 #if defined(HAVE_CONFIG_H)
25 #include "config_ac.h"
26 #endif
27 
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 
32 /* this should be before all X11 .h files */
33 #include <xorg-server.h>
34 #include <xorgVersion.h>
35 
36 /* all driver need this */
37 #include <xf86.h>
38 #include <xf86_OSproc.h>
39 
40 #include <mipointer.h>
41 #include <fb.h>
42 #include <micmap.h>
43 #include <mi.h>
44 #include <dixfontstr.h>
45 
46 #include "rdp.h"
47 #include "rdpDraw.h"
48 #include "rdpClientCon.h"
49 #include "rdpMisc.h"
50 #include "rdpGlyphs.h"
51 #include "rdpReg.h"
52 #include "rdpMain.h"
53 
54 #define LOG_LEVEL 1
55 #define LLOGLN(_level, _args) \
56     do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0)
57 
58 #if !defined(XORG_VERSION_CURRENT)
59 #warning XORG_VERSION_CURRENT not defined
60 #endif
61 
62 /******************************************************************************/
63 static int
is_clientClip_region(GCPtr gc)64 is_clientClip_region(GCPtr gc)
65 {
66 #if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1, 16, 99, 901, 0)
67     return gc->clientClipType == CT_REGION;
68 #else
69     return gc->clientClip != NULL;
70 #endif
71 }
72 
73 /******************************************************************************/
74 /* return 0, draw nothing */
75 /* return 1, draw with no clip */
76 /* return 2, draw using clip */
77 int
rdpDrawGetClip(rdpPtr dev,RegionPtr pRegion,DrawablePtr pDrawable,GCPtr pGC)78 rdpDrawGetClip(rdpPtr dev, RegionPtr pRegion, DrawablePtr pDrawable, GCPtr pGC)
79 {
80     WindowPtr pWindow;
81     RegionPtr temp;
82     BoxRec box;
83     int rv;
84 
85     rv = 0;
86 
87     if (pDrawable->type == DRAWABLE_PIXMAP)
88     {
89         if (is_clientClip_region(pGC))
90         {
91             miComputeCompositeClip(pGC, pDrawable);
92             RegionCopy(pRegion, pGC->pCompositeClip);
93             rv = 2;
94         }
95         else
96         {
97             rv = 1;
98         }
99 
100         if (rv == 2) /* check if the clip is the entire pixmap */
101         {
102             box.x1 = 0;
103             box.y1 = 0;
104             box.x2 = pDrawable->width;
105             box.y2 = pDrawable->height;
106 
107             if (rdpRegionContainsRect(pRegion, &box) == rgnIN)
108             {
109                 rv = 1;
110             }
111         }
112     }
113     else if (pDrawable->type == DRAWABLE_WINDOW)
114     {
115         pWindow = (WindowPtr)pDrawable;
116 
117         if (pWindow->viewable)
118         {
119             if (pGC->subWindowMode == IncludeInferiors)
120             {
121                 temp = &pWindow->borderClip;
122             }
123             else
124             {
125                 temp = &pWindow->clipList;
126             }
127 
128             if (rdpRegionNotEmpty(temp))
129             {
130                 if (is_clientClip_region(pGC))
131                 {
132                     rdpRegionCopy(pRegion, pGC->clientClip);
133                     rdpRegionTranslate(pRegion,
134                                        pDrawable->x + pGC->clipOrg.x,
135                                        pDrawable->y + pGC->clipOrg.y);
136                     rdpRegionIntersect(pRegion, pRegion, temp);
137                     rv = 2;
138                 }
139                 else
140                 {
141                     rdpRegionCopy(pRegion, temp);
142                     rv = 2;
143                 }
144 
145                 if (rv == 2) /* check if the clip is the entire screen */
146                 {
147                     box.x1 = 0;
148                     box.y1 = 0;
149                     box.x2 = dev->width;
150                     box.y2 = dev->height;
151 
152                     if (rdpRegionContainsRect(pRegion, &box) == rgnIN)
153                     {
154                         rv = 1;
155                     }
156                 }
157             }
158         }
159     }
160 
161     return rv;
162 }
163 
164 /******************************************************************************/
165 void
GetTextBoundingBox(DrawablePtr pDrawable,FontPtr font,int x,int y,int n,BoxPtr pbox)166 GetTextBoundingBox(DrawablePtr pDrawable, FontPtr font, int x, int y,
167                    int n, BoxPtr pbox)
168 {
169     int maxAscent;
170     int maxDescent;
171     int maxCharWidth;
172 
173     if (FONTASCENT(font) > FONTMAXBOUNDS(font, ascent))
174     {
175         maxAscent = FONTASCENT(font);
176     }
177     else
178     {
179         maxAscent = FONTMAXBOUNDS(font, ascent);
180     }
181 
182     if (FONTDESCENT(font) > FONTMAXBOUNDS(font, descent))
183     {
184         maxDescent = FONTDESCENT(font);
185     }
186     else
187     {
188         maxDescent = FONTMAXBOUNDS(font, descent);
189     }
190 
191     if (FONTMAXBOUNDS(font, rightSideBearing) >
192             FONTMAXBOUNDS(font, characterWidth))
193     {
194         maxCharWidth = FONTMAXBOUNDS(font, rightSideBearing);
195     }
196     else
197     {
198         maxCharWidth = FONTMAXBOUNDS(font, characterWidth);
199     }
200 
201     pbox->x1 = pDrawable->x + x;
202     pbox->y1 = pDrawable->y + y - maxAscent;
203     pbox->x2 = pbox->x1 + maxCharWidth * n;
204     pbox->y2 = pbox->y1 + maxAscent + maxDescent;
205 
206     if (FONTMINBOUNDS(font, leftSideBearing) < 0)
207     {
208         pbox->x1 += FONTMINBOUNDS(font, leftSideBearing);
209     }
210 }
211 
212 /******************************************************************************/
213 int
rdpDrawItemAdd(rdpPtr dev,rdpPixmapRec * priv,struct rdp_draw_item * di)214 rdpDrawItemAdd(rdpPtr dev, rdpPixmapRec *priv, struct rdp_draw_item *di)
215 {
216     priv->is_alpha_dirty_not = FALSE;
217 
218     if (priv->draw_item_tail == NULL)
219     {
220         priv->draw_item_tail = di;
221         priv->draw_item_head = di;
222     }
223     else
224     {
225         di->prev = priv->draw_item_tail;
226         priv->draw_item_tail->next = di;
227         priv->draw_item_tail = di;
228     }
229 
230     if (priv == &(dev->screenPriv))
231     {
232         rdpClientConScheduleDeferredUpdate(dev);
233     }
234 
235     return 0;
236 }
237 
238 /******************************************************************************/
239 int
rdpDrawItemRemove(rdpPtr dev,rdpPixmapRec * priv,struct rdp_draw_item * di)240 rdpDrawItemRemove(rdpPtr dev, rdpPixmapRec *priv, struct rdp_draw_item *di)
241 {
242     if (di->prev != NULL)
243     {
244         di->prev->next = di->next;
245     }
246 
247     if (di->next != NULL)
248     {
249         di->next->prev = di->prev;
250     }
251 
252     if (priv->draw_item_head == di)
253     {
254         priv->draw_item_head = di->next;
255     }
256 
257     if (priv->draw_item_tail == di)
258     {
259         priv->draw_item_tail = di->prev;
260     }
261 
262     if (di->type == RDI_LINE)
263     {
264         if (di->u.line.segs != NULL)
265         {
266             free(di->u.line.segs);
267         }
268     }
269 
270     if (di->type == RDI_TEXT)
271     {
272         rdpGlyphDeleteRdpText(di->u.text.rtext);
273     }
274 
275     rdpRegionDestroy(di->reg);
276     free(di);
277     return 0;
278 }
279 
280 /******************************************************************************/
281 int
rdpDrawItemRemoveAll(rdpPtr dev,rdpPixmapRec * priv)282 rdpDrawItemRemoveAll(rdpPtr dev, rdpPixmapRec *priv)
283 {
284     struct rdp_draw_item *di;
285 
286     di = priv->draw_item_head;
287 
288     while (di != NULL)
289     {
290         rdpDrawItemRemove(dev, priv, di);
291         di = priv->draw_item_head;
292     }
293 
294     return 0;
295 }
296 
297 /*****************************************************************************/
298 void
rdpCopyWindow(WindowPtr pWin,DDXPointRec ptOldOrg,RegionPtr pOldRegion)299 rdpCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr pOldRegion)
300 {
301     ScreenPtr pScreen;
302     rdpPtr dev;
303     RegionRec reg;
304     RegionRec clip;
305     int dx;
306     int dy;
307     int num_clip_rects;
308     int num_reg_rects;
309     BoxPtr box;
310     BoxRec box1;
311 
312     LLOGLN(10, ("rdpCopyWindow:"));
313     pScreen = pWin->drawable.pScreen;
314     dev = rdpGetDevFromScreen(pScreen);
315     dev->counts.rdpCopyWindowCallCount++;
316 
317     rdpRegionInit(&reg, NullBox, 0);
318     rdpRegionCopy(&reg, pOldRegion);
319     rdpRegionInit(&clip, NullBox, 0);
320     rdpRegionCopy(&clip, &pWin->borderClip);
321     dx = pWin->drawable.x - ptOldOrg.x;
322     dy = pWin->drawable.y - ptOldOrg.y;
323 
324     dev->pScreen->CopyWindow = dev->CopyWindow;
325     dev->pScreen->CopyWindow(pWin, ptOldOrg, pOldRegion);
326     dev->pScreen->CopyWindow = rdpCopyWindow;
327 
328     num_clip_rects = REGION_NUM_RECTS(&clip);
329     num_reg_rects = REGION_NUM_RECTS(&reg);
330 
331     if ((num_clip_rects == 0) || (num_reg_rects == 0))
332     {
333     }
334     else
335     {
336         if ((num_clip_rects > 16) || (num_reg_rects > 16))
337         {
338             LLOGLN(10, ("rdpCopyWindow: big list"));
339             box = rdpRegionExtents(&reg);
340             box1 = *box;
341             box1.x1 += dx;
342             box1.y1 += dy;
343             box1.x2 += dx;
344             box1.y2 += dy;
345             rdpClientConAddAllBox(dev, &box1, &(pWin->drawable));
346         }
347         else
348         {
349             rdpRegionTranslate(&reg, dx, dy);
350             rdpRegionIntersect(&reg, &reg, &clip);
351             rdpClientConAddAllReg(dev, &reg, &(pWin->drawable));
352         }
353     }
354     rdpRegionUninit(&reg);
355     rdpRegionUninit(&clip);
356 }
357 
358 #if XRDP_CLOSESCR == 1 /* before v1.13 */
359 
360 /*****************************************************************************/
361 Bool
rdpCloseScreen(int index,ScreenPtr pScreen)362 rdpCloseScreen(int index, ScreenPtr pScreen)
363 {
364     rdpPtr dev;
365     Bool rv;
366 
367     LLOGLN(0, ("rdpCloseScreen:"));
368     dev = rdpGetDevFromScreen(pScreen);
369     dev->pScreen->CloseScreen = dev->CloseScreen;
370     rv = dev->pScreen->CloseScreen(index, pScreen);
371     dev->pScreen->CloseScreen = rdpCloseScreen;
372     xorgxrdpDownDown(pScreen);
373     return rv;
374 }
375 
376 #else
377 
378 /*****************************************************************************/
379 Bool
rdpCloseScreen(ScreenPtr pScreen)380 rdpCloseScreen(ScreenPtr pScreen)
381 {
382     rdpPtr dev;
383     Bool rv;
384 
385     LLOGLN(0, ("rdpCloseScreen:"));
386     dev = rdpGetDevFromScreen(pScreen);
387     dev->pScreen->CloseScreen = dev->CloseScreen;
388     rv = dev->pScreen->CloseScreen(pScreen);
389     dev->pScreen->CloseScreen = rdpCloseScreen;
390     xorgxrdpDownDown(pScreen);
391     return rv;
392 }
393 
394 #endif
395 
396 /******************************************************************************/
397 WindowPtr
rdpGetRootWindowPtr(ScreenPtr pScreen)398 rdpGetRootWindowPtr(ScreenPtr pScreen)
399 {
400 #if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1, 9, 0, 0, 0)
401     return WindowTable[pScreen->myNum]; /* in globals.c */
402 #else
403     return pScreen->root;
404 #endif
405 }
406 
407 /******************************************************************************/
408 rdpPtr
rdpGetDevFromScreen(ScreenPtr pScreen)409 rdpGetDevFromScreen(ScreenPtr pScreen)
410 {
411     ScrnInfoPtr pScrn;
412     rdpPtr dev;
413 
414     if (pScreen == NULL)
415     {
416         pScrn = xf86Screens[0];
417     }
418     else
419     {
420         pScrn = xf86Screens[pScreen->myNum];
421     }
422     dev = XRDPPTR(pScrn);
423     return dev;
424 }
425