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