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 23 * questions. 24 */ 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. 127 * This field guarantees that the listener will exist throughout 128 * the whole lifetime of the WebView node. This field is necessary 129 * because the toolkit references its stage pulse listeners weakly. 130 */ 131 private final TKPulseListener stagePulseListener; 132 133 /** 134 * Returns the {@code WebEngine} object. 135 */ 136 public final WebEngine getEngine() { 137 return engine; 138 } 139 140 private final ReadOnlyDoubleWrapper width = new ReadOnlyDoubleWrapper(this, "width"); 141 142 /** 143 * Returns width of this {@code WebView}. 144 */ 145 public final double getWidth() { 146 return width.get(); 147 } 148 149 /** 150 * Width of this {@code WebView}. 151 */ 152 public ReadOnlyDoubleProperty widthProperty() { 153 return width.getReadOnlyProperty(); 154 } 155 156 private final ReadOnlyDoubleWrapper height = new ReadOnlyDoubleWrapper(this, "height"); 157 158 /** 159 * Returns height of this {@code WebView}. 160 */ 161 public final double getHeight() { 162 return height.get(); 163 } 164 165 /** 166 * Height of this {@code WebView}. 167 */ 168 public ReadOnlyDoubleProperty heightProperty() { 169 return height.getReadOnlyProperty(); 170 } 171 172 /** 173 * Zoom factor applied to the whole page contents. 174 * 175 * @defaultValue 1.0 176 */ 177 private DoubleProperty zoom; 178 179 /** 180 * Sets current zoom factor applied to the whole page contents. 181 * @param value zoom factor to be set 182 * @see #zoomProperty() 183 * @see #getZoom() 184 * @since JavaFX 8.0 185 */ 186 public final void setZoom(double value) { 187 WebEngine.checkThread(); 188 zoomProperty().set(value); 189 } 190 191 /** 192 * Returns current zoom factor applied to the whole page contents. 193 * @return current zoom factor 194 * @see #zoomProperty() 195 * @see #setZoom(double value) 196 * @since JavaFX 8.0 197 */ 198 public final double getZoom() { 199 return (this.zoom != null) 200 ? this.zoom.get() 201 : DEFAULT_ZOOM; 202 } 203 204 /** 205 * Returns zoom property object. 206 * @return zoom property object 207 * @see #getZoom() 208 * @see #setZoom(double value) 209 * @since JavaFX 8.0 210 */ 211 public final DoubleProperty zoomProperty() { 212 if (zoom == null) { 213 zoom = new StyleableDoubleProperty(DEFAULT_ZOOM) { 214 @Override public void invalidated() { 215 Toolkit.getToolkit().checkFxUserThread(); 216 } 217 218 @Override public CssMetaData<WebView, Number> getCssMetaData() { 219 return StyleableProperties.ZOOM; 220 } 221 @Override public Object getBean() { 222 return WebView.this; 223 } 224 @Override public String getName() { 225 return "zoom"; 226 } 227 }; 228 } 229 return zoom; 230 } 231 232 /** 233 * Specifies scale factor applied to font. This setting affects 234 * text content but not images and fixed size elements. 235 * 236 * @defaultValue 1.0 237 */ 238 private DoubleProperty fontScale; 239 240 public final void setFontScale(double value) { 241 WebEngine.checkThread(); 242 fontScaleProperty().set(value); 243 } 244 245 public final double getFontScale() { 246 return (this.fontScale != null) 247 ? this.fontScale.get() 248 : DEFAULT_FONT_SCALE; 249 } 250 251 public DoubleProperty fontScaleProperty() { 252 if (fontScale == null) { 253 fontScale = new StyleableDoubleProperty(DEFAULT_FONT_SCALE) { 254 @Override public void invalidated() { 255 Toolkit.getToolkit().checkFxUserThread(); 256 } 257 @Override public CssMetaData<WebView, Number> getCssMetaData() { 258 return StyleableProperties.FONT_SCALE; 259 } 260 @Override public Object getBean() { 261 return WebView.this; 262 } 263 @Override public String getName() { 264 return "fontScale"; 265 } 266 }; 267 } 268 return fontScale; 269 } 270 271 /** 272 * Creates a {@code WebView} object. 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) { 314 do { 315 final Node n = newValue; 316 newValue.boundsInParentProperty().addListener(chListener); 317 newValue = newValue.getParent(); 318 } while (newValue != null); 319 } 320 } 321 322 }); 323 324 layoutBoundsProperty().addListener(new ChangeListener<Bounds>() { 325 326 @Override 327 public void changed(ObservableValue<? extends Bounds> observable, Bounds oldValue, Bounds newValue) { 328 Affine3D trans = calculateNodeToSceneTransform(WebView.this); 329 _setTransform(handle, 330 trans.getMxx(), trans.getMxy(), trans.getMxz(), trans.getMxt(), 331 trans.getMyx(), trans.getMyy(), trans.getMyz(), trans.getMyt(), 332 trans.getMzx(), trans.getMzy(), trans.getMzz(), trans.getMzt()); 333 334 } 335 336 }); 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(); 378 } 379 380 381 /** 382 * Called during layout to determine the preferred width for this node. 383 * 384 * @return the preferred width that this node should be resized to during layout 385 */ 386 @Override public final double prefWidth(double height) { 387 return getPrefWidth(); 388 } 389 390 /** 391 * Called during layout to determine the preferred height for this node. 392 * 393 * @return the preferred height that this node should be resized to during layout 394 */ 395 @Override public final double prefHeight(double width) { 396 return getPrefHeight(); 397 } 398 /** 399 * Called during layout to determine the maximum width for this node. 400 * 401 * @return the maximum width that this node should be resized to during layout 402 */ 403 @Override public final double maxWidth(double height) { 404 return getMaxWidth(); 405 } 406 407 /** 408 * Called during layout to determine the maximum height for this node. 409 * 410 * @return the maximum height that this node should be resized to during layout 411 */ 412 @Override public final double maxHeight(double width) { 413 return getMaxHeight(); 414 } 415 416 /** 417 * Minimum width property. 418 */ 419 public DoubleProperty minWidthProperty() { 420 if (minWidth == null) { 421 minWidth = new StyleableDoubleProperty(DEFAULT_MIN_WIDTH) { 422 @Override 423 public void invalidated() { 424 if (getParent() != null) { 425 getParent().requestLayout(); 426 } 427 } 428 @Override 429 public CssMetaData<WebView, Number> getCssMetaData() { 430 return StyleableProperties.MIN_WIDTH; 431 } 432 @Override 433 public Object getBean() { 434 return WebView.this; 435 } 436 @Override 437 public String getName() { 438 return "minWidth"; 439 } 440 }; 441 } 442 return minWidth; 443 } 444 private DoubleProperty minWidth; 445 446 /** 447 * Sets minimum width. 448 */ 449 public final void setMinWidth(double value) { 450 minWidthProperty().set(value); 451 _setWidth(handle, value); 452 } 453 454 /** 455 * Returns minimum width. 456 */ 457 public final double getMinWidth() { 458 return (this.minWidth != null) 459 ? this.minWidth.get() 460 : DEFAULT_MIN_WIDTH; 461 } 462 463 /** 464 * Minimum height property. 465 */ 466 public DoubleProperty minHeightProperty() { 467 if (minHeight == null) { 468 minHeight = new StyleableDoubleProperty(DEFAULT_MIN_HEIGHT) { 469 @Override 470 public void invalidated() { 471 if (getParent() != null) { 472 getParent().requestLayout(); 473 } 474 } 475 @Override 476 public CssMetaData<WebView, Number> getCssMetaData() { 477 return StyleableProperties.MIN_HEIGHT; 478 } 479 @Override 480 public Object getBean() { 481 return WebView.this; 482 } 483 @Override 484 public String getName() { 485 return "minHeight"; 486 } 487 }; 488 } 489 return minHeight; 490 } 491 private DoubleProperty minHeight; 492 493 /** 494 * Sets minimum height. 495 */ 496 public final void setMinHeight(double value) { 497 minHeightProperty().set(value); 498 _setHeight(handle, value); 499 } 500 501 /** 502 * Sets minimum height. 503 */ 504 public final double getMinHeight() { 505 return (this.minHeight != null) 506 ? this.minHeight.get() 507 : DEFAULT_MIN_HEIGHT; 508 } 509 510 /** 511 * Convenience method for setting minimum width and height. 512 */ 513 public void setMinSize(double minWidth, double minHeight) { 514 setMinWidth(minWidth); 515 setMinHeight(minHeight); 516 _setWidth(handle, minWidth); 517 _setHeight(handle, minHeight); 518 } 519 520 /** 521 * Preferred width property. 522 */ 523 public DoubleProperty prefWidthProperty() { 524 if (prefWidth == null) { 525 prefWidth = new StyleableDoubleProperty(DEFAULT_PREF_WIDTH) { 526 @Override 527 public void invalidated() { 528 if (getParent() != null) { 529 getParent().requestLayout(); 530 } 531 } 532 @Override 533 public CssMetaData<WebView, Number> getCssMetaData() { 534 return StyleableProperties.PREF_WIDTH; 535 } 536 @Override 537 public Object getBean() { 538 return WebView.this; 539 } 540 @Override 541 public String getName() { 542 return "prefWidth"; 543 } 544 }; 545 } 546 return prefWidth; 547 } 548 private DoubleProperty prefWidth; 549 550 /** 551 * Sets preferred width. 552 */ 553 public final void setPrefWidth(double value) { 554 prefWidthProperty().set(value); 555 _setWidth(handle, value); 556 } 557 558 /** 559 * Returns preferred width. 560 */ 561 public final double getPrefWidth() { 562 return (this.prefWidth != null) 563 ? this.prefWidth.get() 564 : DEFAULT_PREF_WIDTH; 565 } 566 567 /** 568 * Preferred height property. 569 */ 570 public DoubleProperty prefHeightProperty() { 571 if (prefHeight == null) { 572 prefHeight = new StyleableDoubleProperty(DEFAULT_PREF_HEIGHT) { 573 @Override 574 public void invalidated() { 575 if (getParent() != null) { 576 getParent().requestLayout(); 577 } 578 } 579 @Override 580 public CssMetaData<WebView, Number> getCssMetaData() { 581 return StyleableProperties.PREF_HEIGHT; 582 } 583 @Override 584 public Object getBean() { 585 return WebView.this; 586 } 587 @Override 588 public String getName() { 589 return "prefHeight"; 590 } 591 }; 592 } 593 return prefHeight; 594 } 595 private DoubleProperty prefHeight; 596 597 /** 598 * Sets preferred height. 599 */ 600 public final void setPrefHeight(double value) { 601 prefHeightProperty().set(value); 602 _setHeight(handle, value); 603 } 604 605 /** 606 * Returns preferred height. 607 */ 608 public final double getPrefHeight() { 609 return (this.prefHeight != null) 610 ? this.prefHeight.get() 611 : DEFAULT_PREF_HEIGHT; 612 } 613 614 /** 615 * Convenience method for setting preferred width and height. 616 */ 617 public void setPrefSize(double prefWidth, double prefHeight) { 618 setPrefWidth(prefWidth); 619 setPrefHeight(prefHeight); 620 _setWidth(handle, prefWidth); 621 _setHeight(handle, prefHeight); 622 } 623 624 /** 625 * Maximum width property. 626 */ 627 public DoubleProperty maxWidthProperty() { 628 if (maxWidth == null) { 629 maxWidth = new StyleableDoubleProperty(DEFAULT_MAX_WIDTH) { 630 @Override 631 public void invalidated() { 632 if (getParent() != null) { 633 getParent().requestLayout(); 634 } 635 } 636 @Override 637 public CssMetaData<WebView, Number> getCssMetaData() { 638 return StyleableProperties.MAX_WIDTH; 639 } 640 @Override 641 public Object getBean() { 642 return WebView.this; 643 } 644 @Override 645 public String getName() { 646 return "maxWidth"; 647 } 648 }; 649 } 650 return maxWidth; 651 } 652 private DoubleProperty maxWidth; 653 654 /** 655 * Sets maximum width. 656 */ 657 public final void setMaxWidth(double value) { 658 maxWidthProperty().set(value); 659 _setWidth(handle, value); 660 } 661 662 /** 663 * Returns maximum width. 664 */ 665 public final double getMaxWidth() { 666 return (this.maxWidth != null) 667 ? this.maxWidth.get() 668 : DEFAULT_MAX_WIDTH; 669 } 670 671 /** 672 * Maximum height property. 673 */ 674 public DoubleProperty maxHeightProperty() { 675 if (maxHeight == null) { 676 maxHeight = new StyleableDoubleProperty(DEFAULT_MAX_HEIGHT) { 677 @Override 678 public void invalidated() { 679 if (getParent() != null) { 680 getParent().requestLayout(); 681 } 682 } 683 @Override 684 public CssMetaData<WebView, Number> getCssMetaData() { 685 return StyleableProperties.MAX_HEIGHT; 686 } 687 @Override 688 public Object getBean() { 689 return WebView.this; 690 } 691 @Override 692 public String getName() { 693 return "maxHeight"; 694 } 695 }; 696 } 697 return maxHeight; 698 } 699 private DoubleProperty maxHeight; 700 701 /** 702 * Sets maximum height. 703 */ 704 public final void setMaxHeight(double value) { 705 maxHeightProperty().set(value); 706 _setHeight(handle, value); 707 } 708 709 /** 710 * Returns maximum height. 711 */ 712 public final double getMaxHeight() { 713 return (this.maxHeight != null) 714 ? this.maxHeight.get() 715 : DEFAULT_MAX_HEIGHT; 716 } 717 718 /** 719 * Convenience method for setting maximum width and height. 720 */ 721 public void setMaxSize(double maxWidth, double maxHeight) { 722 setMaxWidth(maxWidth); 723 setMaxHeight(maxHeight); 724 _setWidth(handle, maxWidth); 725 _setHeight(handle, maxHeight); 726 } 727 728 729 /** 730 * Specifies a requested font smoothing type : gray or LCD. 731 * 732 * The width of the bounding box is defined by the widest row. 733 * 734 * Note: LCD mode doesn't apply in numerous cases, such as various 735 * compositing modes, where effects are applied and very large glyphs. 736 * 737 * @defaultValue FontSmoothingType.LCD 738 * @since JavaFX 2.2 739 */ 740 private ObjectProperty<FontSmoothingType> fontSmoothingType; 741 742 public final void setFontSmoothingType(FontSmoothingType value) { 743 fontSmoothingTypeProperty().set(value); 744 } 745 746 public final FontSmoothingType getFontSmoothingType() { 747 return (this.fontSmoothingType != null) 748 ? this.fontSmoothingType.get() 749 : DEFAULT_FONT_SMOOTHING_TYPE; 750 } 751 752 public final ObjectProperty<FontSmoothingType> fontSmoothingTypeProperty() { 753 if (this.fontSmoothingType == null) { 754 this.fontSmoothingType = new StyleableObjectProperty<FontSmoothingType>(DEFAULT_FONT_SMOOTHING_TYPE) { 755 @Override 756 public void invalidated() { 757 Toolkit.getToolkit().checkFxUserThread(); 758 } 759 @Override 760 public CssMetaData<WebView, FontSmoothingType> getCssMetaData() { 761 return StyleableProperties.FONT_SMOOTHING_TYPE; 762 } 763 @Override 764 public Object getBean() { 765 return WebView.this; 766 } 767 @Override 768 public String getName() { 769 return "fontSmoothingType"; 770 } 771 }; 772 } 773 return this.fontSmoothingType; 774 } 775 776 /** 777 * Specifies whether context menu is enabled. 778 * 779 * @defaultValue true 780 * @since JavaFX 2.2 781 */ 782 private BooleanProperty contextMenuEnabled; 783 784 public final void setContextMenuEnabled(boolean value) { 785 contextMenuEnabledProperty().set(value); 786 } 787 788 public final boolean isContextMenuEnabled() { 789 return contextMenuEnabled == null 790 ? DEFAULT_CONTEXT_MENU_ENABLED 791 : contextMenuEnabled.get(); 792 } 793 794 public final BooleanProperty contextMenuEnabledProperty() { 795 if (contextMenuEnabled == null) { 796 contextMenuEnabled = new StyleableBooleanProperty(DEFAULT_CONTEXT_MENU_ENABLED) { 797 @Override public void invalidated() { 798 Toolkit.getToolkit().checkFxUserThread(); 799 } 800 801 @Override public CssMetaData<WebView, Boolean> getCssMetaData() { 802 return StyleableProperties.CONTEXT_MENU_ENABLED; 803 } 804 805 @Override public Object getBean() { 806 return WebView.this; 807 } 808 809 @Override public String getName() { 810 return "contextMenuEnabled"; 811 } 812 }; 813 } 814 return contextMenuEnabled; 815 } 816 817 /** 818 * Super-lazy instantiation pattern from Bill Pugh. 819 */ 820 private static final class StyleableProperties { 821 822 private static final CssMetaData<WebView, Boolean> CONTEXT_MENU_ENABLED 823 = new CssMetaData<WebView, Boolean>( 824 "-fx-context-menu-enabled", 825 BooleanConverter.getInstance(), 826 DEFAULT_CONTEXT_MENU_ENABLED) 827 { 828 @Override public boolean isSettable(WebView view) { 829 return view.contextMenuEnabled == null || !view.contextMenuEnabled.isBound(); 830 } 831 @Override public StyleableProperty<Boolean> getStyleableProperty(WebView view) { 832 return (StyleableProperty<Boolean>)view.contextMenuEnabledProperty(); 833 } 834 }; 835 836 private static final CssMetaData<WebView, FontSmoothingType> FONT_SMOOTHING_TYPE 837 = new CssMetaData<WebView, FontSmoothingType>( 838 "-fx-font-smoothing-type", 839 new EnumConverter<FontSmoothingType>(FontSmoothingType.class), 840 DEFAULT_FONT_SMOOTHING_TYPE) { 841 @Override 842 public boolean isSettable(WebView view) { 843 return view.fontSmoothingType == null || !view.fontSmoothingType.isBound(); 844 } 845 @Override 846 public StyleableProperty<FontSmoothingType> getStyleableProperty(WebView view) { 847 return (StyleableProperty<FontSmoothingType>)view.fontSmoothingTypeProperty(); 848 } 849 }; 850 851 private static final CssMetaData<WebView, Number> ZOOM 852 = new CssMetaData<WebView, Number>( 853 "-fx-zoom", 854 SizeConverter.getInstance(), 855 DEFAULT_ZOOM) { 856 @Override public boolean isSettable(WebView view) { 857 return view.zoom == null || !view.zoom.isBound(); 858 } 859 @Override public StyleableProperty<Number> getStyleableProperty(WebView view) { 860 return (StyleableProperty<Number>)view.zoomProperty(); 861 } 862 }; 863 864 private static final CssMetaData<WebView, Number> FONT_SCALE 865 = new CssMetaData<WebView, Number>( 866 "-fx-font-scale", 867 SizeConverter.getInstance(), 868 DEFAULT_FONT_SCALE) { 869 @Override 870 public boolean isSettable(WebView view) { 871 return view.fontScale == null || !view.fontScale.isBound(); 872 } 873 @Override 874 public StyleableProperty<Number> getStyleableProperty(WebView view) { 875 return (StyleableProperty<Number>)view.fontScaleProperty(); 876 } 877 }; 878 879 private static final CssMetaData<WebView, Number> MIN_WIDTH 880 = new CssMetaData<WebView, Number>( 881 "-fx-min-width", 882 SizeConverter.getInstance(), 883 DEFAULT_MIN_WIDTH) { 884 @Override 885 public boolean isSettable(WebView view) { 886 return view.minWidth == null || !view.minWidth.isBound(); 887 } 888 @Override 889 public StyleableProperty<Number> getStyleableProperty(WebView view) { 890 return (StyleableProperty<Number>)view.minWidthProperty(); 891 } 892 }; 893 894 private static final CssMetaData<WebView, Number> MIN_HEIGHT 895 = new CssMetaData<WebView, Number>( 896 "-fx-min-height", 897 SizeConverter.getInstance(), 898 DEFAULT_MIN_HEIGHT) { 899 @Override 900 public boolean isSettable(WebView view) { 901 return view.minHeight == null || !view.minHeight.isBound(); 902 } 903 @Override 904 public StyleableProperty<Number> getStyleableProperty(WebView view) { 905 return (StyleableProperty<Number>)view.minHeightProperty(); 906 } 907 }; 908 909 private static final CssMetaData<WebView, Number> MAX_WIDTH 910 = new CssMetaData<WebView, Number>( 911 "-fx-max-width", 912 SizeConverter.getInstance(), 913 DEFAULT_MAX_WIDTH) { 914 @Override 915 public boolean isSettable(WebView view) { 916 return view.maxWidth == null || !view.maxWidth.isBound(); 917 } 918 @Override 919 public StyleableProperty<Number> getStyleableProperty(WebView view) { 920 return (StyleableProperty<Number>)view.maxWidthProperty(); 921 } 922 }; 923 924 private static final CssMetaData<WebView, Number> MAX_HEIGHT 925 = new CssMetaData<WebView, Number>( 926 "-fx-max-height", 927 SizeConverter.getInstance(), 928 DEFAULT_MAX_HEIGHT) { 929 @Override 930 public boolean isSettable(WebView view) { 931 return view.maxHeight == null || !view.maxHeight.isBound(); 932 } 933 @Override 934 public StyleableProperty<Number> getStyleableProperty(WebView view) { 935 return (StyleableProperty<Number>)view.maxHeightProperty(); 936 } 937 }; 938 939 private static final CssMetaData<WebView, Number> PREF_WIDTH 940 = new CssMetaData<WebView, Number>( 941 "-fx-pref-width", 942 SizeConverter.getInstance(), 943 DEFAULT_PREF_WIDTH) { 944 @Override 945 public boolean isSettable(WebView view) { 946 return view.prefWidth == null || !view.prefWidth.isBound(); 947 } 948 @Override 949 public StyleableProperty<Number> getStyleableProperty(WebView view) { 950 return (StyleableProperty<Number>)view.prefWidthProperty(); 951 } 952 }; 953 954 private static final CssMetaData<WebView, Number> PREF_HEIGHT 955 = new CssMetaData<WebView, Number>( 956 "-fx-pref-height", 957 SizeConverter.getInstance(), 958 DEFAULT_PREF_HEIGHT) { 959 @Override 960 public boolean isSettable(WebView view) { 961 return view.prefHeight == null || !view.prefHeight.isBound(); 962 } 963 @Override 964 public StyleableProperty<Number> getStyleableProperty(WebView view) { 965 return (StyleableProperty<Number>)view.prefHeightProperty(); 966 } 967 }; 968 969 private static final List<CssMetaData<? extends Styleable, ?>> STYLEABLES; 970 971 static { 972 List<CssMetaData<? extends Styleable, ?>> styleables 973 = new ArrayList<CssMetaData<? extends Styleable, ?>>(Parent.getClassCssMetaData()); 974 styleables.add(CONTEXT_MENU_ENABLED); 975 styleables.add(FONT_SMOOTHING_TYPE); 976 styleables.add(ZOOM); 977 styleables.add(FONT_SCALE); 978 styleables.add(MIN_WIDTH); 979 styleables.add(PREF_WIDTH); 980 styleables.add(MAX_WIDTH); 981 styleables.add(MIN_HEIGHT); 982 styleables.add(PREF_HEIGHT); 983 styleables.add(MAX_HEIGHT); 984 STYLEABLES = Collections.unmodifiableList(styleables); 985 } 986 } 987 988 /** 989 * @return The CssMetaData associated with this class, which may include the 990 * CssMetaData of its super classes. 991 * @since JavaFX 8.0 992 */ 993 public static List<CssMetaData<? extends Styleable, ?>> getClassCssMetaData() { 994 return StyleableProperties.STYLEABLES; 995 } 996 997 /** 998 * {@inheritDoc} 999 * @since JavaFX 8.0 1000 */ 1001 @Override 1002 public List<CssMetaData<? extends Styleable, ?>> getCssMetaData() { 1003 return getClassCssMetaData(); 1004 } 1005 1006 // event handling 1007 1008 private void handleStagePulse() { 1009 // The stage pulse occurs before the scene pulse. 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() { 1118 engine.notifyLoadFailed(); 1119 } 1120 private void notifyJavaCall(String arg) { 1121 engine.notifyJavaCall(arg); 1122 } 1123 1124 1125 /* Inits native WebView and returns its pointer in the given array */ 1126 private native void _initWebView(long[] nativeHandle); 1127 1128 /* Sets width of the native WebView */ 1129 private native void _setWidth(long handle, double w); 1130 1131 /* Sets height of the native WebView */ 1132 private native void _setHeight(long handle, double h); 1133 1134 /* Sets visibility of the native WebView */ 1135 private native void _setVisible(long handle, boolean v); 1136 1137 /* Removes the native WebView from scene */ 1138 private native void _removeWebView(long handle); 1139 1140 /* Applies transform on the native WebView */ 1141 private native void _setTransform(long handle, 1142 double mxx, double mxy, double mxz, double mxt, 1143 double myx, double myy, double myz, double myt, 1144 double mzx, double mzy, double mzz, double mzt); 1145 }