1 /*
2 * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
25
26 package javafx.scene.web;
27
28
29 import javafx.css.CssMetaData;
30 import javafx.css.StyleableBooleanProperty;
31 import javafx.css.StyleableDoubleProperty;
32 import javafx.css.StyleableObjectProperty;
33 import javafx.css.StyleableProperty;
34 import javafx.css.converter.BooleanConverter;
35 import javafx.css.converter.EnumConverter;
36 import javafx.css.converter.SizeConverter;
37 import com.sun.javafx.geom.BaseBounds;
38 import com.sun.javafx.geom.PickRay;
39 import com.sun.javafx.geom.transform.Affine3D;
40 import com.sun.javafx.geom.transform.BaseTransform;
41 import com.sun.javafx.scene.DirtyBits;
42 import com.sun.javafx.scene.NodeHelper;
43 import com.sun.javafx.scene.input.PickResultChooser;
44 import com.sun.java.scene.web.WebViewHelper;
45 import com.sun.javafx.tk.TKPulseListener;
46 import com.sun.javafx.tk.Toolkit;
47 import java.util.ArrayList;
48 import java.util.Collections;
49 import java.util.List;
50 import javafx.beans.property.*;
51 import javafx.beans.value.ChangeListener;
52 import javafx.beans.value.ObservableValue;
53 import javafx.collections.ObservableList;
54 import javafx.css.Styleable;
55 import javafx.geometry.Bounds;
56 import javafx.scene.Node;
57 import javafx.scene.Parent;
58 import javafx.scene.Scene;
59 import javafx.scene.text.FontSmoothingType;
60
61 /**
62 * {@code WebView} is a {@link javafx.scene.Node} that manages a
63 * {@link WebEngine} and displays its content. The associated {@code WebEngine}
64 * is created automatically at construction time and cannot be changed
65 * afterwards. {@code WebView} handles mouse and some keyboard events, and
66 * manages scrolling automatically, so there's no need to put it into a
67 * {@code ScrollPane}.
68 *
69 * <p>{@code WebView} objects must be created and accessed solely from the
70 * FX thread.
71 * @since JavaFX 2.0
72 */
73 final public class WebView extends Parent {
74 static {
75 WebViewHelper.setWebViewAccessor(new WebViewHelper.WebViewAccessor() {
76 @Override
77 public NGNode doCreatePeer(Node node) {
78 return ((WebView) node).doCreatePeer();
79 }
80
81 @Override
82 public void doUpdatePeer(Node node) {
83 ((WebView) node).doUpdatePeer();
84 }
85 });
86 }
87
88 private static final boolean DEFAULT_CONTEXT_MENU_ENABLED = true;
89 private static final FontSmoothingType DEFAULT_FONT_SMOOTHING_TYPE = FontSmoothingType.LCD;
90 private static final double DEFAULT_ZOOM = 1.0;
91 private static final double DEFAULT_FONT_SCALE = 1.0;
92 private static final double DEFAULT_MIN_WIDTH = 0;
93 private static final double DEFAULT_MIN_HEIGHT = 0;
94 private static final double DEFAULT_PREF_WIDTH = 800;
95 private static final double DEFAULT_PREF_HEIGHT = 600;
96 private static final double DEFAULT_MAX_WIDTH = Double.MAX_VALUE;
97 private static final double DEFAULT_MAX_HEIGHT = Double.MAX_VALUE;
98
99 private final WebEngine engine;
100 // pointer to native WebViewImpl
101 private final long handle;
102
103 /**
104 * The stage pulse listener registered with the toolkit.
251 */
252 public WebView() {
253 long[] nativeHandle = new long[1];
254 _initWebView(nativeHandle);
255 getStyleClass().add("web-view");
256 handle = nativeHandle[0];
257 engine = new WebEngine();
258 engine.setView(this);
259
260 stagePulseListener = () -> {
261 handleStagePulse();
262 };
263 focusedProperty().addListener((ov, t, t1) -> {
264 });
265 Toolkit.getToolkit().addStageTkPulseListener(stagePulseListener);
266
267 final ChangeListener<Bounds> chListener = new ChangeListener<Bounds>() {
268
269 @Override
270 public void changed(ObservableValue<? extends Bounds> observable, Bounds oldValue, Bounds newValue) {
271 WebView.this.impl_transformsChanged();
272 }
273 };
274
275 parentProperty().addListener(new ChangeListener<Parent>(){
276
277 @Override
278 public void changed(ObservableValue<? extends Parent> observable, Parent oldValue, Parent newValue) {
279 if (oldValue != null && newValue == null) {
280 // webview has been removed from scene
281 _removeWebView(handle);
282 }
283
284 if (oldValue != null) {
285 do {
286 oldValue.boundsInParentProperty().removeListener(chListener);
287 oldValue = oldValue.getParent();
288 } while (oldValue != null);
289 }
290
291 if (newValue != null) {
315
316 impl_treeVisibleProperty().addListener(new ChangeListener<Boolean>() {
317
318 @Override
319 public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
320 _setVisible(handle, newValue);
321 }
322 });
323 }
324 // Resizing support. Allows arbitrary growing and shrinking.
325 // Designed after javafx.scene.control.Control
326
327 @Override public boolean isResizable() {
328 return true;
329 }
330
331 @Override public void resize(double width, double height) {
332 this.width.set(width);
333 this.height.set(height);
334 NodeHelper.markDirty(this, DirtyBits.NODE_GEOMETRY);
335 impl_geomChanged();
336 _setWidth(handle, width);
337 _setHeight(handle, height);
338 }
339
340 /**
341 * Called during layout to determine the minimum width for this node.
342 *
343 * @return the minimum width that this node should be resized to during layout
344 */
345 @Override public final double minWidth(double height) {
346 return getMinWidth();
347 }
348
349 /**
350 * Called during layout to determine the minimum height for this node.
351 *
352 * @return the minimum height that this node should be resized to during layout
353 */
354 @Override public final double minHeight(double width) {
355 return getMinHeight();
988 // Here the page content is updated before CSS/Layout/Sync pass
989 // is initiated by the scene pulse. The update may
990 // change the WebView children and, if so, the children should be
991 // processed right away during the scene pulse.
992
993 // The WebView node does not render its pending render queues
994 // while it is invisible. Therefore, we should not schedule new
995 // render queues while the WebView is invisible to prevent
996 // the list of render queues from growing infinitely.
997 // Also, if and when the WebView becomes invisible, the currently
998 // pending render queues, if any, become obsolete and should be
999 // discarded.
1000
1001 boolean reallyVisible = impl_isTreeVisible()
1002 && getScene() != null
1003 && getScene().getWindow() != null
1004 && getScene().getWindow().isShowing();
1005
1006 if (reallyVisible) {
1007 if (NodeHelper.isDirty(this, DirtyBits.WEBVIEW_VIEW)) {
1008 Scene.impl_setAllowPGAccess(true);
1009 //getPGWebView().update(); // creates new render queues
1010 Scene.impl_setAllowPGAccess(false);
1011 }
1012 } else {
1013 _setVisible(handle, false);
1014 }
1015 }
1016
1017 /**
1018 * @treatAsPrivate implementation detail
1019 * @deprecated This is an internal API that is not intended for use and will be removed in the next version
1020 */
1021 @Deprecated
1022 @Override protected void impl_pickNodeLocal(PickRay pickRay, PickResultChooser result) {
1023 impl_intersects(pickRay, result);
1024 }
1025
1026 @Override protected ObservableList<Node> getChildren() {
1027 return super.getChildren();
1028 }
1029
1030 // Node stuff
1031
1032 /*
1033 * Note: This method MUST only be called via its accessor method.
1034 */
1035 private NGNode doCreatePeer() {
1036 // return new NGWebView();
1037 return null; // iOS doesn't need this method.
1038 }
1039
1040 /**
1041 * @treatAsPrivate implementation detail
1042 * @deprecated This is an internal API that is not intended for use and will be removed in the next version
1043 */
1044 @Deprecated
1045 @Override public BaseBounds impl_computeGeomBounds(BaseBounds bounds, BaseTransform tx) {
1046 bounds.deriveWithNewBounds(0, 0, 0, (float) getWidth(), (float)getHeight(), 0);
1047 tx.transform(bounds, bounds);
1048 return bounds;
1049 }
1050
1051 /**
1052 * @treatAsPrivate implementation detail
1053 * @deprecated This is an internal API that is not intended for use and will be removed in the next version
1054 */
1055 @Deprecated
1056 @Override protected boolean impl_computeContains(double localX, double localY) {
1057 // Note: Local bounds contain test is already done by the caller. (Node.contains()).
1058 return true;
1059 }
1060
1061 /*
1062 * Note: This method MUST only be called via its accessor method.
1063 */
1064 private void doUpdatePeer() {
1065 //PGWebView peer = getPGWebView();
1066
1067 if (NodeHelper.isDirty(this, DirtyBits.NODE_GEOMETRY)) {
1068 //peer.resize((float)getWidth(), (float)getHeight());
1069 }
1070 if (NodeHelper.isDirty(this, DirtyBits.WEBVIEW_VIEW)) {
1071 //peer.requestRender();
1072 }
1073 }
1074
1075 private static Affine3D calculateNodeToSceneTransform(Node node) {
1076 final Affine3D transform = new Affine3D();
1077 do {
1078 transform.preConcatenate(node.impl_getLeafTransform());
1079 node = node.getParent();
1080 } while (node != null);
1081
1082 return transform;
1083 }
1084
1085 @Deprecated
1086 @Override public void impl_transformsChanged() {
1087 super.impl_transformsChanged();
1088
1089 Affine3D trans = calculateNodeToSceneTransform(this);
1090 _setTransform(handle,
1091 trans.getMxx(), trans.getMxy(), trans.getMxz(), trans.getMxt(),
1092 trans.getMyx(), trans.getMyy(), trans.getMyz(), trans.getMyt(),
1093 trans.getMzx(), trans.getMzy(), trans.getMzz(), trans.getMzt());
1094 }
1095
1096 long getNativeHandle() {
1097 return handle;
1098 }
1099
1100
1101 // native callbacks
1102 private void notifyLoadStarted() {
1103 engine.notifyLoadStarted();
1104 }
1105 private void notifyLoadFinished(String loc, String content) {
1106 engine.notifyLoadFinished(loc, content);
1107 }
1108 private void notifyLoadFailed() {
|
1 /*
2 * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
25
26 package javafx.scene.web;
27
28
29 import javafx.css.CssMetaData;
30 import javafx.css.StyleableBooleanProperty;
31 import javafx.css.StyleableDoubleProperty;
32 import javafx.css.StyleableObjectProperty;
33 import javafx.css.StyleableProperty;
34 import javafx.css.converter.BooleanConverter;
35 import javafx.css.converter.EnumConverter;
36 import javafx.css.converter.SizeConverter;
37 import com.sun.javafx.geom.BaseBounds;
38 import com.sun.javafx.geom.PickRay;
39 import com.sun.javafx.geom.transform.Affine3D;
40 import com.sun.javafx.geom.transform.BaseTransform;
41 import com.sun.javafx.scene.DirtyBits;
42 import com.sun.javafx.scene.NodeHelper;
43 import com.sun.javafx.scene.input.PickResultChooser;
44 import com.sun.java.scene.web.WebViewHelper;
45 import com.sun.javafx.scene.SceneHelper;
46 import com.sun.javafx.sg.prism.NGNode;
47 import com.sun.javafx.tk.TKPulseListener;
48 import com.sun.javafx.tk.Toolkit;
49 import java.util.ArrayList;
50 import java.util.Collections;
51 import java.util.List;
52 import javafx.beans.property.*;
53 import javafx.beans.value.ChangeListener;
54 import javafx.beans.value.ObservableValue;
55 import javafx.collections.ObservableList;
56 import javafx.css.Styleable;
57 import javafx.geometry.Bounds;
58 import javafx.scene.Node;
59 import javafx.scene.Parent;
60 import javafx.scene.text.FontSmoothingType;
61
62 /**
63 * {@code WebView} is a {@link javafx.scene.Node} that manages a
64 * {@link WebEngine} and displays its content. The associated {@code WebEngine}
65 * is created automatically at construction time and cannot be changed
66 * afterwards. {@code WebView} handles mouse and some keyboard events, and
67 * manages scrolling automatically, so there's no need to put it into a
68 * {@code ScrollPane}.
69 *
70 * <p>{@code WebView} objects must be created and accessed solely from the
71 * FX thread.
72 * @since JavaFX 2.0
73 */
74 final public class WebView extends Parent {
75 static {
76 WebViewHelper.setWebViewAccessor(new WebViewHelper.WebViewAccessor() {
77 @Override
78 public NGNode doCreatePeer(Node node) {
79 return ((WebView) node).doCreatePeer();
80 }
81
82 @Override
83 public void doUpdatePeer(Node node) {
84 ((WebView) node).doUpdatePeer();
85 }
86
87 @Override
88 public void doTransformsChanged(Node node) {
89 ((WebView) node).doTransformsChanged();
90 }
91
92 @Override
93 public BaseBounds doComputeGeomBounds(Node node,
94 BaseBounds bounds, BaseTransform tx) {
95 return ((WebView) node).doComputeGeomBounds(bounds, tx);
96 }
97
98 @Override
99 public boolean doComputeContains(Node node, double localX, double localY) {
100 return ((WebView) node).doComputeContains(localX, localY);
101 }
102
103 @Override
104 public void doPickNodeLocal(Node node, PickRay localPickRay, PickResultChooser result) {
105 throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
106 }
107 });
108 }
109
110 private static final boolean DEFAULT_CONTEXT_MENU_ENABLED = true;
111 private static final FontSmoothingType DEFAULT_FONT_SMOOTHING_TYPE = FontSmoothingType.LCD;
112 private static final double DEFAULT_ZOOM = 1.0;
113 private static final double DEFAULT_FONT_SCALE = 1.0;
114 private static final double DEFAULT_MIN_WIDTH = 0;
115 private static final double DEFAULT_MIN_HEIGHT = 0;
116 private static final double DEFAULT_PREF_WIDTH = 800;
117 private static final double DEFAULT_PREF_HEIGHT = 600;
118 private static final double DEFAULT_MAX_WIDTH = Double.MAX_VALUE;
119 private static final double DEFAULT_MAX_HEIGHT = Double.MAX_VALUE;
120
121 private final WebEngine engine;
122 // pointer to native WebViewImpl
123 private final long handle;
124
125 /**
126 * The stage pulse listener registered with the toolkit.
273 */
274 public WebView() {
275 long[] nativeHandle = new long[1];
276 _initWebView(nativeHandle);
277 getStyleClass().add("web-view");
278 handle = nativeHandle[0];
279 engine = new WebEngine();
280 engine.setView(this);
281
282 stagePulseListener = () -> {
283 handleStagePulse();
284 };
285 focusedProperty().addListener((ov, t, t1) -> {
286 });
287 Toolkit.getToolkit().addStageTkPulseListener(stagePulseListener);
288
289 final ChangeListener<Bounds> chListener = new ChangeListener<Bounds>() {
290
291 @Override
292 public void changed(ObservableValue<? extends Bounds> observable, Bounds oldValue, Bounds newValue) {
293 NodeHelper.transformsChanged(WebView.this);
294 }
295 };
296
297 parentProperty().addListener(new ChangeListener<Parent>(){
298
299 @Override
300 public void changed(ObservableValue<? extends Parent> observable, Parent oldValue, Parent newValue) {
301 if (oldValue != null && newValue == null) {
302 // webview has been removed from scene
303 _removeWebView(handle);
304 }
305
306 if (oldValue != null) {
307 do {
308 oldValue.boundsInParentProperty().removeListener(chListener);
309 oldValue = oldValue.getParent();
310 } while (oldValue != null);
311 }
312
313 if (newValue != null) {
337
338 impl_treeVisibleProperty().addListener(new ChangeListener<Boolean>() {
339
340 @Override
341 public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
342 _setVisible(handle, newValue);
343 }
344 });
345 }
346 // Resizing support. Allows arbitrary growing and shrinking.
347 // Designed after javafx.scene.control.Control
348
349 @Override public boolean isResizable() {
350 return true;
351 }
352
353 @Override public void resize(double width, double height) {
354 this.width.set(width);
355 this.height.set(height);
356 NodeHelper.markDirty(this, DirtyBits.NODE_GEOMETRY);
357 NodeHelper.geomChanged(this);
358 _setWidth(handle, width);
359 _setHeight(handle, height);
360 }
361
362 /**
363 * Called during layout to determine the minimum width for this node.
364 *
365 * @return the minimum width that this node should be resized to during layout
366 */
367 @Override public final double minWidth(double height) {
368 return getMinWidth();
369 }
370
371 /**
372 * Called during layout to determine the minimum height for this node.
373 *
374 * @return the minimum height that this node should be resized to during layout
375 */
376 @Override public final double minHeight(double width) {
377 return getMinHeight();
1010 // Here the page content is updated before CSS/Layout/Sync pass
1011 // is initiated by the scene pulse. The update may
1012 // change the WebView children and, if so, the children should be
1013 // processed right away during the scene pulse.
1014
1015 // The WebView node does not render its pending render queues
1016 // while it is invisible. Therefore, we should not schedule new
1017 // render queues while the WebView is invisible to prevent
1018 // the list of render queues from growing infinitely.
1019 // Also, if and when the WebView becomes invisible, the currently
1020 // pending render queues, if any, become obsolete and should be
1021 // discarded.
1022
1023 boolean reallyVisible = impl_isTreeVisible()
1024 && getScene() != null
1025 && getScene().getWindow() != null
1026 && getScene().getWindow().isShowing();
1027
1028 if (reallyVisible) {
1029 if (NodeHelper.isDirty(this, DirtyBits.WEBVIEW_VIEW)) {
1030 SceneHelper.setAllowPGAccess(true);
1031 //getPGWebView().update(); // creates new render queues
1032 SceneHelper.setAllowPGAccess(false);
1033 }
1034 } else {
1035 _setVisible(handle, false);
1036 }
1037 }
1038
1039 @Override protected ObservableList<Node> getChildren() {
1040 return super.getChildren();
1041 }
1042
1043 // Node stuff
1044
1045 /*
1046 * Note: This method MUST only be called via its accessor method.
1047 */
1048 private NGNode doCreatePeer() {
1049 // return new NGWebView();
1050 return null; // iOS doesn't need this method.
1051 }
1052
1053 /*
1054 * Note: This method MUST only be called via its accessor method.
1055 */
1056 private BaseBounds doComputeGeomBounds(BaseBounds bounds, BaseTransform tx) {
1057 bounds.deriveWithNewBounds(0, 0, 0, (float) getWidth(), (float)getHeight(), 0);
1058 tx.transform(bounds, bounds);
1059 return bounds;
1060 }
1061
1062 /*
1063 * Note: This method MUST only be called via its accessor method.
1064 */
1065 private boolean doComputeContains(double localX, double localY) {
1066 // Note: Local bounds contain test is already done by the caller. (Node.contains()).
1067 return true;
1068 }
1069
1070 /*
1071 * Note: This method MUST only be called via its accessor method.
1072 */
1073 private void doUpdatePeer() {
1074 //PGWebView peer = getPGWebView();
1075
1076 if (NodeHelper.isDirty(this, DirtyBits.NODE_GEOMETRY)) {
1077 //peer.resize((float)getWidth(), (float)getHeight());
1078 }
1079 if (NodeHelper.isDirty(this, DirtyBits.WEBVIEW_VIEW)) {
1080 //peer.requestRender();
1081 }
1082 }
1083
1084 private static Affine3D calculateNodeToSceneTransform(Node node) {
1085 final Affine3D transform = new Affine3D();
1086 do {
1087 transform.preConcatenate(NodeHelper.getLeafTransform(node));
1088 node = node.getParent();
1089 } while (node != null);
1090
1091 return transform;
1092 }
1093
1094 /*
1095 * Note: This method MUST only be called via its accessor method.
1096 */
1097 private void doTransformsChanged() {
1098 Affine3D trans = calculateNodeToSceneTransform(this);
1099 _setTransform(handle,
1100 trans.getMxx(), trans.getMxy(), trans.getMxz(), trans.getMxt(),
1101 trans.getMyx(), trans.getMyy(), trans.getMyz(), trans.getMyt(),
1102 trans.getMzx(), trans.getMzy(), trans.getMzz(), trans.getMzt());
1103 }
1104
1105 long getNativeHandle() {
1106 return handle;
1107 }
1108
1109
1110 // native callbacks
1111 private void notifyLoadStarted() {
1112 engine.notifyLoadStarted();
1113 }
1114 private void notifyLoadFinished(String loc, String content) {
1115 engine.notifyLoadFinished(loc, content);
1116 }
1117 private void notifyLoadFailed() {
|