Coverage Report

Created: 2025-07-01 06:46

/src/FreeRDP/libfreerdp/gdi/video.c
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * FreeRDP: A Remote Desktop Protocol Implementation
3
 * Video Optimized Remoting Virtual Channel Extension for X11
4
 *
5
 * Copyright 2017 David Fort <contact@hardening-consulting.com>
6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
10
 *
11
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
18
 */
19
20
#include "../core/update.h"
21
22
#include <winpr/assert.h>
23
24
#include <freerdp/client/geometry.h>
25
#include <freerdp/client/video.h>
26
#include <freerdp/gdi/gdi.h>
27
#include <freerdp/gdi/video.h>
28
#include <freerdp/gdi/region.h>
29
30
void gdi_video_geometry_init(rdpGdi* gdi, GeometryClientContext* geom)
31
0
{
32
0
  WINPR_ASSERT(gdi);
33
0
  WINPR_ASSERT(geom);
34
35
0
  gdi->geometry = geom;
36
37
0
  if (gdi->video)
38
0
  {
39
0
    VideoClientContext* video = gdi->video;
40
41
0
    WINPR_ASSERT(video);
42
0
    WINPR_ASSERT(video->setGeometry);
43
0
    video->setGeometry(video, gdi->geometry);
44
0
  }
45
0
}
46
47
void gdi_video_geometry_uninit(rdpGdi* gdi, GeometryClientContext* geom)
48
0
{
49
0
  WINPR_ASSERT(gdi);
50
0
  WINPR_ASSERT(geom);
51
0
  WINPR_UNUSED(gdi);
52
0
  WINPR_UNUSED(geom);
53
0
}
54
55
static VideoSurface* gdiVideoCreateSurface(WINPR_ATTR_UNUSED VideoClientContext* video, UINT32 x,
56
                                           UINT32 y, UINT32 width, UINT32 height)
57
0
{
58
0
  return VideoClient_CreateCommonContext(sizeof(VideoSurface), x, y, width, height);
59
0
}
60
61
static BOOL gdiVideoShowSurface(VideoClientContext* video, const VideoSurface* surface,
62
                                UINT32 destinationWidth, UINT32 destinationHeight)
