forked from enlightenment/efl
massively improve xrender scaling to be almost perfect. a few nigglies remain
though with transformed images (especailly with border scaling) SVN revision: 26965
This commit is contained in:
parent
bcd4e797d6
commit
b24c5e70da
|
@ -73,8 +73,8 @@ Xrender_Surface *_xr_render_surface_format_adopt(Ximage_Info *xinf, Drawable dra
|
||||||
void _xr_render_surface_free(Xrender_Surface *rs);
|
void _xr_render_surface_free(Xrender_Surface *rs);
|
||||||
void _xr_render_surface_repeat_set(Xrender_Surface *rs, int repeat);
|
void _xr_render_surface_repeat_set(Xrender_Surface *rs, int repeat);
|
||||||
void _xr_render_surface_solid_rectangle_set(Xrender_Surface *rs, int r, int g, int b, int a, int x, int y, int w, int h);
|
void _xr_render_surface_solid_rectangle_set(Xrender_Surface *rs, int r, int g, int b, int a, int x, int y, int w, int h);
|
||||||
void _xr_render_surface_argb_pixels_fill(Xrender_Surface *rs, int sw, int sh, void *pixels, int x, int y, int w, int h);
|
void _xr_render_surface_argb_pixels_fill(Xrender_Surface *rs, int sw, int sh, void *pixels, int x, int y, int w, int h, int ox, int oy);
|
||||||
void _xr_render_surface_rgb_pixels_fill(Xrender_Surface *rs, int sw, int sh, void *pixels, int x, int y, int w, int h);
|
void _xr_render_surface_rgb_pixels_fill(Xrender_Surface *rs, int sw, int sh, void *pixels, int x, int y, int w, int h, int ox, int oy);
|
||||||
void _xr_render_surface_clips_set(Xrender_Surface *rs, RGBA_Draw_Context *dc, int rx, int ry, int rw, int rh);
|
void _xr_render_surface_clips_set(Xrender_Surface *rs, RGBA_Draw_Context *dc, int rx, int ry, int rw, int rh);
|
||||||
void _xr_render_surface_composite(Xrender_Surface *srs, Xrender_Surface *drs, RGBA_Draw_Context *dc, int sx, int sy, int sw, int sh, int x, int y, int w, int h, int smooth);
|
void _xr_render_surface_composite(Xrender_Surface *srs, Xrender_Surface *drs, RGBA_Draw_Context *dc, int sx, int sy, int sw, int sh, int x, int y, int w, int h, int smooth);
|
||||||
void _xr_render_surface_copy(Xrender_Surface *srs, Xrender_Surface *drs, int sx, int sy, int x, int y, int w, int h);
|
void _xr_render_surface_copy(Xrender_Surface *srs, Xrender_Surface *drs, int sx, int sy, int x, int y, int w, int h);
|
||||||
|
|
|
@ -281,6 +281,7 @@ _xre_image_copy(XR_Image *im)
|
||||||
void
|
void
|
||||||
_xre_image_resize(XR_Image *im, int w, int h)
|
_xre_image_resize(XR_Image *im, int w, int h)
|
||||||
{
|
{
|
||||||
|
/* FIXME: ... */
|
||||||
if ((w == im->w) && (h == im->h)) return;
|
if ((w == im->w) && (h == im->h)) return;
|
||||||
if (im->surface)
|
if (im->surface)
|
||||||
{
|
{
|
||||||
|
@ -290,10 +291,18 @@ _xre_image_resize(XR_Image *im, int w, int h)
|
||||||
ww = w; hh = h;
|
ww = w; hh = h;
|
||||||
RECTS_CLIP_TO_RECT(x, y, ww, hh, 0, 0, im->w, im->h);
|
RECTS_CLIP_TO_RECT(x, y, ww, hh, 0, 0, im->w, im->h);
|
||||||
old_surface = im->surface;
|
old_surface = im->surface;
|
||||||
im->surface = _xr_render_surface_new(old_surface->xinf, w + 1, h + 1, old_surface->fmt, old_surface->alpha);
|
im->surface = _xr_render_surface_new(old_surface->xinf, w + 2, h + 2, old_surface->fmt, old_surface->alpha);
|
||||||
if (im->surface)
|
if (im->surface)
|
||||||
_xr_render_surface_copy(old_surface, im->surface, 0, 0, 0, 0, ww, hh);
|
_xr_render_surface_copy(old_surface, im->surface, 0, 0, 0, 0, ww + 1, hh + 1);
|
||||||
_xr_render_surface_free(old_surface);
|
_xr_render_surface_free(old_surface);
|
||||||
|
_xr_render_surface_copy(im->surface, im->surface,
|
||||||
|
ww, 1,
|
||||||
|
ww + 1, 1,
|
||||||
|
1, hh);
|
||||||
|
_xr_render_surface_copy(im->surface, im->surface,
|
||||||
|
0, hh,
|
||||||
|
0, hh + 1,
|
||||||
|
ww + 2, 1);
|
||||||
}
|
}
|
||||||
if (im->data)
|
if (im->data)
|
||||||
{
|
{
|
||||||
|
@ -462,11 +471,11 @@ _xre_image_alpha_set(XR_Image *im, int alpha)
|
||||||
old_surface = im->surface;
|
old_surface = im->surface;
|
||||||
im->surface = NULL;
|
im->surface = NULL;
|
||||||
if (im->alpha)
|
if (im->alpha)
|
||||||
im->surface = _xr_render_surface_new(im->xinf, im->w + 1, im->h + 1, im->xinf->fmt32, 1);
|
im->surface = _xr_render_surface_new(im->xinf, im->w + 2, im->h + 2, im->xinf->fmt32, 1);
|
||||||
else
|
else
|
||||||
im->surface = _xr_render_surface_new(im->xinf, im->w + 1, im->h + 1, im->xinf->fmt24, 0);
|
im->surface = _xr_render_surface_new(im->xinf, im->w + 2, im->h + 2, im->xinf->fmt24, 0);
|
||||||
if (im->surface)
|
if (im->surface)
|
||||||
_xr_render_surface_copy(old_surface, im->surface, 0, 0, 0, 0, im->w + 1, im->h + 1);
|
_xr_render_surface_copy(old_surface, im->surface, 0, 0, 0, 0, im->w + 2, im->h + 2);
|
||||||
_xr_render_surface_free(old_surface);
|
_xr_render_surface_free(old_surface);
|
||||||
}
|
}
|
||||||
if (im->updates)
|
if (im->updates)
|
||||||
|
@ -538,9 +547,9 @@ _xre_image_surface_gen(XR_Image *im)
|
||||||
rx = r->x; ry = r->y; rw = r->w, rh = r->h;
|
rx = r->x; ry = r->y; rw = r->w, rh = r->h;
|
||||||
RECTS_CLIP_TO_RECT(rx, ry, rw, rh, 0, 0, im->w, im->h);
|
RECTS_CLIP_TO_RECT(rx, ry, rw, rh, 0, 0, im->w, im->h);
|
||||||
if (im->alpha)
|
if (im->alpha)
|
||||||
_xr_render_surface_argb_pixels_fill(im->surface, im->w, im->h, data, rx, ry, rw, rh);
|
_xr_render_surface_argb_pixels_fill(im->surface, im->w, im->h, data, rx, ry, rw, rh, 1, 1);
|
||||||
else
|
else
|
||||||
_xr_render_surface_rgb_pixels_fill(im->surface, im->w, im->h, data, rx, ry, rw, rh);
|
_xr_render_surface_rgb_pixels_fill(im->surface, im->w, im->h, data, rx, ry, rw, rh, 1, 1);
|
||||||
}
|
}
|
||||||
evas_common_tilebuf_free_render_rects(rects);
|
evas_common_tilebuf_free_render_rects(rects);
|
||||||
}
|
}
|
||||||
|
@ -551,27 +560,31 @@ _xre_image_surface_gen(XR_Image *im)
|
||||||
}
|
}
|
||||||
if (im->alpha)
|
if (im->alpha)
|
||||||
{
|
{
|
||||||
im->surface = _xr_render_surface_new(im->xinf, im->w + 1, im->h + 1, im->xinf->fmt32, 1);
|
im->surface = _xr_render_surface_new(im->xinf, im->w + 2, im->h + 2, im->xinf->fmt32, 1);
|
||||||
_xr_render_surface_argb_pixels_fill(im->surface, im->w, im->h, data, 0, 0, im->w, im->h);
|
_xr_render_surface_argb_pixels_fill(im->surface, im->w, im->h, data, 0, 0, im->w, im->h, 1, 1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
im->surface = _xr_render_surface_new(im->xinf, im->w + 1, im->h + 1, im->xinf->fmt24, 0);
|
im->surface = _xr_render_surface_new(im->xinf, im->w + 2, im->h + 2, im->xinf->fmt24, 0);
|
||||||
_xr_render_surface_rgb_pixels_fill(im->surface, im->w, im->h, data, 0, 0, im->w, im->h);
|
_xr_render_surface_rgb_pixels_fill(im->surface, im->w, im->h, data, 0, 0, im->w, im->h, 1, 1);
|
||||||
}
|
}
|
||||||
/* fill right and bottom pixel so interpolation works right */
|
/* fill borders */
|
||||||
_xr_render_surface_copy(im->surface, im->surface,
|
_xr_render_surface_copy(im->surface, im->surface,
|
||||||
im->w - 1, 0,
|
1, 1,
|
||||||
im->w, 0,
|
0, 1,
|
||||||
1, im->h);
|
1, im->h);
|
||||||
_xr_render_surface_copy(im->surface, im->surface,
|
_xr_render_surface_copy(im->surface, im->surface,
|
||||||
0, im->h - 1,
|
0, 1,
|
||||||
0, im->h,
|
0, 0,
|
||||||
im->w, 1);
|
im->w + 2, 1);
|
||||||
_xr_render_surface_copy(im->surface, im->surface,
|
_xr_render_surface_copy(im->surface, im->surface,
|
||||||
im->w - 1, im->h - 1,
|
im->w, 1,
|
||||||
im->w, im->h,
|
im->w + 1, 1,
|
||||||
1, 1);
|
1, im->h);
|
||||||
|
_xr_render_surface_copy(im->surface, im->surface,
|
||||||
|
0, im->h,
|
||||||
|
0, im->h + 1,
|
||||||
|
im->w + 2, 1);
|
||||||
if ((im->im) && (!im->dirty))
|
if ((im->im) && (!im->dirty))
|
||||||
{
|
{
|
||||||
evas_common_image_unref(im->im);
|
evas_common_image_unref(im->im);
|
||||||
|
|
|
@ -165,7 +165,7 @@ _xr_render_surface_solid_rectangle_set(Xrender_Surface *rs, int r, int g, int b,
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
_xr_render_surface_argb_pixels_fill(Xrender_Surface *rs, int sw, int sh, void *pixels, int x, int y, int w, int h)
|
_xr_render_surface_argb_pixels_fill(Xrender_Surface *rs, int sw, int sh, void *pixels, int x, int y, int w, int h, int ox, int oy)
|
||||||
{
|
{
|
||||||
Ximage_Image *xim;
|
Ximage_Image *xim;
|
||||||
unsigned int *p, *sp, *sple, *spe;
|
unsigned int *p, *sp, *sple, *spe;
|
||||||
|
@ -209,11 +209,11 @@ _xr_render_surface_argb_pixels_fill(Xrender_Surface *rs, int sw, int sh, void *p
|
||||||
sp += sjump;
|
sp += sjump;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_xr_image_put(xim, rs->draw, x, y, w, h);
|
_xr_image_put(xim, rs->draw, x + ox, y + oy, w, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
_xr_render_surface_rgb_pixels_fill(Xrender_Surface *rs, int sw, int sh, void *pixels, int x, int y, int w, int h)
|
_xr_render_surface_rgb_pixels_fill(Xrender_Surface *rs, int sw, int sh, void *pixels, int x, int y, int w, int h, int ox, int oy)
|
||||||
{
|
{
|
||||||
Ximage_Image *xim;
|
Ximage_Image *xim;
|
||||||
unsigned int *p, *sp, *sple, *spe;
|
unsigned int *p, *sp, *sple, *spe;
|
||||||
|
@ -257,7 +257,7 @@ _xr_render_surface_rgb_pixels_fill(Xrender_Surface *rs, int sw, int sh, void *pi
|
||||||
sp += sjump;
|
sp += sjump;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_xr_image_put(xim, rs->draw, x, y, w, h);
|
_xr_image_put(xim, rs->draw, x + ox, y + oy, w, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -318,14 +318,16 @@ init_xtransform(XTransform *t)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
set_xtransform_scale(XTransform *t, int sw, int sh, int w, int h)
|
set_xtransform_scale(XTransform *t, int sw, int sh, int w, int h, int tx, int ty)
|
||||||
{
|
{
|
||||||
// if ((sw > 1) && (w > 1))
|
// if ((sw > 1) && (w > 1))
|
||||||
// { sw--; w--; }
|
// { sw--; w--; }
|
||||||
// if ((sh > 1) && (h > 1))
|
// if ((sh > 1) && (h > 1))
|
||||||
// { sh--; h--; }
|
// { sh--; h--; }
|
||||||
t->matrix[0][0] = XDoubleToFixed((double)sw / (double)w);
|
t->matrix[0][0] = XDoubleToFixed((double)(sw) / (double)(w));
|
||||||
t->matrix[1][1] = XDoubleToFixed((double)sh / (double)h);
|
t->matrix[1][1] = XDoubleToFixed((double)(sh) / (double)(h));
|
||||||
|
t->matrix[2][0] = tx;
|
||||||
|
t->matrix[2][1] = ty;
|
||||||
}
|
}
|
||||||
|
|
||||||
// when color multiplier is used want: instead
|
// when color multiplier is used want: instead
|
||||||
|
@ -397,10 +399,10 @@ _xr_render_surface_composite(Xrender_Surface *srs, Xrender_Surface *drs, RGBA_Dr
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ((srs->alpha) || (a != 0xff))
|
if ((srs->alpha) || (a != 0xff))
|
||||||
trs = _xr_render_surface_new(srs->xinf, sw + e, sh + e,
|
trs = _xr_render_surface_new(srs->xinf, sw + 2, sh + 2,
|
||||||
srs->xinf->fmt32, 1);
|
srs->xinf->fmt32, 1);
|
||||||
else
|
else
|
||||||
trs = _xr_render_surface_new(srs->xinf, sw + e, sh + e,
|
trs = _xr_render_surface_new(srs->xinf, sw + 2, sh + 2,
|
||||||
srs->fmt, srs->alpha);
|
srs->fmt, srs->alpha);
|
||||||
if (!trs) return;
|
if (!trs) return;
|
||||||
|
|
||||||
|
@ -408,63 +410,56 @@ _xr_render_surface_composite(Xrender_Surface *srs, Xrender_Surface *drs, RGBA_Dr
|
||||||
XRenderChangePicture(srs->xinf->disp, mask, CPComponentAlpha, &att);
|
XRenderChangePicture(srs->xinf->disp, mask, CPComponentAlpha, &att);
|
||||||
XRenderSetPictureTransform(srs->xinf->disp, srs->pic, &xf);
|
XRenderSetPictureTransform(srs->xinf->disp, srs->pic, &xf);
|
||||||
XRenderComposite(srs->xinf->disp, PictOpSrc, srs->pic, mask,
|
XRenderComposite(srs->xinf->disp, PictOpSrc, srs->pic, mask,
|
||||||
trs->pic, sx, sy, 0, 0, 0, 0, sw, sh);
|
trs->pic,
|
||||||
/* fill right and bottom pixel so interpolation works right */
|
sx, sy,
|
||||||
if (e)
|
sx, sy,
|
||||||
{
|
0, 0, sw + 2, sh + 2);
|
||||||
XRenderComposite(srs->xinf->disp, PictOpSrc, srs->pic, mask,
|
|
||||||
trs->pic, sx + sw - 1, sy, 0, 0, sw, 0, 1, sh);
|
|
||||||
XRenderComposite(srs->xinf->disp, PictOpSrc, srs->pic, mask,
|
|
||||||
trs->pic, sx, sy + sh - 1, 0, 0, 0, sh, sw, 1);
|
|
||||||
XRenderComposite(srs->xinf->disp, PictOpSrc, srs->pic, mask,
|
|
||||||
trs->pic, sx + sw - 1, sy + sh - 1, 0, 0, sw, sh, 1, 1);
|
|
||||||
}
|
|
||||||
mask = None;
|
mask = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//#define HFW + (sw / 2)
|
||||||
|
//#define HFH + (sh / 2)
|
||||||
|
#define HFW
|
||||||
|
#define HFH
|
||||||
|
|
||||||
_xr_render_surface_clips_set(drs, dc, x, y, w, h);
|
_xr_render_surface_clips_set(drs, dc, x, y, w, h);
|
||||||
if (trs)
|
if (trs)
|
||||||
{
|
{
|
||||||
XRenderSetPictureFilter(trs->xinf->disp, trs->pic, get_filter(smooth), NULL, 0);
|
XRenderSetPictureFilter(trs->xinf->disp, trs->pic, get_filter(smooth), NULL, 0);
|
||||||
|
|
||||||
set_xtransform_scale(&xf, sw, sh, w, h);
|
set_xtransform_scale(&xf, sw, sh, w, h, -1, -1);
|
||||||
XRenderSetPictureTransform(trs->xinf->disp, trs->pic, &xf);
|
XRenderSetPictureTransform(trs->xinf->disp, trs->pic, &xf);
|
||||||
|
|
||||||
att.component_alpha = 0;
|
att.component_alpha = 0;
|
||||||
if (dc->render_op == _EVAS_RENDER_MUL)
|
if (dc->render_op == _EVAS_RENDER_MUL) att.component_alpha = 1;
|
||||||
att.component_alpha = 1;
|
|
||||||
XRenderChangePicture(trs->xinf->disp, trs->pic, CPComponentAlpha, &att);
|
XRenderChangePicture(trs->xinf->disp, trs->pic, CPComponentAlpha, &att);
|
||||||
|
|
||||||
XRenderComposite(trs->xinf->disp, op, trs->pic, mask, drs->pic,
|
XRenderComposite(trs->xinf->disp, op, trs->pic, mask, drs->pic,
|
||||||
0, 0, 0, 0, x, y, w, h);
|
(w HFW) / sw, (h HFH) / sh,
|
||||||
|
(w HFW) / sw, (h HFH) / sh,
|
||||||
|
x, y, w, h);
|
||||||
_xr_render_surface_free(trs);
|
_xr_render_surface_free(trs);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (srs->bordered && is_scaling)
|
if (srs->bordered && is_scaling)
|
||||||
{
|
{
|
||||||
trs = _xr_render_surface_new(srs->xinf, sw + 1, sh + 1,
|
trs = _xr_render_surface_new(srs->xinf, sw + 2, sh + 2,
|
||||||
srs->fmt, srs->alpha);
|
srs->fmt, srs->alpha);
|
||||||
if (!trs) return;
|
if (!trs) return;
|
||||||
|
|
||||||
att.component_alpha = 0;
|
att.component_alpha = 0;
|
||||||
XRenderChangePicture(srs->xinf->disp, srs->pic, CPComponentAlpha, &att);
|
XRenderChangePicture(srs->xinf->disp, srs->pic, CPComponentAlpha, &att);
|
||||||
XRenderSetPictureTransform(srs->xinf->disp, srs->pic, &xf);
|
XRenderSetPictureTransform(srs->xinf->disp, srs->pic, &xf);
|
||||||
XRenderComposite(srs->xinf->disp, PictOpSrc, srs->pic, None,
|
|
||||||
trs->pic, sx, sy, 0, 0, 0, 0, sw, sh);
|
|
||||||
|
|
||||||
XRenderComposite(srs->xinf->disp, PictOpSrc, srs->pic, None,
|
XRenderComposite(srs->xinf->disp, PictOpSrc, srs->pic, None,
|
||||||
trs->pic, sx + sw - 1, sy, 0, 0, sw, 0, 1, sh);
|
trs->pic, sx, sy, sx, sy, 0, 0, sw + 2, sh + 2);
|
||||||
XRenderComposite(srs->xinf->disp, PictOpSrc, srs->pic, None,
|
|
||||||
trs->pic, sx, sy + sh - 1, 0, 0, 0, sh, sw, 1);
|
|
||||||
XRenderComposite(srs->xinf->disp, PictOpSrc, srs->pic, None,
|
|
||||||
trs->pic, sx + sw - 1, sy + sh - 1, 0, 0, sw, sh, 1, 1);
|
|
||||||
|
|
||||||
XRenderSetPictureFilter(trs->xinf->disp, trs->pic, get_filter(smooth), NULL, 0);
|
XRenderSetPictureFilter(trs->xinf->disp, trs->pic, get_filter(smooth), NULL, 0);
|
||||||
|
|
||||||
set_xtransform_scale(&xf, sw, sh, w, h);
|
set_xtransform_scale(&xf, sw, sh, w, h, -1, -1);
|
||||||
XRenderSetPictureTransform(trs->xinf->disp, trs->pic, &xf);
|
XRenderSetPictureTransform(trs->xinf->disp, trs->pic, &xf);
|
||||||
|
|
||||||
if (dc->render_op == _EVAS_RENDER_MUL)
|
if (dc->render_op == _EVAS_RENDER_MUL)
|
||||||
|
@ -474,14 +469,17 @@ _xr_render_surface_composite(Xrender_Surface *srs, Xrender_Surface *drs, RGBA_Dr
|
||||||
}
|
}
|
||||||
|
|
||||||
XRenderComposite(trs->xinf->disp, op, trs->pic, mask, drs->pic,
|
XRenderComposite(trs->xinf->disp, op, trs->pic, mask, drs->pic,
|
||||||
0, 0, 0, 0, x, y, w, h);
|
(w HFW) / sw, (h HFH) / sh,
|
||||||
|
(w HFW) / sw, (h HFH) / sh,
|
||||||
|
// 1, 1, 1, 1,
|
||||||
|
x, y, w, h);
|
||||||
_xr_render_surface_free(trs);
|
_xr_render_surface_free(trs);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
XRenderSetPictureFilter(srs->xinf->disp, srs->pic, get_filter(smooth), NULL, 0);
|
XRenderSetPictureFilter(srs->xinf->disp, srs->pic, get_filter(smooth), NULL, 0);
|
||||||
|
|
||||||
set_xtransform_scale(&xf, sw, sh, w, h);
|
set_xtransform_scale(&xf, sw, sh, w, h, 0, 0);
|
||||||
XRenderSetPictureTransform(srs->xinf->disp, srs->pic, &xf);
|
XRenderSetPictureTransform(srs->xinf->disp, srs->pic, &xf);
|
||||||
|
|
||||||
att.component_alpha = 0;
|
att.component_alpha = 0;
|
||||||
|
@ -490,9 +488,11 @@ _xr_render_surface_composite(Xrender_Surface *srs, Xrender_Surface *drs, RGBA_Dr
|
||||||
XRenderChangePicture(srs->xinf->disp, srs->pic, CPComponentAlpha, &att);
|
XRenderChangePicture(srs->xinf->disp, srs->pic, CPComponentAlpha, &att);
|
||||||
|
|
||||||
XRenderComposite(srs->xinf->disp, op, srs->pic, mask, drs->pic,
|
XRenderComposite(srs->xinf->disp, op, srs->pic, mask, drs->pic,
|
||||||
((sx * w) + (sw / 2)) / sw,
|
((((sx + 1) * w) HFW) / sw),
|
||||||
((sy * h) + (sh / 2)) / sh,
|
((((sy + 1) * h) HFH) / sh),
|
||||||
0, 0, x, y, w, h);
|
((((sx + 1) * w) HFW) / sw),
|
||||||
|
((((sy + 1) * h) HFH) / sh),
|
||||||
|
x, y, w, h);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue