mirror of https://github.com/FreeRDP/FreeRDP
* include/freerdp/codec/color.h:
(freerdp_color_convert_drawing_order_color_to_gdi_color): Declare new function. * libfreerdp/codec/color.c: (freerdp_color_convert_drawing_order_color_to_gdi_color): Implement. (freerdp_image_convert_8bpp): Properly use the ARGB32/ABGR32/RGB32/BGR32 macros when converting 8bpp data to 32bpp. (freerdp_image_convert_32bpp): Fix CLRCONV_ALPHA and CLRCONV_INVERT processing for 32bpp destination. (freerdp_mono_image_convert): Use ARGB32/ABGR32 when converting to 32bpp and CLRCONV_ALPHA is set. * libfreerdp/core/orders.c: Color data from drawing orders is interpreted in big endian mode. * libfreerdp/core/update.c (update_read_palette): Likewise. * libfreerdp/gdi/16bpp.c (gdi_get_color_16bpp): GDI colors are stored as RGB now. * libfreerdp/gdi/32bpp.c (gdi_get_color_32bpp): Likewise. * libfreerdp/gdi/gdi.c: Use freerdp_color_convert_drawing_order_color_to_gdi_color() to convert from drawing order color representation to GDI color representation troughout. * libfreerdp/gdi/graphics.c (gdi_Glyph_BeginDraw): Likewise. (gdi_Glyph_EndDraw): Likewise.
This commit is contained in:
parent
8a4f134fab
commit
c51c5df2ff
|
@ -392,6 +392,7 @@ FREERDP_API UINT32 freerdp_color_convert_rgb_bgr(UINT32 srcColor, int srcBpp, in
|
|||
FREERDP_API UINT32 freerdp_color_convert_bgr_rgb(UINT32 srcColor, int srcBpp, int dstBpp, HCLRCONV clrconv);
|
||||
FREERDP_API UINT32 freerdp_color_convert_var_rgb(UINT32 srcColor, int srcBpp, int dstBpp, HCLRCONV clrconv);
|
||||
FREERDP_API UINT32 freerdp_color_convert_var_bgr(UINT32 srcColor, int srcBpp, int dstBpp, HCLRCONV clrconv);
|
||||
FREERDP_API UINT32 freerdp_color_convert_drawing_order_color_to_gdi_color(UINT32 color, int bpp, HCLRCONV clrconv);
|
||||
|
||||
FREERDP_API HCLRCONV freerdp_clrconv_new(UINT32 flags);
|
||||
FREERDP_API void freerdp_clrconv_free(HCLRCONV clrconv);
|
||||
|
|
|
@ -379,6 +379,43 @@ UINT32 freerdp_color_convert_var_bgr(UINT32 srcColor, int srcBpp, int dstBpp, HC
|
|||
return freerdp_color_convert_rgb_bgr(srcColor, srcBpp, dstBpp, clrconv);
|
||||
}
|
||||
|
||||
UINT32 freerdp_color_convert_drawing_order_color_to_gdi_color(UINT32 color, int bpp, HCLRCONV clrconv)
|
||||
{
|
||||
UINT32 r, g, b;
|
||||
|
||||
switch (bpp)
|
||||
{
|
||||
case 16:
|
||||
color = (color & (UINT32) 0xFF00) | ((color >> 16) & (UINT32) 0xFF);
|
||||
GetRGB16(r, g, b, color);
|
||||
break;
|
||||
|
||||
case 15:
|
||||
color = (color & (UINT32) 0xFF00) | ((color >> 16) & (UINT32) 0xFF);
|
||||
GetRGB15(r, g, b, color);
|
||||
break;
|
||||
|
||||
case 8:
|
||||
color = (color >> 16) & (UINT32) 0xFF;
|
||||
r = clrconv->palette->entries[color].red;
|
||||
g = clrconv->palette->entries[color].green;
|
||||
b = clrconv->palette->entries[color].blue;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
r = g = b = 0;
|
||||
if (color != 0)
|
||||
r = g = b = 0xFF;
|
||||
break;
|
||||
|
||||
default:
|
||||
return color;
|
||||
break;
|
||||
}
|
||||
|
||||
return RGB32(r, g, b);
|
||||
}
|
||||
|
||||
BYTE* freerdp_image_convert_8bpp(BYTE* srcData, BYTE* dstData, int width, int height, int srcBpp, int dstBpp, HCLRCONV clrconv)
|
||||
{
|
||||
int i;
|
||||
|
@ -470,11 +507,11 @@ BYTE* freerdp_image_convert_8bpp(BYTE* srcData, BYTE* dstData, int width, int he
|
|||
blue = clrconv->palette->entries[pixel].blue;
|
||||
if (clrconv->alpha)
|
||||
{
|
||||
pixel = (clrconv->invert) ? ARGB32(0xFF, red, green, blue) : ABGR32(0xFF, red, green, blue);
|
||||
pixel = (clrconv->invert) ? ABGR32(0xFF, red, green, blue) : ARGB32(0xFF, red, green, blue);
|
||||
}
|
||||
else
|
||||
{
|
||||
pixel = (clrconv->invert) ? RGB32(red, green, blue) : BGR32(red, green, blue);
|
||||
pixel = (clrconv->invert) ? BGR32(red, green, blue) : RGB32(red, green, blue);
|
||||
}
|
||||
*dst32 = pixel;
|
||||
dst32++;
|
||||
|
@ -760,33 +797,47 @@ BYTE* freerdp_image_convert_32bpp(BYTE* srcData, BYTE* dstData, int width, int h
|
|||
}
|
||||
else if (dstBpp == 32)
|
||||
{
|
||||
int i;
|
||||
UINT32 pixel;
|
||||
UINT32 alpha_mask;
|
||||
UINT32* srcp;
|
||||
UINT32* dstp;
|
||||
BYTE red, green, blue;
|
||||
|
||||
if (!dstData)
|
||||
dstData = (BYTE*) _aligned_malloc(width * height * 4, 16);
|
||||
|
||||
if (!dstData)
|
||||
return NULL;
|
||||
|
||||
if (clrconv->alpha)
|
||||
alpha_mask = clrconv->alpha ? 0xFF000000 : 0;
|
||||
|
||||
srcp = (UINT32*) srcData;
|
||||
dstp = (UINT32*) dstData;
|
||||
|
||||
if (clrconv->invert)
|
||||
{
|
||||
int x, y;
|
||||
BYTE* dstp;
|
||||
|
||||
CopyMemory(dstData, srcData, width * height * 4);
|
||||
|
||||
dstp = dstData;
|
||||
for (y = 0; y < height; y++)
|
||||
for (i = width * height; i > 0; i--)
|
||||
{
|
||||
for (x = 0; x < width * 4; x += 4)
|
||||
{
|
||||
dstp += 3;
|
||||
*dstp = 0xFF;
|
||||
dstp++;
|
||||
}
|
||||
pixel = *srcp;
|
||||
srcp++;
|
||||
GetRGB32(red, green, blue, pixel);
|
||||
pixel = alpha_mask | BGR32(red, green, blue);
|
||||
*dstp = pixel;
|
||||
dstp++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CopyMemory(dstData, srcData, width * height * 4);
|
||||
for (i = width * height; i > 0; i--)
|
||||
{
|
||||
pixel = *srcp;
|
||||
srcp++;
|
||||
GetRGB32(red, green, blue, pixel);
|
||||
pixel = alpha_mask | RGB32(red, green, blue);
|
||||
*dstp = pixel;
|
||||
dstp++;
|
||||
}
|
||||
}
|
||||
|
||||
return dstData;
|
||||
|
@ -995,36 +1046,9 @@ BYTE* freerdp_mono_image_convert(BYTE* srcData, int width, int height, int srcBp
|
|||
int bitIndex;
|
||||
BYTE redBg, greenBg, blueBg;
|
||||
BYTE redFg, greenFg, blueFg;
|
||||
|
||||
switch (srcBpp)
|
||||
{
|
||||
case 8:
|
||||
bgcolor &= 0xFF;
|
||||
redBg = clrconv->palette->entries[bgcolor].red;
|
||||
greenBg = clrconv->palette->entries[bgcolor].green;
|
||||
blueBg = clrconv->palette->entries[bgcolor].blue;
|
||||
|
||||
fgcolor &= 0xFF;
|
||||
redFg = clrconv->palette->entries[fgcolor].red;
|
||||
greenFg = clrconv->palette->entries[fgcolor].green;
|
||||
blueFg = clrconv->palette->entries[fgcolor].blue;
|
||||
break;
|
||||
|
||||
case 16:
|
||||
GetRGB16(redBg, greenBg, blueBg, bgcolor);
|
||||
GetRGB16(redFg, greenFg, blueFg, fgcolor);
|
||||
break;
|
||||
|
||||
case 15:
|
||||
GetRGB15(redBg, greenBg, blueBg, bgcolor);
|
||||
GetRGB15(redFg, greenFg, blueFg, fgcolor);
|
||||
break;
|
||||
|
||||
default:
|
||||
GetRGB32(redBg, greenBg, blueBg, bgcolor);
|
||||
GetRGB32(redFg, greenFg, blueFg, fgcolor);
|
||||
break;
|
||||
}
|
||||
|
||||
GetRGB32(redBg, greenBg, blueBg, bgcolor);
|
||||
GetRGB32(redFg, greenFg, blueFg, fgcolor);
|
||||
|
||||
if (dstBpp == 16)
|
||||
{
|
||||
|
@ -1092,11 +1116,25 @@ BYTE* freerdp_mono_image_convert(BYTE* srcData, int width, int height, int srcBp
|
|||
{
|
||||
if ((bitMask >> bitIndex) & 0x01)
|
||||
{
|
||||
*dst32 = (clrconv->invert) ? BGR32(redBg, greenBg, blueBg) : RGB32(redBg, greenBg, blueBg);
|
||||
if (clrconv->alpha)
|
||||
{
|
||||
*dst32 = (clrconv->invert) ? ABGR32(0xFF, redBg, greenBg, blueBg) : ARGB32(0xFF, redBg, greenBg, blueBg);
|
||||
}
|
||||
else
|
||||
{
|
||||
*dst32 = (clrconv->invert) ? BGR32(redBg, greenBg, blueBg) : RGB32(redBg, greenBg, blueBg);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*dst32 = (clrconv->invert) ? BGR32(redFg, greenFg, blueFg) : RGB32(redFg, greenFg, blueFg);
|
||||
if (clrconv->alpha)
|
||||
{
|
||||
*dst32 = (clrconv->invert) ? ABGR32(0xFF, redFg, greenFg, blueFg) : ARGB32(0xFF, redFg, greenFg, blueFg);
|
||||
}
|
||||
else
|
||||
{
|
||||
*dst32 = (clrconv->invert) ? BGR32(redFg, greenFg, blueFg) : RGB32(redFg, greenFg, blueFg);
|
||||
}
|
||||
}
|
||||
dst32++;
|
||||
}
|
||||
|
|
|
@ -223,11 +223,11 @@ static INLINE BOOL update_read_color(wStream* s, UINT32* color)
|
|||
return FALSE;
|
||||
|
||||
Stream_Read_UINT8(s, byte);
|
||||
*color = byte;
|
||||
*color = (UINT32) byte << 16;
|
||||
Stream_Read_UINT8(s, byte);
|
||||
*color |= (byte << 8);
|
||||
*color |= ((UINT32) byte << 8);
|
||||
Stream_Read_UINT8(s, byte);
|
||||
*color |= (byte << 16);
|
||||
*color |= (UINT32) byte;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -979,7 +979,7 @@ BOOL update_read_opaque_rect_order(wStream* s, ORDER_INFO* orderInfo, OPAQUE_REC
|
|||
return FALSE;
|
||||
|
||||
Stream_Read_UINT8(s, byte);
|
||||
opaque_rect->color = (opaque_rect->color & 0xFFFFFF00) | byte;
|
||||
opaque_rect->color = (opaque_rect->color & 0xFF00FFFF) | ((UINT32) byte << 16);
|
||||
}
|
||||
|
||||
if (orderInfo->fieldFlags & ORDER_FIELD_06)
|
||||
|
@ -988,7 +988,7 @@ BOOL update_read_opaque_rect_order(wStream* s, ORDER_INFO* orderInfo, OPAQUE_REC
|
|||
return FALSE;
|
||||
|
||||
Stream_Read_UINT8(s, byte);
|
||||
opaque_rect->color = (opaque_rect->color & 0xFFFF00FF) | (byte << 8);
|
||||
opaque_rect->color = (opaque_rect->color & 0xFFFF00FF) | ((UINT32) byte << 8);
|
||||
}
|
||||
|
||||
if (orderInfo->fieldFlags & ORDER_FIELD_07)
|
||||
|
@ -997,7 +997,7 @@ BOOL update_read_opaque_rect_order(wStream* s, ORDER_INFO* orderInfo, OPAQUE_REC
|
|||
return FALSE;
|
||||
|
||||
Stream_Read_UINT8(s, byte);
|
||||
opaque_rect->color = (opaque_rect->color & 0xFF00FFFF) | (byte << 16);
|
||||
opaque_rect->color = (opaque_rect->color & 0xFFFFFF00) | (UINT32) byte;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
@ -1178,7 +1178,7 @@ BOOL update_read_multi_opaque_rect_order(wStream* s, ORDER_INFO* orderInfo, MULT
|
|||
return FALSE;
|
||||
|
||||
Stream_Read_UINT8(s, byte);
|
||||
multi_opaque_rect->color = (multi_opaque_rect->color & 0xFFFFFF00) | byte;
|
||||
multi_opaque_rect->color = (multi_opaque_rect->color & 0xFF00FFFF) | ((UINT32) byte << 16);
|
||||
}
|
||||
|
||||
if (orderInfo->fieldFlags & ORDER_FIELD_06)
|
||||
|
@ -1187,7 +1187,7 @@ BOOL update_read_multi_opaque_rect_order(wStream* s, ORDER_INFO* orderInfo, MULT
|
|||
return FALSE;
|
||||
|
||||
Stream_Read_UINT8(s, byte);
|
||||
multi_opaque_rect->color = (multi_opaque_rect->color & 0xFFFF00FF) | (byte << 8);
|
||||
multi_opaque_rect->color = (multi_opaque_rect->color & 0xFFFF00FF) | ((UINT32) byte << 8);
|
||||
}
|
||||
|
||||
if (orderInfo->fieldFlags & ORDER_FIELD_07)
|
||||
|
@ -1196,7 +1196,7 @@ BOOL update_read_multi_opaque_rect_order(wStream* s, ORDER_INFO* orderInfo, MULT
|
|||
return FALSE;
|
||||
|
||||
Stream_Read_UINT8(s, byte);
|
||||
multi_opaque_rect->color = (multi_opaque_rect->color & 0xFF00FFFF) | (byte << 16);
|
||||
multi_opaque_rect->color = (multi_opaque_rect->color & 0xFFFFFF00) | (UINT32) byte;
|
||||
}
|
||||
|
||||
ORDER_FIELD_BYTE(8, multi_opaque_rect->numRectangles);
|
||||
|
|
|
@ -230,9 +230,9 @@ BOOL update_read_palette(rdpUpdate* update, wStream* s, PALETTE_UPDATE* palette_
|
|||
{
|
||||
entry = &palette_update->entries[i];
|
||||
|
||||
Stream_Read_UINT8(s, entry->blue);
|
||||
Stream_Read_UINT8(s, entry->green);
|
||||
Stream_Read_UINT8(s, entry->red);
|
||||
Stream_Read_UINT8(s, entry->green);
|
||||
Stream_Read_UINT8(s, entry->blue);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ UINT16 gdi_get_color_16bpp(HGDI_DC hdc, GDI_COLOR color)
|
|||
BYTE r, g, b;
|
||||
UINT16 color16;
|
||||
|
||||
GetBGR32(r, g, b, color);
|
||||
GetRGB32(r, g, b, color);
|
||||
|
||||
if (hdc->rgb555)
|
||||
{
|
||||
|
|
|
@ -44,7 +44,7 @@ UINT32 gdi_get_color_32bpp(HGDI_DC hdc, GDI_COLOR color)
|
|||
BYTE a, r, g, b;
|
||||
|
||||
a = 0xFF;
|
||||
GetBGR32(r, g, b, color);
|
||||
GetRGB32(r, g, b, color);
|
||||
|
||||
if (hdc->invert)
|
||||
{
|
||||
|
|
|
@ -495,8 +495,8 @@ void gdi_patblt(rdpContext* context, PATBLT_ORDER* patblt)
|
|||
|
||||
brush = &patblt->brush;
|
||||
|
||||
foreColor = freerdp_color_convert_rgb(patblt->foreColor, gdi->srcBpp, 24, gdi->clrconv);
|
||||
backColor = freerdp_color_convert_rgb(patblt->backColor, gdi->srcBpp, 24, gdi->clrconv);
|
||||
foreColor = freerdp_color_convert_drawing_order_color_to_gdi_color(patblt->foreColor, gdi->srcBpp, gdi->clrconv);
|
||||
backColor = freerdp_color_convert_drawing_order_color_to_gdi_color(patblt->backColor, gdi->srcBpp, gdi->clrconv);
|
||||
|
||||
originalColor = gdi_SetTextColor(gdi->drawing->hdc, foreColor);
|
||||
|
||||
|
@ -541,7 +541,7 @@ void gdi_patblt(rdpContext* context, PATBLT_ORDER* patblt)
|
|||
else
|
||||
{
|
||||
data = freerdp_mono_image_convert(brush->data, 8, 8, gdi->srcBpp, gdi->dstBpp,
|
||||
patblt->backColor, patblt->foreColor, gdi->clrconv);
|
||||
backColor, foreColor, gdi->clrconv);
|
||||
}
|
||||
|
||||
hBmp = gdi_CreateBitmap(8, 8, gdi->drawing->hdc->bitsPerPixel, data);
|
||||
|
@ -582,7 +582,8 @@ void gdi_opaque_rect(rdpContext* context, OPAQUE_RECT_ORDER* opaque_rect)
|
|||
gdi_CRgnToRect(opaque_rect->nLeftRect, opaque_rect->nTopRect,
|
||||
opaque_rect->nWidth, opaque_rect->nHeight, &rect);
|
||||
|
||||
brush_color = freerdp_color_convert_var_bgr(opaque_rect->color, gdi->srcBpp, 32, gdi->clrconv);
|
||||
brush_color = freerdp_color_convert_drawing_order_color_to_gdi_color(
|
||||
opaque_rect->color, gdi->srcBpp, gdi->clrconv);
|
||||
|
||||
hBrush = gdi_CreateSolidBrush(brush_color);
|
||||
gdi_FillRect(gdi->drawing->hdc, &rect, hBrush);
|
||||
|
@ -606,7 +607,8 @@ void gdi_multi_opaque_rect(rdpContext* context, MULTI_OPAQUE_RECT_ORDER* multi_o
|
|||
gdi_CRgnToRect(rectangle->left, rectangle->top,
|
||||
rectangle->width, rectangle->height, &rect);
|
||||
|
||||
brush_color = freerdp_color_convert_var_bgr(multi_opaque_rect->color, gdi->srcBpp, 32, gdi->clrconv);
|
||||
brush_color = freerdp_color_convert_drawing_order_color_to_gdi_color(
|
||||
multi_opaque_rect->color, gdi->srcBpp, gdi->clrconv);
|
||||
|
||||
hBrush = gdi_CreateSolidBrush(brush_color);
|
||||
gdi_FillRect(gdi->drawing->hdc, &rect, hBrush);
|
||||
|
@ -621,7 +623,8 @@ void gdi_line_to(rdpContext* context, LINE_TO_ORDER* lineTo)
|
|||
HGDI_PEN hPen;
|
||||
rdpGdi* gdi = context->gdi;
|
||||
|
||||
color = freerdp_color_convert_rgb(lineTo->penColor, gdi->srcBpp, 32, gdi->clrconv);
|
||||
color = freerdp_color_convert_drawing_order_color_to_gdi_color(
|
||||
lineTo->penColor, gdi->srcBpp, gdi->clrconv);
|
||||
hPen = gdi_CreatePen(lineTo->penStyle, lineTo->penWidth, (GDI_COLOR) color);
|
||||
gdi_SelectObject(gdi->drawing->hdc, (HGDIOBJECT) hPen);
|
||||
gdi_SetROP2(gdi->drawing->hdc, lineTo->bRop2);
|
||||
|
@ -642,7 +645,8 @@ void gdi_polyline(rdpContext* context, POLYLINE_ORDER* polyline)
|
|||
DELTA_POINT* points;
|
||||
rdpGdi* gdi = context->gdi;
|
||||
|
||||
color = freerdp_color_convert_rgb(polyline->penColor, gdi->srcBpp, 32, gdi->clrconv);
|
||||
color = freerdp_color_convert_drawing_order_color_to_gdi_color(
|
||||
polyline->penColor, gdi->srcBpp, gdi->clrconv);
|
||||
hPen = gdi_CreatePen(GDI_PS_SOLID, 1, (GDI_COLOR) color);
|
||||
gdi_SelectObject(gdi->drawing->hdc, (HGDIOBJECT) hPen);
|
||||
gdi_SetROP2(gdi->drawing->hdc, polyline->bRop2);
|
||||
|
@ -689,8 +693,8 @@ void gdi_mem3blt(rdpContext* context, MEM3BLT_ORDER* mem3blt)
|
|||
brush = &mem3blt->brush;
|
||||
bitmap = (gdiBitmap*) mem3blt->bitmap;
|
||||
|
||||
foreColor = freerdp_color_convert_rgb(mem3blt->foreColor, gdi->srcBpp, 24, gdi->clrconv);
|
||||
backColor = freerdp_color_convert_rgb(mem3blt->backColor, gdi->srcBpp, 24, gdi->clrconv);
|
||||
foreColor = freerdp_color_convert_drawing_order_color_to_gdi_color(mem3blt->foreColor, gdi->srcBpp, gdi->clrconv);
|
||||
backColor = freerdp_color_convert_drawing_order_color_to_gdi_color(mem3blt->backColor, gdi->srcBpp, gdi->clrconv);
|
||||
|
||||
originalColor = gdi_SetTextColor(gdi->drawing->hdc, foreColor);
|
||||
|
||||
|
@ -717,7 +721,7 @@ void gdi_mem3blt(rdpContext* context, MEM3BLT_ORDER* mem3blt)
|
|||
else
|
||||
{
|
||||
data = freerdp_mono_image_convert(brush->data, 8, 8, gdi->srcBpp, gdi->dstBpp,
|
||||
mem3blt->backColor, mem3blt->foreColor, gdi->clrconv);
|
||||
backColor, foreColor, gdi->clrconv);
|
||||
}
|
||||
|
||||
hBmp = gdi_CreateBitmap(8, 8, gdi->drawing->hdc->bitsPerPixel, data);
|
||||
|
|
|
@ -242,8 +242,10 @@ void gdi_Glyph_BeginDraw(rdpContext* context, int x, int y, int width, int heigh
|
|||
HGDI_BRUSH brush;
|
||||
rdpGdi* gdi = context->gdi;
|
||||
|
||||
bgcolor = freerdp_color_convert_var_bgr(bgcolor, gdi->srcBpp, 32, gdi->clrconv);
|
||||
fgcolor = freerdp_color_convert_var_bgr(fgcolor, gdi->srcBpp, 32, gdi->clrconv);
|
||||
bgcolor = freerdp_color_convert_drawing_order_color_to_gdi_color(
|
||||
bgcolor, gdi->srcBpp, gdi->clrconv);
|
||||
fgcolor = freerdp_color_convert_drawing_order_color_to_gdi_color(
|
||||
fgcolor, gdi->srcBpp, gdi->clrconv);
|
||||
|
||||
gdi_CRgnToRect(x, y, width, height, &rect);
|
||||
|
||||
|
@ -258,7 +260,8 @@ void gdi_Glyph_EndDraw(rdpContext* context, int x, int y, int width, int height,
|
|||
{
|
||||
rdpGdi* gdi = context->gdi;
|
||||
|
||||
bgcolor = freerdp_color_convert_var_bgr(bgcolor, gdi->srcBpp, 32, gdi->clrconv);
|
||||
bgcolor = freerdp_color_convert_drawing_order_color_to_gdi_color(
|
||||
bgcolor, gdi->srcBpp, gdi->clrconv);
|
||||
gdi->textColor = gdi_SetTextColor(gdi->drawing->hdc, bgcolor);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue