Skip to content

Instantly share code, notes, and snippets.

@riccardobl
Last active June 23, 2020 09:31
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save riccardobl/18603f9de508b1ab6c9e to your computer and use it in GitHub Desktop.
Save riccardobl/18603f9de508b1ab6c9e to your computer and use it in GitHub Desktop.
JavaFX Transparent WebView PATCH
/**
* @author Riccardo Balbo
* @description This patch aims to make the WebView capable to correctly render transparent pages.
* @license
* Copyright (c) 2015 Riccardo Balbo < riccardo @ forkforge . net >
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any
* damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any
* purpose, including commercial applications, and to alter it and
* redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must
* not claim that you wrote the original software. If you use this
* software in a product, an acknowledgment in the product
* documentation would be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must
* not be misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*/
import java.io.ByteArrayInputStream;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
import java.lang.instrument.Instrumentation;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
public class TransparentWebViewPatch implements ClassFileTransformer{
private final ClassPool _CLASS_POOL=ClassPool.getDefault();
public static void premain(String agentArguments,Instrumentation instrumentation){
instrumentation.addTransformer(new TransparentWebViewPatch());
}
// This patch aims to make the WebView capable to correctly render
// transparent pages.
@Override
public byte[] transform(ClassLoader loader, String class_name, Class<?> class_being_redefined, ProtectionDomain protection_domain, byte[] byte_code) throws IllegalClassFormatException {
if(class_name.equals("com/sun/webkit/WebPage")){
System.out.println("> Patching "+class_name+" ...");
try{
CtClass ct_class=_CLASS_POOL.makeClass(new ByteArrayInputStream(byte_code));
// First thing to do is edit the fireLoadEvent in order to force
// the page to set its own
// background to transparent black (0x00000000 argb) each time
// it changes
CtMethod fireLoadEvent_method=ct_class.getDeclaredMethod("fireLoadEvent");
fireLoadEvent_method.insertBefore("{\n"+" "
+ "setBackgroundColor(0);\n"
+"}");
// DEPRECATED CODE: NOT WORKING FROM JAVA 1.8.0_66
// Then, we edit the the paint2GC method in order to call
// clearRect every time right before it
// start to draw a clip (clips are parts of the rendered frame).
// We need this because when the webpage is rendered with the
// backbuffer enabled,
// every clip is just drawn over the old rendered frame without
// care about the alpha channel.
// NOTE: there is a system property
// com.sun.webkit.pagebackbuffer that could do the trick without
// this entire patch, but i didn't succeed in getting anything
// useful out of it...
// CtMethod
// paint2GC_method=ct_class.getDeclaredMethod("paint2GC");
// paint2GC_method.insertAt(696,
// "{\n" +
// " com.sun.webkit.graphics.WCRectangle clip=$1.getClip(); \n"
// +
// "
// $1.clearRect(clip.getX(),clip.getY(),clip.getWidth(),clip.getHeight());\n"
// +
// "}"
// );
// END OF DEPRECATED CODE
// Then we replace the scroll method body in order to force the
// repaint of the entire frame
// when the page is scrolled
CtMethod scroll_method=ct_class.getDeclaredMethod("scroll");
scroll_method.setBody(
"{\n"+" "
+ "addDirtyRect(new com.sun.webkit.graphics.WCRectangle(0f,0f,(float)width,(float)height));\n"
+"}"
);
byte_code=ct_class.toBytecode();
ct_class.detach();
}catch(Exception e){
System.out.println("/!\\ "+class_name+" patching failed :(");
e.printStackTrace();
return byte_code;
}
System.out.println("> "+class_name+" patching succeeded!");
}else if(class_name.equals("com/sun/javafx/webkit/prism/WCGraphicsPrismContext")){
System.out.println("> Patching "+class_name+" ...");
try{
CtClass ct_class=_CLASS_POOL.makeClass(new ByteArrayInputStream(byte_code));
// Then, we edit the the WCGraphicsPrismContext.setClip method
// in order to call clearRect over the area of the clip.
CtClass signature[]=new CtClass[]{_CLASS_POOL.get("com.sun.webkit.graphics.WCRectangle")};
CtMethod setClip_method=ct_class.getDeclaredMethod("setClip",signature);
setClip_method.insertBefore(
"{"+" "
+ " $0.clearRect($1.getX(),$1.getY(),$1.getWidth(),$1.getHeight());"
+"}");
byte_code=ct_class.toBytecode();
ct_class.detach();
}catch(Exception e){
System.out.println("/!\\ "+class_name+" patching failed :(");
e.printStackTrace();
return byte_code;
}
System.out.println("> "+class_name+" patching succeeded!");
}
return byte_code;
}
}
origin_dir=$PWD
rm -R build
mkdir build
rm -R /tmp/buildTransparentWebViewPatch
mkdir /tmp/buildTransparentWebViewPatch
cp TransparentWebViewPatch.java /tmp/buildTransparentWebViewPatch
cd /tmp/buildTransparentWebViewPatch
echo "Downloading jboss javassist..."
wget https://github.com/jboss-javassist/javassist/releases/download/rel_3_20_0_ga/javassist.jar > /dev/null 2>&1
echo "Compiling..."
javac -cp javassist.jar TransparentWebViewPatch.java
echo "Building jar..."
sed -n '/\/\*\*/,/\*\//p' TransparentWebViewPatch.java > INFO.txt
echo "Premain-Class: TransparentWebViewPatch" > manifest.txt
jar -cvfm TransparentWebViewPatch.jar manifest.txt INFO.txt TransparentWebViewPatch.class TransparentWebViewPatch.java
cp TransparentWebViewPatch.jar $origin_dir/build/
cp javassist.jar $origin_dir/build/
rm -R /tmp/buildTransparentWebViewPatch
echo "Done!"
@micheljung
Copy link

