Unverified Commit cf6413c8 authored by Roman Sedaikin's avatar Roman Sedaikin Committed by GitHub

Transparency in window support. (#232)

Transparency support.
parent 358ae344
......@@ -71,6 +71,11 @@ tasks.register("runSoftware") {
dependsOn(casualRun)
}
tasks.register("runWithTransparency") {
additionalArguments += mapOf("skiko.transparency" to "true")
dependsOn(casualRun)
}
tasks.withType<KotlinCompile>().configureEach {
kotlinOptions.freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn"
}
......@@ -110,6 +110,16 @@ fun createWindow(title: String, exitOnClose: Boolean) = SwingUtilities.invokeLat
}
})
// Window transparency
if (System.getProperty("skiko.transparency") == "true") {
window.setUndecorated(true)
// On Windows we don't set transparent background to avoid event input issues (JDK specific)
if (hostOs != OS.Windows) {
window.background = java.awt.Color(0, 0, 0, 0)
}
window.layer.transparency = true
}
// MANDATORY: set window preferred size before calling pack()
window.preferredSize = Dimension(800, 600)
window.pack()
......
......@@ -10,6 +10,8 @@ interface SkiaRenderer {
expect open class SkiaLayer {
var renderApi: GraphicsApi
val contentScale: Float
var fullscreen: Boolean
var transparency: Boolean
}
internal class PictureHolder(val instance: Picture, val width: Int, val height: Int)
......@@ -5,13 +5,13 @@ import org.jetbrains.skia.Canvas
import org.jetbrains.skia.DirectContext
import org.jetbrains.skia.Picture
import org.jetbrains.skia.Surface
import org.jetbrains.skiko.OS
import org.jetbrains.skiko.GraphicsApi
import org.jetbrains.skiko.SkiaLayer
import org.jetbrains.skiko.hostArch
import org.jetbrains.skiko.hostOs
internal abstract class ContextHandler(val layer: SkiaLayer) {
open val bleachConstant = if (hostOs == OS.MacOS) 0 else -1
open val clearColor = if (layer.transparency) 0 else -1
var context: DirectContext? = null
var renderTarget: BackendRenderTarget? = null
var surface: Surface? = null
......@@ -21,7 +21,8 @@ internal abstract class ContextHandler(val layer: SkiaLayer) {
abstract fun initCanvas()
fun clearCanvas() {
canvas?.clear(bleachConstant)
val color = if (layer.fullscreen) -1 else clearColor
canvas?.clear(color)
}
open fun drawOnCanvas(picture: Picture) {
......
......@@ -6,4 +6,10 @@ actual open class SkiaLayer {
set(value) {}
actual val contentScale: Float
get() = TODO("Not yet implemented")
actual var fullscreen: Boolean
get() = TODO("Not yet implemented")
set(value) {}
actual var transparency: Boolean
get() = TODO("Not yet implemented")
set(value) {}
}
\ No newline at end of file
......@@ -4,4 +4,10 @@ actual open class SkiaLayer {
actual var renderApi: GraphicsApi = GraphicsApi.WEBGL
actual val contentScale: Float
get() = 1.0f
actual var fullscreen: Boolean
get() = false
set(value) = throw Exception("Fullscreen is not supported!")
actual var transparency: Boolean
get() = false
set(value) = throw Exception("Transparency is not supported!")
}
#if SK_BUILD_FOR_WIN
#include <dwmapi.h>
void enableTransparentWindow(HWND hwnd);
#endif
......@@ -63,13 +63,30 @@ extern "C"
glXMakeCurrent(display, window, *context);
}
JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_LinuxOpenGLRedrawerKt_createContext(JNIEnv *env, jobject redrawer, jlong displayPtr)
JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_LinuxOpenGLRedrawerKt_createContext(JNIEnv *env, jobject redrawer, jlong displayPtr, jboolean transparency)
{
Display *display = fromJavaPointer<Display *>(displayPtr);
if (!display) return 0;
XVisualInfo *vi;
if (transparency)
{
GLint att[] = {
GLX_RGBA,
GLX_RED_SIZE, 8,
GLX_GREEN_SIZE, 8,
GLX_BLUE_SIZE, 8,
GLX_ALPHA_SIZE, 8,
GLX_DEPTH_SIZE, 32,
GLX_DOUBLEBUFFER, True, None
};
vi = glXChooseVisual(display, 0, att);
}
else {
GLint att[] = {GLX_RGBA, GLX_DOUBLEBUFFER, True, None};
XVisualInfo *vi = glXChooseVisual(display, 0, att);
vi = glXChooseVisual(display, 0, att);
}
if (!vi) return 0;
......
......@@ -2,6 +2,7 @@
#include <jawt_md.h>
#include "jni_helpers.h"
#include "exceptions_handler.h"
#include "window_util.h"
#include "SkSurface.h"
#include "src/core/SkAutoMalloc.h"
......@@ -20,10 +21,15 @@ public:
extern "C"
{
JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_WindowsSoftwareRedrawer_createDevice(
JNIEnv *env, jobject redrawer, jlong contentHandle)
JNIEnv *env, jobject redrawer, jlong contentHandle, jboolean transparency)
{
SoftwareDevice *device = new SoftwareDevice();
device->window = (HWND)contentHandle;
if (transparency)
{
HWND parent = GetAncestor(device->window, GA_PARENT);
enableTransparentWindow(parent);
}
GetClientRect(device->window, &device->clientRect);
return toJavaPointer(device);
}
......
......@@ -4,6 +4,7 @@
#include <jawt_md.h>
#include "jni_helpers.h"
#include "exceptions_handler.h"
#include "window_util.h"
#include "GrBackendSurface.h"
#include "GrDirectContext.h"
......@@ -289,7 +290,7 @@ extern "C"
}
JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_Direct3DRedrawer_createDirectXDevice(
JNIEnv *env, jobject redrawer, jint adapterPriority, jlong contentHandle)
JNIEnv *env, jobject redrawer, jint adapterPriority, jlong contentHandle, jboolean transparency)
{
gr_cp<IDXGIFactory4> deviceFactory;
if (!SUCCEEDED(CreateDXGIFactory1(IID_PPV_ARGS(&deviceFactory))))
......@@ -329,6 +330,14 @@ extern "C"
d3dDevice->queue = queue;
d3dDevice->window = (HWND)contentHandle;
if (transparency)
{
//TODO: current swapChain does not support transparency
return 0;
// HWND wnd = GetAncestor(d3dDevice->window, GA_PARENT);
// enableTransparentWindow(wnd);
}
return toJavaPointer(d3dDevice);
}
......
......@@ -5,6 +5,7 @@
#include <dwmapi.h>
#include "jni_helpers.h"
#include "exceptions_handler.h"
#include "window_util.h"
extern "C"
{
......@@ -20,10 +21,11 @@ extern "C"
memset(&pixFormatDscr, 0, sizeof(PIXELFORMATDESCRIPTOR));
pixFormatDscr.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pixFormatDscr.nVersion = 1;
pixFormatDscr.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pixFormatDscr.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_SUPPORT_COMPOSITION;
pixFormatDscr.iPixelType = PFD_TYPE_RGBA;
pixFormatDscr.cColorBits = 32;
pixFormatDscr.cAlphaBits = 8;
int iPixelFormat = ChoosePixelFormat(device, &pixFormatDscr);
SetPixelFormat(device, iPixelFormat, &pixFormatDscr);
DescribePixelFormat(device, iPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pixFormatDscr);
......@@ -76,10 +78,16 @@ extern "C"
wglMakeCurrent(device, context);
}
JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_WindowsOpenGLRedrawerKt_createContext(JNIEnv *env, jobject redrawer, jlong devicePtr)
JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_WindowsOpenGLRedrawerKt_createContext(JNIEnv *env, jobject redrawer, jlong devicePtr, jlong contentHandle, jboolean transparency)
{
__try
{
if (transparency)
{
HWND parent = GetAncestor(fromJavaPointer<HWND>(contentHandle), GA_PARENT);
enableTransparentWindow(parent);
}
HDC device = fromJavaPointer<HDC>(devicePtr);
return toJavaPointer(wglCreateContext(device));
}
......
#if SK_BUILD_FOR_WIN
#include "window_util.h"
void enableTransparentWindow(HWND hwnd)
{
HRGN region = CreateRectRgn(0, 0, -1, -1);
DWM_BLURBEHIND bb = {0};
bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;
bb.hRgnBlur = region;
bb.fEnable = TRUE;
DwmEnableBlurBehindWindow(hwnd, &bb);
DeleteObject(region);
}
#endif
\ No newline at end of file
package org.jetbrains.skiko
import org.jetbrains.skia.*
import org.jetbrains.skia.Canvas
import org.jetbrains.skia.Bitmap
import org.jetbrains.skia.ColorAlphaType
import org.jetbrains.skia.ColorInfo
import org.jetbrains.skia.ColorType
import org.jetbrains.skia.ColorSpace
import org.jetbrains.skia.ClipMode
import org.jetbrains.skia.ImageInfo
import org.jetbrains.skia.Picture
import org.jetbrains.skia.PictureRecorder
import org.jetbrains.skia.Rect
import org.jetbrains.skiko.context.ContextHandler
import org.jetbrains.skiko.redrawer.Redrawer
import java.awt.Color
import java.awt.Graphics
import java.awt.event.*
import java.awt.im.InputMethodRequests
......@@ -25,6 +36,8 @@ actual open class SkiaLayer internal constructor(
ContentScale,
}
actual var transparency: Boolean = false
internal val backedLayer: HardwareLayer
constructor(
......@@ -36,6 +49,7 @@ actual open class SkiaLayer internal constructor(
init {
isOpaque = false
background = Color(0, 0, 0, 0)
layout = null
backedLayer = object : HardwareLayer() {
override fun paint(g: Graphics) {
......@@ -98,7 +112,7 @@ actual open class SkiaLayer internal constructor(
val windowHandle: Long
get() = backedLayer.windowHandle
var fullscreen: Boolean
actual var fullscreen: Boolean
get() = backedLayer.fullscreen
set(value) {
backedLayer.fullscreen = value
......
......@@ -8,7 +8,6 @@ import org.jetbrains.skiko.redrawer.AbstractDirectSoftwareRedrawer
import java.lang.ref.Reference
internal class DirectSoftwareContextHandler(layer: SkiaLayer) : ContextHandler(layer) {
override val bleachConstant = -1
var isInited = false
val softwareRedrawer: AbstractDirectSoftwareRedrawer
......
......@@ -6,7 +6,10 @@ import org.jetbrains.skia.ColorAlphaType
import org.jetbrains.skia.ImageInfo
import org.jetbrains.skia.Picture
import org.jetbrains.skiko.SkiaLayer
import org.jetbrains.skiko.hostOs
import org.jetbrains.skiko.OS
import java.awt.Transparency
import java.awt.Color
import java.awt.color.ColorSpace
import java.awt.image.BufferedImage
import java.awt.image.ComponentColorModel
......@@ -16,7 +19,7 @@ import java.awt.image.Raster
import java.awt.image.WritableRaster
internal class SoftwareContextHandler(layer: SkiaLayer) : ContextHandler(layer) {
override val bleachConstant = -1 // it looks like java.awt.Canvas doesn't support transparency
override val clearColor = if (layer.transparency && hostOs == OS.MacOS) 0 else -1
val colorModel = ComponentColorModel(
ColorSpace.getInstance(ColorSpace.CS_sRGB),
......@@ -76,7 +79,12 @@ internal class SoftwareContextHandler(layer: SkiaLayer) : ContextHandler(layer)
null
)
image = BufferedImage(colorModel, raster!!, false, null)
layer.backedLayer.getGraphics()?.drawImage(image!!, 0, 0, layer.width, layer.height, null)
val graphics = layer.backedLayer.getGraphics()
if (!layer.fullscreen && layer.transparency && hostOs == OS.MacOS) {
graphics?.setColor(Color(0, 0, 0, 0))
graphics?.clearRect(0, 0, w, h)
}
graphics?.drawImage(image!!, 0, 0, layer.width, layer.height, null)
}
}
......
......@@ -15,7 +15,7 @@ internal class Direct3DRedrawer(
private var isDisposed = false
private var drawLock = Any()
private val device = createDirectXDevice(getAdapterPriority(), layer.contentHandle).also {
private val device = createDirectXDevice(getAdapterPriority(), layer.contentHandle, layer.transparency).also {
if (it == 0L || !isVideoCardSupported(layer.renderApi)) {
throw RenderException("Failed to create DirectX12 device.")
}
......@@ -92,7 +92,7 @@ internal class Direct3DRedrawer(
val adapterName get() = getAdapterName(device)
val adapterMemorySize get() = getAdapterMemorySize(device)
private external fun createDirectXDevice(adapterPriority: Int, contentHandle: Long): Long
private external fun createDirectXDevice(adapterPriority: Int, contentHandle: Long, transparency: Boolean): Long
private external fun makeDirectXContext(device: Long): Long
private external fun makeDirectXSurface(device: Long, context: Long, width: Int, height: Int, index: Int): Long
private external fun resizeBuffers(device: Long, width: Int, height: Int)
......
......@@ -14,7 +14,7 @@ internal class LinuxOpenGLRedrawer(
init {
layer.backedLayer.lockLinuxDrawingSurface {
context = it.createContext()
context = it.createContext(layer.transparency)
if (context == 0L) {
throw RenderException("Cannot create Linux GL context")
}
......@@ -150,14 +150,14 @@ internal class LinuxOpenGLRedrawer(
}
}
private fun LinuxDrawingSurface.createContext() = createContext(display)
private fun LinuxDrawingSurface.createContext(transparency: Boolean) = createContext(display, transparency)
private fun LinuxDrawingSurface.destroyContext(context: Long) = destroyContext(display, context)
private fun LinuxDrawingSurface.makeCurrent(context: Long) = makeCurrent(display, window, context)
private fun LinuxDrawingSurface.swapBuffers() = swapBuffers(display, window)
private fun LinuxDrawingSurface.setSwapInterval(interval: Int) = setSwapInterval(display, window, interval)
private external fun makeCurrent(display: Long, window: Long, context: Long)
private external fun createContext(display: Long): Long
private external fun createContext(display: Long, transparency: Boolean): Long
private external fun destroyContext(display: Long, context: Long)
private external fun setSwapInterval(display: Long, window: Long, interval: Int)
private external fun swapBuffers(display: Long, window: Long)
\ No newline at end of file
......@@ -21,7 +21,7 @@ internal class MetalRedrawer(
private var isDisposed = false
private var drawLock = Any()
private val device = layer.backedLayer.useDrawingSurfacePlatformInfo {
createMetalDevice(getAdapterPriority(), it)
createMetalDevice(layer.windowHandle, layer.transparency, getAdapterPriority(), it)
}
private val windowHandle = layer.windowHandle
......@@ -131,7 +131,7 @@ internal class MetalRedrawer(
fun getAdapterName(): String = getAdapterName(device)
fun getAdapterMemorySize(): Long = getAdapterMemorySize(device)
private external fun createMetalDevice(adapterPriority: Int, platformInfo: Long): Long
private external fun createMetalDevice(window:Long, transparency: Boolean, adapterPriority: Int, platformInfo: Long): Long
private external fun makeMetalContext(device: Long): Long
private external fun makeMetalRenderTarget(device: Long, width: Int, height: Int): Long
private external fun disposeDevice(device: Long)
......
......@@ -11,7 +11,7 @@ internal class WindowsOpenGLRedrawer(
private val properties: SkiaLayerProperties
) : Redrawer {
private val device = layer.backedLayer.useDrawingSurfacePlatformInfo(::getDevice)
private val context = createContext(device).also {
private val context = createContext(device, layer.contentHandle, layer.transparency).also {
if (it == 0L) {
throw RenderException("Cannot create Windows GL context")
}
......@@ -115,7 +115,7 @@ internal class WindowsOpenGLRedrawer(
private external fun makeCurrent(device: Long, context: Long)
private external fun getDevice(platformInfo: Long): Long
private external fun createContext(device: Long): Long
private external fun createContext(device: Long, contentHandle:Long, transparency: Boolean): Long
private external fun deleteContext(context: Long)
private external fun setSwapInterval(interval: Int)
private external fun swapBuffers(device: Long)
......
......@@ -10,12 +10,12 @@ internal class WindowsSoftwareRedrawer(
) : AbstractDirectSoftwareRedrawer(layer, properties) {
init {
device = createDevice(layer.contentHandle).also {
device = createDevice(layer.contentHandle, layer.transparency).also {
if (it == 0L) {
throw RenderException("Failed to create Software device")
}
}
}
private external fun createDevice(contentHandle: Long): Long
private external fun createDevice(contentHandle: Long, transparency: Boolean): Long
}
\ No newline at end of file
......@@ -211,6 +211,4 @@ void getMetalDeviceAndQueue(void** device, void** queue)
*queue = (__bridge void*)fQueue;
}
} // extern C
\ No newline at end of file
......@@ -183,7 +183,7 @@ id<MTLDevice> MTLCreateIntegratedDevice(int adapterPriority) {
}
JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_MetalRedrawer_createMetalDevice(
JNIEnv *env, jobject redrawer, jint adapterPriority, jlong platformInfoPtr)
JNIEnv *env, jobject redrawer, jlong windowPtr, jboolean transparency, jint adapterPriority, jlong platformInfoPtr)
{
MetalDevice *device = [MetalDevice new];
......@@ -214,6 +214,12 @@ JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_MetalRedrawer_createMe
device.layer.backgroundColor = CGColorCreate(CGColorSpaceCreateDeviceRGB(), transparent);
device.layer.opaque = NO;
if (transparency)
{
NSWindow* window = (NSWindow*)windowPtr;
window.hasShadow = NO;
}
return (jlong) device;
}
......
......@@ -6,4 +6,10 @@ actual open class SkiaLayer {
set(value) {}
actual val contentScale: Float
get() = TODO("Not yet implemented")
actual var fullscreen: Boolean
get() = TODO("Not yet implemented")
set(value) {}
actual var transparency: Boolean
get() = TODO("Not yet implemented")
set(value) {}
}
\ No newline at end of file
......@@ -14,6 +14,12 @@ actual open class SkiaLayer(
actual val contentScale: Float
get() = _contentScale
actual var fullscreen: Boolean
get() = TODO("Not yet implemented")
set(value) {}
actual var transparency: Boolean = false
val nsView = NSView(NSMakeRect(0.0, 0.0, 640.0, 480.0))
var _contentScale: Float = 1.0f
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment