在 JavaFX Web View 显示的 IMG 标记中使用数据 URI 时"unknown protocol: data"



对标题表示歉意,我试图简洁,但在这种情况下很难做到。

我正在构建一个使用 JavaFX 的WebView类来显示 SVG 图像列表的应用程序。

因为它们需要适应父母的宽度(可以改变(,所以我被迫使用带有数据 URI 的<img>标签,而不是内联<svg>(我不会在这里详细介绍这个问题,但这是WebView使用的 WebKit 引擎的一个缺陷,它阻止<svg>元素根据它们的宽度调整它们的高度,这在当前的 Firefox 版本中工作正常(。

因此,包含元素的innerHTML可能如下所示(省略了大多数 Base64 数据(:

<img src="data:image/svg+xml;base64,PHN2Zy[...]" style="width: 100%;">
<img src="data:image/svg+xml;base64,PD94bW[...]" style="width: 100%;">

这将很好地显示图像。然而,我遇到了一些奇怪的行为:一旦我做了一些拖放图像(只是思考时的一些空闲动作,没有预期的行为(,这个异常出现了:

Exception in thread "JavaFX Application Thread" java.lang.IllegalArgumentException: Invalid URL: unknown protocol: data
at javafx.scene.image.Image.validateUrl(Image.java:1121)
at javafx.scene.image.Image.<init>(Image.java:620)
at com.sun.javafx.tk.quantum.QuantumClipboard.readImage(QuantumClipboard.java:400)
at com.sun.javafx.tk.quantum.QuantumClipboard.getContent(QuantumClipboard.java:291)
at javafx.scene.input.Clipboard.getContentImpl(Clipboard.java:261)
at javafx.scene.input.Dragboard.getContentImpl(Dragboard.java:62)
at javafx.scene.input.Clipboard.getContent(Clipboard.java:254)
at javafx.scene.web.WebView.lambda$registerEventHandlers$35(WebView.java:1170)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.scene.Scene$DnDGesture.handleExitEnter(Scene.java:3210)
at javafx.scene.Scene$DnDGesture.processTargetEnterOver(Scene.java:3098)
at javafx.scene.Scene$DnDGesture.access$6100(Scene.java:2909)
at javafx.scene.Scene$DropTargetListener.dragEnter(Scene.java:2813)
at com.sun.javafx.tk.quantum.GlassSceneDnDEventHandler.lambda$handleDragEnter$307(GlassSceneDnDEventHandler.java:70)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.quantum.GlassSceneDnDEventHandler.handleDragEnter(GlassSceneDnDEventHandler.java:65)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleDragEnter$361(GlassViewEventHandler.java:661)
at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleDragEnter(GlassViewEventHandler.java:660)
at com.sun.glass.ui.View.handleDragEnter(View.java:688)
at com.sun.glass.ui.View.notifyDragEnter(View.java:1020)
at com.sun.glass.ui.gtk.GtkDnDClipboard.pushToSystemImpl(Native Method)
at com.sun.glass.ui.gtk.GtkDnDClipboard.pushToSystem(GtkDnDClipboard.java:39)
at com.sun.glass.ui.SystemClipboard.flush(SystemClipboard.java:51)
at com.sun.glass.ui.ClipboardAssistance.flush(ClipboardAssistance.java:59)
at com.sun.javafx.tk.quantum.QuantumClipboard.flush(QuantumClipboard.java:274)
at com.sun.javafx.tk.quantum.QuantumToolkit.startDrag(QuantumToolkit.java:1224)
at javafx.scene.Scene$DnDGesture.dragDetectedProcessed(Scene.java:2953)
at javafx.scene.Scene$DnDGesture.process(Scene.java:3022)
at javafx.scene.Scene$DnDGesture.access$8200(Scene.java:2909)
at javafx.scene.Scene$MouseHandler.process(Scene.java:3773)
at javafx.scene.Scene$MouseHandler.access$1500(Scene.java:3485)
at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1762)
at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2494)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:380)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:294)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$354(GlassViewEventHandler.java:416)
at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:415)
at com.sun.glass.ui.View.handleMouseEvent(View.java:555)
at com.sun.glass.ui.View.notifyMouse(View.java:937)
at com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
at com.sun.glass.ui.gtk.GtkApplication.lambda$null$49(GtkApplication.java:139)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.net.MalformedURLException: unknown protocol: data
at java.net.URL.<init>(URL.java:600)
at java.net.URL.<init>(URL.java:490)
at java.net.URL.<init>(URL.java:439)
at javafx.scene.image.Image.validateUrl(Image.java:1115)
... 58 more

经过仔细检查,我了解到每次我尝试拖动图像时它都会这样做;其他一切都很好。

所以我不得不怀疑:拖放会导致这些错误的原因是什么?我该如何阻止它?

一些注意事项:

  • SVG 数据是"动态"创建的,并且它绝不存在于 磁盘。
  • 将数据写入磁盘不是一种选择。
  • 它们必须是 SVG 图像。

[编辑:根据新的观察更新了问题,即效果仅通过拖动图像发生,并且每次尝试仅发生一次。

正如我在评论中已经提到的,这是JavaFX中的一个开放错误: https://bugs.openjdk.java.net/browse/JDK-8160597

但似乎我已经找到了解决方法。我只需要在 Web 视图中添加三个侦听器即可处理拖动事件,这些事件根本不执行任何操作,甚至不消耗事件。之后,Web 视图中的文本选择仍然有效,拖动图像时的异常消失了:

webview {
setOnDragEntered {
}
setOnDragOver {
}
setOnDragExited {
}
}

这是 Kotlin 代码,因为我正在使用 TornadoFX(JavaFX 包装器(在 Kotlin 中开发。我猜在 Java 中代码看起来非常相似。只需直接在 Web 视图对象上调用这三个 set 方法,并使用空句柄方法添加一个匿名类。或者,如果您使用的是较新的 Java 版本,请使用空的 lambda 表达式。

最新更新