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;
|
||||
|
||||
import sun.awt.UNIXToolkit;
|
||||
import sun.java2d.pipe.Region;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.security.AccessController;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
@ -109,9 +112,20 @@ public class ScreencastHelper {
|
||||
.stream(GraphicsEnvironment
|
||||
.getLocalGraphicsEnvironment()
|
||||
.getScreenDevices())
|
||||
.map(graphicsDevice ->
|
||||
graphicsDevice.getDefaultConfiguration().getBounds()
|
||||
).toList();
|
||||
.map(graphicsDevice -> {
|
||||
GraphicsConfiguration gc =
|
||||
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();
|
||||
|
@ -369,6 +369,17 @@ final class TokenStorage {
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -319,6 +319,10 @@ GtkApi* gtk3_load(JNIEnv *env, const char* lib_name)
|
||||
|
||||
/* Pixbuf */
|
||||
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 =
|
||||
dl_symbol("gdk_pixbuf_new_from_file");
|
||||
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_error_free = fp_g_error_free;
|
||||
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);
|
||||
static GdkPixbuf *(*fp_gdk_pixbuf_new)(GdkColorspace colorspace,
|
||||
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,
|
||||
gint* width, gint* height);
|
||||
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 (*GCallback)(void);
|
||||
|
||||
typedef void GdkPixbuf;
|
||||
typedef void (* GdkPixbufDestroyNotify) (guchar *pixels, gpointer data);
|
||||
|
||||
typedef struct GtkApi {
|
||||
int version;
|
||||
@ -797,6 +799,46 @@ typedef struct GtkApi {
|
||||
gint index_,
|
||||
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> */
|
||||
} GtkApi;
|
||||
|
||||
|
@ -175,49 +175,6 @@ static gboolean initScreencast(const gchar *token,
|
||||
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(
|
||||
void *userdata,
|
||||
uint32_t id,
|
||||
@ -301,24 +258,81 @@ static void onStreamProcess(void *userdata) {
|
||||
|
||||
struct spa_data spaData = spaBuffer->datas[0];
|
||||
|
||||
gint streamWidth = data->rawFormat.size.width;
|
||||
gint streamHeight = data->rawFormat.size.height;
|
||||
|
||||
DEBUG_SCREEN(screen);
|
||||
DEBUG_SCREEN_PREFIX(screen,
|
||||
"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,
|
||||
spaData.chunk->offset,
|
||||
spaData.chunk->stride,
|
||||
spaData.chunk->flags,
|
||||
spaData.fd,
|
||||
screen->captureDataReady
|
||||
screen->captureDataReady,
|
||||
streamWidth,
|
||||
streamHeight
|
||||
);
|
||||
|
||||
data->screenProps->captureData = cropTo(
|
||||
spaData,
|
||||
data->rawFormat,
|
||||
screen->captureArea.x, screen->captureArea.y,
|
||||
screen->captureArea.width, screen->captureArea.height
|
||||
);
|
||||
GdkRectangle captureArea = screen->captureArea;
|
||||
GdkRectangle screenBounds = screen->bounds;
|
||||
|
||||
GdkPixbuf *pixbuf = gtk->gdk_pixbuf_new_from_data(spaData.data,
|
||||
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;
|
||||
|
||||
@ -366,11 +380,7 @@ static bool startStream(
|
||||
SPA_FORMAT_mediaSubtype,
|
||||
SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw),
|
||||
SPA_FORMAT_VIDEO_format,
|
||||
SPA_POD_CHOICE_ENUM_Id(
|
||||
2,
|
||||
SPA_VIDEO_FORMAT_RGBx,
|
||||
SPA_VIDEO_FORMAT_BGRx
|
||||
),
|
||||
SPA_POD_Id(SPA_VIDEO_FORMAT_BGRx),
|
||||
SPA_FORMAT_VIDEO_size,
|
||||
SPA_POD_CHOICE_RANGE_Rectangle(
|
||||
&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\n",
|
||||
i, screenProps->captureData,
|
||||
i, screenProps->captureDataPixbuf,
|
||||
requestedArea.x, requestedArea.y,
|
||||
requestedArea.width, requestedArea.height,
|
||||
"requested area",
|
||||
@ -924,7 +934,7 @@ JNIEXPORT jint JNICALL Java_sun_awt_screencast_ScreencastHelper_getRGBPixelsImpl
|
||||
"in-screen coords capture area"
|
||||
);
|
||||
|
||||
if (screenProps->captureData) {
|
||||
if (screenProps->captureDataPixbuf) {
|
||||
for (int y = 0; y < captureArea.height; y++) {
|
||||
jsize preY = (requestedArea.y > screenProps->bounds.y)
|
||||
? 0
|
||||
@ -939,14 +949,18 @@ JNIEXPORT jint JNICALL Java_sun_awt_screencast_ScreencastHelper_getRGBPixelsImpl
|
||||
(*env)->SetIntArrayRegion(
|
||||
env, pixelArray,
|
||||
start, len,
|
||||
((jint *) screenProps->captureData)
|
||||
+ (captureArea.width * y)
|
||||
((jint *) gtk->gdk_pixbuf_get_pixels(
|
||||
screenProps->captureDataPixbuf
|
||||
))
|
||||
+ (captureArea.width * y)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
free(screenProps->captureData);
|
||||
screenProps->captureData = NULL;
|
||||
if (screenProps->captureDataPixbuf) {
|
||||
gtk->g_object_unref(screenProps->captureDataPixbuf);
|
||||
screenProps->captureDataPixbuf = NULL;
|
||||
}
|
||||
screenProps->shouldCapture = FALSE;
|
||||
|
||||
fp_pw_thread_loop_lock(pw.loop);
|
||||
|
@ -48,7 +48,7 @@ struct ScreenProps {
|
||||
GdkRectangle captureArea;
|
||||
struct PwStreamData *data;
|
||||
|
||||
gchar *captureData;
|
||||
GdkPixbuf *captureDataPixbuf;
|
||||
volatile gboolean shouldCapture;
|
||||
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.
|
||||
* 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.Robot;
|
||||
import java.awt.image.BufferedImage;
|
||||
import javax.swing.UIManager;
|
||||
import javax.imageio.ImageIO;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@ -54,6 +53,12 @@ public class ScreenCaptureGtkTest {
|
||||
Color.GREEN, Color.BLUE, Color.ORANGE, Color.RED};
|
||||
|
||||
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 leftOffset = 50;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user