How to apply this patch?

@riccardobl
Copy link
Author

Hi, i'm sorry for the two months delay but i've lost or never received (still not sure how this gist thing works) the notification.

In case you still need it and for for posterity, this is what you need to do:

  • Compile this class and pack it in a jar file
  • Add this line to the manifest.mf
    Premain-Class: path.of.the.Patch
  • Run your app with -javaagent:path/of/the/jar/that/contains/the/patch.jar

@micheljung
Copy link

Thank you very much! This really solved a big issue for me :-)

I also had to:

  • Replace Patcher._CLASS_POOL with ClasPool.getDefault()
  • Add a method:
  public static void premain(String agentArguments, Instrumentation instrumentation) {
    instrumentation.addTransformer(new TransparentWebViewPatch());
  }

@riccardobl
Copy link
Author

True! I extrapolated this class from a project of mine, as you may have already guessed from the header, and i forgot to add the Patcher class that does what you said.

EDIT: Added the missing code and a build script

@micheljung
Copy link

Time to update this to Java 10 - have you already done it? :)

@1-alex98
Copy link

1-alex98 commented May 2, 2020

Breaks when I update to java fx 14

@1-alex98
Copy link

1-alex98 commented May 2, 2020

Caused by: java.lang.ClassFormatError: Nest member class_info_index 63 has bad constant type in class file com/sun/webkit/WebPage

@1-alex98
Copy link

1-alex98 commented May 2, 2020

Well I removed patching the "scroll" method now it runs and works as well. No idea what I did but seems working :D

@1-alex98
Copy link

1-alex98 commented May 3, 2020

Ok in the end that was not the solution instead:

scroll_method.insertBefore(
            "{\n" + "   "
                + "addDirtyRect(new com.sun.webkit.graphics.WCRectangle(0f,0f,(float)width,(float)height));\n"
                + "return;"
                + "}"
        );

works, setBody(...) somehow does not work.

@tbphong
Copy link

tbphong commented Jun 22, 2020

I have problem with javafx 14.
javassist.CannotCompileException: [source error] no such class: com.sun.webkit.graphics.WCRectangle
javassist.NotFoundException: com.sun.webkit.graphics.WCRectangle

Can you give me some advice? Thanks you.

@tbphong
Copy link

tbphong commented Jun 22, 2020

I have fixed above problem
Console show msg

Patching com/sun/webkit/WebPage ...
com/sun/webkit/WebPage patching succeeded!
Patching com/sun/javafx/webkit/prism/WCGraphicsPrismContext ...
com/sun/javafx/webkit/prism/WCGraphicsPrismContext patching succeeded!

But the webview background still not transparent

@1-alex98
Copy link

@tbphong
Copy link

tbphong commented Jun 23, 2020

Hi axel1200.
I have used your version.
Console show msg.

Patching com/sun/webkit/WebPage ...
com/sun/webkit/WebPage patching succeeded!
Patching com/sun/javafx/webkit/prism/WCGraphicsPrismContext ...
com/sun/javafx/webkit/prism/WCGraphicsPrismContext patching succeeded!

But the webview background still not transparent
I use JDK 14, javaassist 3.27.0-GA, and Java Fx 14.
Can you tell me what u are using? Thank a lot.

@1-alex98
Copy link

I used jdk 11 :D not sure if that creates an issue. As javafx 14 says it needs jdk 11+. Not sure about the rest but you should find it in the repo

@1-alex98
Copy link

javassist.version=3.23.1-GA

@1-alex98
Copy link

And these vm parameters of which many should not be related -DnativeDir=build/resources/native -Dprism.dirtyopts=false -Xms128m -Xmx712m -XX:MinHeapFreeRatio=15 -XX:MaxHeapFreeRatio=33 -XX:+HeapDumpOnOutOfMemoryError -XX:+UseStringDeduplication -javaagent:webview-patch/build/libs/webview-patch.jar -Djava.net.preferIPv4Stack=true -XX:TieredStopAtLevel=1 -noverify

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment