8309621: [XWayland][Screencast] screen capture failure with sun.java2d.uiScale other than 1
Reviewed-by: prr, honkar
This commit is contained in:
parent
8d2ad2b1ae
commit
387896fb34
@ -26,11 +26,14 @@
|
|||||||
package sun.awt.screencast;
|
package sun.awt.screencast;
|
||||||
|
|
||||||
import sun.awt.UNIXToolkit;
|
import sun.awt.UNIXToolkit;
|
||||||
|
import sun.java2d.pipe.Region;
|
||||||
import sun.security.action.GetPropertyAction;
|
import sun.security.action.GetPropertyAction;
|
||||||
|
|
||||||
|
import java.awt.GraphicsConfiguration;
|
||||||
import java.awt.GraphicsEnvironment;
|
import java.awt.GraphicsEnvironment;
|
||||||
import java.awt.Rectangle;
|
import java.awt.Rectangle;
|
||||||
import java.awt.Toolkit;
|
import java.awt.Toolkit;
|
||||||
|
import java.awt.geom.AffineTransform;
|
||||||
import java.security.AccessController;
|
import java.security.AccessController;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -109,9 +112,20 @@ public class ScreencastHelper {
|
|||||||
.stream(GraphicsEnvironment
|
.stream(GraphicsEnvironment
|
||||||
.getLocalGraphicsEnvironment()
|
.getLocalGraphicsEnvironment()
|
||||||
.getScreenDevices())
|
.getScreenDevices())
|
||||||
.map(graphicsDevice ->
|
.map(graphicsDevice -> {
|
||||||
graphicsDevice.getDefaultConfiguration().getBounds()
|
GraphicsConfiguration gc =
|
||||||
).toList();
|
graphicsDevice.getDefaultConfiguration();
|
||||||
|
Rectangle screen = gc.getBounds();
|
||||||
|
AffineTransform tx = gc.getDefaultTransform();
|
||||||
|
|
||||||
|
return new Rectangle(
|
||||||
|
Region.clipRound(screen.x * tx.getScaleX()),
|
||||||
|
Region.clipRound(screen.y * tx.getScaleY()),
|
||||||
|
Region.clipRound(screen.width * tx.getScaleX()),
|
||||||
|
Region.clipRound(screen.height * tx.getScaleY())
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static synchronized native void closeSession();
|
private static synchronized native void closeSession();
|
||||||
|
@ -369,6 +369,17 @@ final class TokenStorage {
|
|||||||
System.out.println("// getTokens same sizes 2. " + result);
|
System.out.println("// getTokens same sizes 2. " + result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 3. add tokens with the same or greater number of screens
|
||||||
|
// This is useful if we once received a token with one screen resolution
|
||||||
|
// and the same screen was later scaled in the system.
|
||||||
|
// In that case, the token is still valid.
|
||||||
|
|
||||||
|
allTokenItems
|
||||||
|
.stream()
|
||||||
|
.filter(t ->
|
||||||
|
t.allowedScreensBounds.size() >= affectedScreenBounds.size())
|
||||||
|
.forEach(result::add);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -319,6 +319,10 @@ GtkApi* gtk3_load(JNIEnv *env, const char* lib_name)
|
|||||||
|
|
||||||
/* Pixbuf */
|
/* Pixbuf */
|
||||||
fp_gdk_pixbuf_new = dl_symbol("gdk_pixbuf_new");
|
fp_gdk_pixbuf_new = dl_symbol("gdk_pixbuf_new");
|
||||||
|
fp_gdk_pixbuf_new_from_data = dl_symbol("gdk_pixbuf_new_from_data");
|
||||||
|
fp_gdk_pixbuf_scale_simple = dl_symbol("gdk_pixbuf_scale_simple");
|
||||||
|
fp_gdk_pixbuf_copy_area = dl_symbol("gdk_pixbuf_copy_area");
|
||||||
|
|
||||||
fp_gdk_pixbuf_new_from_file =
|
fp_gdk_pixbuf_new_from_file =
|
||||||
dl_symbol("gdk_pixbuf_new_from_file");
|
dl_symbol("gdk_pixbuf_new_from_file");
|
||||||
fp_gdk_pixbuf_get_from_drawable =
|
fp_gdk_pixbuf_get_from_drawable =
|
||||||
@ -3123,4 +3127,10 @@ static void gtk3_init(GtkApi* gtk) {
|
|||||||
gtk->g_main_context_iteration = fp_g_main_context_iteration;
|
gtk->g_main_context_iteration = fp_g_main_context_iteration;
|
||||||
gtk->g_error_free = fp_g_error_free;
|
gtk->g_error_free = fp_g_error_free;
|
||||||
gtk->g_unix_fd_list_get = fp_g_unix_fd_list_get;
|
gtk->g_unix_fd_list_get = fp_g_unix_fd_list_get;
|
||||||
|
|
||||||
|
gtk->gdk_pixbuf_new = fp_gdk_pixbuf_new;
|
||||||
|
gtk->gdk_pixbuf_new_from_data = fp_gdk_pixbuf_new_from_data;
|
||||||
|
gtk->gdk_pixbuf_scale_simple = fp_gdk_pixbuf_scale_simple;
|
||||||
|
gtk->gdk_pixbuf_get_pixels = fp_gdk_pixbuf_get_pixels;
|
||||||
|
gtk->gdk_pixbuf_copy_area = fp_gdk_pixbuf_copy_area;
|
||||||
}
|
}
|
||||||
|
@ -528,6 +528,30 @@ static void (*fp_gdk_draw_rectangle)(GdkDrawable*, GdkGC*, gboolean,
|
|||||||
gint, gint, gint, gint);
|
gint, gint, gint, gint);
|
||||||
static GdkPixbuf *(*fp_gdk_pixbuf_new)(GdkColorspace colorspace,
|
static GdkPixbuf *(*fp_gdk_pixbuf_new)(GdkColorspace colorspace,
|
||||||
gboolean has_alpha, int bits_per_sample, int width, int height);
|
gboolean has_alpha, int bits_per_sample, int width, int height);
|
||||||
|
|
||||||
|
static GdkPixbuf *(*fp_gdk_pixbuf_new_from_data)(
|
||||||
|
const guchar *data,
|
||||||
|
GdkColorspace colorspace,
|
||||||
|
gboolean has_alpha,
|
||||||
|
int bits_per_sample,
|
||||||
|
int width,
|
||||||
|
int height,
|
||||||
|
int rowstride,
|
||||||
|
GdkPixbufDestroyNotify destroy_fn,
|
||||||
|
gpointer destroy_fn_data
|
||||||
|
);
|
||||||
|
|
||||||
|
static void (*fp_gdk_pixbuf_copy_area) (
|
||||||
|
const GdkPixbuf* src_pixbuf,
|
||||||
|
int src_x,
|
||||||
|
int src_y,
|
||||||
|
int width,
|
||||||
|
int height,
|
||||||
|
GdkPixbuf* dest_pixbuf,
|
||||||
|
int dest_x,
|
||||||
|
int dest_y
|
||||||
|
);
|
||||||
|
|
||||||
static void (*fp_gdk_drawable_get_size)(GdkDrawable *drawable,
|
static void (*fp_gdk_drawable_get_size)(GdkDrawable *drawable,
|
||||||
gint* width, gint* height);
|
gint* width, gint* height);
|
||||||
static gboolean (*fp_gtk_init_check)(int* argc, char** argv);
|
static gboolean (*fp_gtk_init_check)(int* argc, char** argv);
|
||||||
|
@ -532,6 +532,8 @@ typedef void (*GClosureNotify)(gpointer data, GClosure *closure);
|
|||||||
typedef void (*GDestroyNotify)(gpointer data);
|
typedef void (*GDestroyNotify)(gpointer data);
|
||||||
typedef void (*GCallback)(void);
|
typedef void (*GCallback)(void);
|
||||||
|
|
||||||
|
typedef void GdkPixbuf;
|
||||||
|
typedef void (* GdkPixbufDestroyNotify) (guchar *pixels, gpointer data);
|
||||||
|
|
||||||
typedef struct GtkApi {
|
typedef struct GtkApi {
|
||||||
int version;
|
int version;
|
||||||
@ -797,6 +799,46 @@ typedef struct GtkApi {
|
|||||||
gint index_,
|
gint index_,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
|
||||||
|
GdkPixbuf *(*gdk_pixbuf_new)(GdkColorspace colorspace,
|
||||||
|
gboolean has_alpha,
|
||||||
|
int bits_per_sample,
|
||||||
|
int width,
|
||||||
|
int height);
|
||||||
|
|
||||||
|
|
||||||
|
GdkPixbuf *(*gdk_pixbuf_new_from_data)(
|
||||||
|
const guchar *data,
|
||||||
|
GdkColorspace colorspace,
|
||||||
|
gboolean has_alpha,
|
||||||
|
int bits_per_sample,
|
||||||
|
int width,
|
||||||
|
int height,
|
||||||
|
int rowstride,
|
||||||
|
GdkPixbufDestroyNotify destroy_fn,
|
||||||
|
gpointer destroy_fn_data
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
GdkPixbuf *(*gdk_pixbuf_scale_simple)(GdkPixbuf *src,
|
||||||
|
int dest_width,
|
||||||
|
int dest_heigh,
|
||||||
|
GdkInterpType interp_type
|
||||||
|
);
|
||||||
|
|
||||||
|
guchar* (*gdk_pixbuf_get_pixels) (const GdkPixbuf* pixbuf);
|
||||||
|
|
||||||
|
|
||||||
|
void (*gdk_pixbuf_copy_area) (
|
||||||
|
const GdkPixbuf* src_pixbuf,
|
||||||
|
int src_x,
|
||||||
|
int src_y,
|
||||||
|
int width,
|
||||||
|
int height,
|
||||||
|
GdkPixbuf* dest_pixbuf,
|
||||||
|
int dest_x,
|
||||||
|
int dest_y
|
||||||
|
);
|
||||||
|
|
||||||
/* </for screencast, used only with GTK3> */
|
/* </for screencast, used only with GTK3> */
|
||||||
} GtkApi;
|
} GtkApi;
|
||||||
|
|
||||||
|
@ -175,49 +175,6 @@ static gboolean initScreencast(const gchar *token,
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void convertRGBxToBGRx(int* in) {
|
|
||||||
char* o = (char*) in;
|
|
||||||
char tmp = o[0];
|
|
||||||
o[0] = o[2];
|
|
||||||
o[2] = tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gchar * cropTo(
|
|
||||||
struct spa_data data,
|
|
||||||
struct spa_video_info_raw raw,
|
|
||||||
guint32 x,
|
|
||||||
guint32 y,
|
|
||||||
guint32 width,
|
|
||||||
guint32 height
|
|
||||||
) {
|
|
||||||
int srcW = raw.size.width;
|
|
||||||
if (data.chunk->stride / 4 != srcW) {
|
|
||||||
fprintf(stderr, "%s:%i Unexpected stride / 4: %i srcW: %i\n",
|
|
||||||
__func__, __LINE__, data.chunk->stride / 4, srcW);
|
|
||||||
}
|
|
||||||
|
|
||||||
int* d = data.data;
|
|
||||||
|
|
||||||
int *outData = calloc(width * height, sizeof(int));
|
|
||||||
if (!outData) {
|
|
||||||
ERR("failed to allocate memory\n");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
gboolean needConversion = raw.format != SPA_VIDEO_FORMAT_BGRx;
|
|
||||||
for (guint32 j = y; j < y + height; ++j) {
|
|
||||||
for (guint32 i = x; i < x + width; ++i) {
|
|
||||||
int color = *(d + (j * srcW) + i);
|
|
||||||
if (needConversion) {
|
|
||||||
convertRGBxToBGRx(&color);
|
|
||||||
}
|
|
||||||
*(outData + ((j - y) * width) + (i - x)) = color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (gchar*) outData;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void onStreamParamChanged(
|
static void onStreamParamChanged(
|
||||||
void *userdata,
|
void *userdata,
|
||||||
uint32_t id,
|
uint32_t id,
|
||||||
@ -301,24 +258,81 @@ static void onStreamProcess(void *userdata) {
|
|||||||
|
|
||||||
struct spa_data spaData = spaBuffer->datas[0];
|
struct spa_data spaData = spaBuffer->datas[0];
|
||||||
|
|
||||||
|
gint streamWidth = data->rawFormat.size.width;
|
||||||
|
gint streamHeight = data->rawFormat.size.height;
|
||||||
|
|
||||||
DEBUG_SCREEN(screen);
|
DEBUG_SCREEN(screen);
|
||||||
DEBUG_SCREEN_PREFIX(screen,
|
DEBUG_SCREEN_PREFIX(screen,
|
||||||
"got a frame of size %d offset %d stride %d "
|
"got a frame of size %d offset %d stride %d "
|
||||||
"flags %d FD %li captureDataReady %i\n",
|
"flags %d FD %li captureDataReady %i of stream %dx%d\n",
|
||||||
spaBuffer->datas[0].chunk->size,
|
spaBuffer->datas[0].chunk->size,
|
||||||
spaData.chunk->offset,
|
spaData.chunk->offset,
|
||||||
spaData.chunk->stride,
|
spaData.chunk->stride,
|
||||||
spaData.chunk->flags,
|
spaData.chunk->flags,
|
||||||
spaData.fd,
|
spaData.fd,
|
||||||
screen->captureDataReady
|
screen->captureDataReady,
|
||||||
|
streamWidth,
|
||||||
|
streamHeight
|
||||||
);
|
);
|
||||||
|
|
||||||
data->screenProps->captureData = cropTo(
|
GdkRectangle captureArea = screen->captureArea;
|
||||||
spaData,
|
GdkRectangle screenBounds = screen->bounds;
|
||||||
data->rawFormat,
|
|
||||||
screen->captureArea.x, screen->captureArea.y,
|
GdkPixbuf *pixbuf = gtk->gdk_pixbuf_new_from_data(spaData.data,
|
||||||
screen->captureArea.width, screen->captureArea.height
|
GDK_COLORSPACE_RGB,
|
||||||
);
|
TRUE,
|
||||||
|
8,
|
||||||
|
streamWidth,
|
||||||
|
streamHeight,
|
||||||
|
spaData.chunk->stride,
|
||||||
|
NULL,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if (screen->bounds.width != streamWidth
|
||||||
|
|| screen->bounds.height != streamHeight) {
|
||||||
|
|
||||||
|
DEBUG_SCREEN_PREFIX(screen, "scaling stream data %dx%d -> %dx%d\n",
|
||||||
|
streamWidth, streamHeight,
|
||||||
|
screen->bounds.width, screen->bounds.height
|
||||||
|
);
|
||||||
|
|
||||||
|
GdkPixbuf *scaled = gtk->gdk_pixbuf_scale_simple(pixbuf,
|
||||||
|
screen->bounds.width,
|
||||||
|
screen->bounds.height,
|
||||||
|
GDK_INTERP_BILINEAR);
|
||||||
|
|
||||||
|
gtk->g_object_unref(pixbuf);
|
||||||
|
pixbuf = scaled;
|
||||||
|
}
|
||||||
|
|
||||||
|
GdkPixbuf *cropped = NULL;
|
||||||
|
if (captureArea.width != screenBounds.width
|
||||||
|
|| captureArea.height != screenBounds.height) {
|
||||||
|
|
||||||
|
cropped = gtk->gdk_pixbuf_new(GDK_COLORSPACE_RGB,
|
||||||
|
TRUE,
|
||||||
|
8,
|
||||||
|
captureArea.width,
|
||||||
|
captureArea.height);
|
||||||
|
if (cropped) {
|
||||||
|
gtk->gdk_pixbuf_copy_area(pixbuf,
|
||||||
|
captureArea.x,
|
||||||
|
captureArea.y,
|
||||||
|
captureArea.width,
|
||||||
|
captureArea.height,
|
||||||
|
cropped,
|
||||||
|
0, 0);
|
||||||
|
} else {
|
||||||
|
ERR("Cannot create a new pixbuf.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
gtk->g_object_unref(pixbuf);
|
||||||
|
pixbuf = NULL;
|
||||||
|
|
||||||
|
data->screenProps->captureDataPixbuf = cropped;
|
||||||
|
} else {
|
||||||
|
data->screenProps->captureDataPixbuf = pixbuf;
|
||||||
|
}
|
||||||
|
|
||||||
screen->captureDataReady = TRUE;
|
screen->captureDataReady = TRUE;
|
||||||
|
|
||||||
@ -366,11 +380,7 @@ static bool startStream(
|
|||||||
SPA_FORMAT_mediaSubtype,
|
SPA_FORMAT_mediaSubtype,
|
||||||
SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw),
|
SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw),
|
||||||
SPA_FORMAT_VIDEO_format,
|
SPA_FORMAT_VIDEO_format,
|
||||||
SPA_POD_CHOICE_ENUM_Id(
|
SPA_POD_Id(SPA_VIDEO_FORMAT_BGRx),
|
||||||
2,
|
|
||||||
SPA_VIDEO_FORMAT_RGBx,
|
|
||||||
SPA_VIDEO_FORMAT_BGRx
|
|
||||||
),
|
|
||||||
SPA_FORMAT_VIDEO_size,
|
SPA_FORMAT_VIDEO_size,
|
||||||
SPA_POD_CHOICE_RANGE_Rectangle(
|
SPA_POD_CHOICE_RANGE_Rectangle(
|
||||||
&SPA_RECTANGLE(320, 240),
|
&SPA_RECTANGLE(320, 240),
|
||||||
@ -910,7 +920,7 @@ JNIEXPORT jint JNICALL Java_sun_awt_screencast_ScreencastHelper_getRGBPixelsImpl
|
|||||||
"\t||\tx %5i y %5i w %5i h %5i %s\n"
|
"\t||\tx %5i y %5i w %5i h %5i %s\n"
|
||||||
"\t||\tx %5i y %5i w %5i h %5i %s\n"
|
"\t||\tx %5i y %5i w %5i h %5i %s\n"
|
||||||
"\t||\tx %5i y %5i w %5i h %5i %s\n\n",
|
"\t||\tx %5i y %5i w %5i h %5i %s\n\n",
|
||||||
i, screenProps->captureData,
|
i, screenProps->captureDataPixbuf,
|
||||||
requestedArea.x, requestedArea.y,
|
requestedArea.x, requestedArea.y,
|
||||||
requestedArea.width, requestedArea.height,
|
requestedArea.width, requestedArea.height,
|
||||||
"requested area",
|
"requested area",
|
||||||
@ -924,7 +934,7 @@ JNIEXPORT jint JNICALL Java_sun_awt_screencast_ScreencastHelper_getRGBPixelsImpl
|
|||||||
"in-screen coords capture area"
|
"in-screen coords capture area"
|
||||||
);
|
);
|
||||||
|
|
||||||
if (screenProps->captureData) {
|
if (screenProps->captureDataPixbuf) {
|
||||||
for (int y = 0; y < captureArea.height; y++) {
|
for (int y = 0; y < captureArea.height; y++) {
|
||||||
jsize preY = (requestedArea.y > screenProps->bounds.y)
|
jsize preY = (requestedArea.y > screenProps->bounds.y)
|
||||||
? 0
|
? 0
|
||||||
@ -939,14 +949,18 @@ JNIEXPORT jint JNICALL Java_sun_awt_screencast_ScreencastHelper_getRGBPixelsImpl
|
|||||||
(*env)->SetIntArrayRegion(
|
(*env)->SetIntArrayRegion(
|
||||||
env, pixelArray,
|
env, pixelArray,
|
||||||
start, len,
|
start, len,
|
||||||
((jint *) screenProps->captureData)
|
((jint *) gtk->gdk_pixbuf_get_pixels(
|
||||||
+ (captureArea.width * y)
|
screenProps->captureDataPixbuf
|
||||||
|
))
|
||||||
|
+ (captureArea.width * y)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
free(screenProps->captureData);
|
if (screenProps->captureDataPixbuf) {
|
||||||
screenProps->captureData = NULL;
|
gtk->g_object_unref(screenProps->captureDataPixbuf);
|
||||||
|
screenProps->captureDataPixbuf = NULL;
|
||||||
|
}
|
||||||
screenProps->shouldCapture = FALSE;
|
screenProps->shouldCapture = FALSE;
|
||||||
|
|
||||||
fp_pw_thread_loop_lock(pw.loop);
|
fp_pw_thread_loop_lock(pw.loop);
|
||||||
|
@ -48,7 +48,7 @@ struct ScreenProps {
|
|||||||
GdkRectangle captureArea;
|
GdkRectangle captureArea;
|
||||||
struct PwStreamData *data;
|
struct PwStreamData *data;
|
||||||
|
|
||||||
gchar *captureData;
|
GdkPixbuf *captureDataPixbuf;
|
||||||
volatile gboolean shouldCapture;
|
volatile gboolean shouldCapture;
|
||||||
volatile gboolean captureDataReady;
|
volatile gboolean captureDataReady;
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
* Copyright (c) 2022, JetBrains s.r.o.. All rights reserved.
|
* Copyright (c) 2022, JetBrains s.r.o.. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
@ -32,7 +32,6 @@ import java.awt.Point;
|
|||||||
import java.awt.Rectangle;
|
import java.awt.Rectangle;
|
||||||
import java.awt.Robot;
|
import java.awt.Robot;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import javax.swing.UIManager;
|
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -54,6 +53,12 @@ public class ScreenCaptureGtkTest {
|
|||||||
Color.GREEN, Color.BLUE, Color.ORANGE, Color.RED};
|
Color.GREEN, Color.BLUE, Color.ORANGE, Color.RED};
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
|
if ("2".equals(System.getProperty("jdk.gtk.version"))
|
||||||
|
&& System.getenv("WAYLAND_DISPLAY") != null) {
|
||||||
|
// screen capture is not supported with gtk2 on Wayland
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
final int topOffset = 50;
|
final int topOffset = 50;
|
||||||
final int leftOffset = 50;
|
final int leftOffset = 50;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user