63
0
{
64
0
  BOOL rc = FALSE;
65
0
  rdpGdi* gdi = NULL;
66
0
  rdpUpdate* update = NULL;
67
68
0
  WINPR_ASSERT(video);
69
0
  WINPR_ASSERT(surface);
70
71
0
  gdi = (rdpGdi*)video->custom;
72
0
  WINPR_ASSERT(gdi);
73
0
  WINPR_ASSERT(gdi->context);
74
75
0
  update = gdi->context->update;
76
0
  WINPR_ASSERT(update);
77
78
0
  if (!update_begin_paint(update))
79
0
    goto fail;
80
81
0
  if ((gdi->width < 0) || (gdi->height < 0))
82
0
    goto fail;
83
0
  else
84
0
  {
85
0
    const UINT32 nXSrc = surface->x;
86
0
    const UINT32 nYSrc = surface->y;
87
0
    const UINT32 nXDst = nXSrc;
88
0
    const UINT32 nYDst = nYSrc;
89
0
    const UINT32 width = (destinationWidth + surface->x < (UINT32)gdi->width)
90
0
                             ? destinationWidth
91
0
                             : (UINT32)gdi->width - surface->x;
92
0
    const UINT32 height = (destinationHeight + surface->y < (UINT32)gdi->height)
93
0
                              ? destinationHeight
94
0
                              : (UINT32)gdi->height - surface->y;
95
96
0
    WINPR_ASSERT(gdi->primary_buffer);
97
0
    WINPR_ASSERT(gdi->primary);
98
0
    WINPR_ASSERT(gdi->primary->hdc);
99
100
0
    if (!freerdp_image_scale(gdi->primary_buffer, gdi->primary->hdc->format, gdi->stride, nXDst,
101
0
                             nYDst, width, height, surface->data, surface->format,
102
0
                             surface->scanline, 0, 0, surface->w, surface->h))
103
0
      goto fail;
104
105
0
    if ((nXDst > INT32_MAX) || (nYDst > INT32_MAX) || (width > INT32_MAX) ||
106
0
        (height > INT32_MAX))
107
0
      goto fail;
108
109
0
    gdi_InvalidateRegion(gdi->primary->hdc, (INT32)nXDst, (INT32)nYDst, (INT32)width,
110
0
                         (INT32)height);
111
0
  }
112
113
0
  rc = TRUE;
114
0
fail:
115
116
0
  if (!update_end_paint(update))
117
0
    return FALSE;
118
119
0
  return rc;
120
0
}
121
122
static BOOL gdiVideoDeleteSurface(VideoClientContext* video, VideoSurface* surface)
123
0
{
124
0
  WINPR_UNUSED(video);
125
0
  VideoClient_DestroyCommonContext(surface);
126
0
  return TRUE;
127
0
}
128
129
void gdi_video_control_init(rdpGdi* gdi, VideoClientContext* video)
130
0
{
131
0
  WINPR_ASSERT(gdi);
132
0
  WINPR_ASSERT(video);
133
134
0
  gdi->video = video;
135
0
  video->custom = gdi;
136
0
  video->createSurface = gdiVideoCreateSurface;
137
0
  video->showSurface = gdiVideoShowSurface;
138
0
  video->deleteSurface = gdiVideoDeleteSurface;
139
0
  video->setGeometry(video, gdi->geometry);
140
0
}
141
142
void gdi_video_control_uninit(rdpGdi* gdi, WINPR_ATTR_UNUSED VideoClientContext* video)
143
0
{
144
0
  WINPR_ASSERT(gdi);
145
0
  gdi->video = NULL;
146
0
}
147
148
void gdi_video_data_init(WINPR_ATTR_UNUSED rdpGdi* gdi, WINPR_ATTR_UNUSED VideoClientContext* video)
149
0
{
150
0
  WINPR_ASSERT(gdi);
151
0
  WINPR_ASSERT(gdi->context);
152
0
}
153
154
void gdi_video_data_uninit(WINPR_ATTR_UNUSED rdpGdi* gdi,
155
                           WINPR_ATTR_UNUSED VideoClientContext* context)
156
0
{
157
0
  WINPR_ASSERT(gdi);
158
0
  WINPR_ASSERT(gdi->context);
159
0
}
160
161
VideoSurface* VideoClient_CreateCommonContext(size_t size, UINT32 x, UINT32 y, UINT32 w, UINT32 h)
162
0
{
163
0
  VideoSurface* ret = NULL;
164
165
0
  WINPR_ASSERT(size >= sizeof(VideoSurface));
166
167
0
  ret = calloc(1, size);
168
0
  if (!ret)
169
0
    return NULL;
170
171
0
  ret->format = PIXEL_FORMAT_BGRX32;
172
0
  ret->x = x;
173
0
  ret->y = y;
174
0
  ret->w = w;
175
0
  ret->h = h;
176
0
  ret->alignedWidth = ret->w + 32 - ret->w % 16;
177
0
  ret->alignedHeight = ret->h + 32 - ret->h % 16;
178
179
0
  ret->scanline = ret->alignedWidth * FreeRDPGetBytesPerPixel(ret->format);
180
0
  ret->data = winpr_aligned_malloc(1ull * ret->scanline * ret->alignedHeight, 64);
181
0
  if (!ret->data)
182
0
    goto fail;
183
0
  return ret;
184
0
fail:
185
0
  VideoClient_DestroyCommonContext(ret);
186
0
  return NULL;
187
0
}
188
189
void VideoClient_DestroyCommonContext(VideoSurface* surface)
190
0
{
191
0
  if (!surface)
192
0
    return;
193
0
  winpr_aligned_free(surface->data);
194
0
  free(surface);
195
0
}