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 com.sun.javafx.css.converters.BooleanConverter; 35 import com.sun.javafx.css.converters.EnumConverter; 36 import com.sun.javafx.css.converters.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.input.PickResultChooser; 43 import com.sun.javafx.tk.TKPulseListener; 44 import com.sun.javafx.tk.Toolkit; 45 import java.util.ArrayList; 46 import java.util.Collections; 47 import java.util.List; 48 import javafx.beans.property.*; 49 import javafx.beans.value.ChangeListener; 50 import javafx.beans.value.ObservableValue; 51 import javafx.collections.ObservableList; 52 import javafx.css.Styleable; 53 import javafx.geometry.Bounds; 54 import javafx.scene.Node; 55 import javafx.scene.Parent; 56 import javafx.scene.Scene; 57 import javafx.scene.text.FontSmoothingType; 58 59 /** 60 * {@code WebView} is a {@link javafx.scene.Node} that manages a 61 * {@link WebEngine} and displays its content. The associated {@code WebEngine} 62 * is created automatically at construction time and cannot be changed 63 * afterwards. {@code WebView} handles mouse and some keyboard events, and 64 * manages scrolling automatically, so there's no need to put it into a 65 * {@code ScrollPane}. 66 * 67 * <p>{@code WebView} objects must be created and accessed solely from the 68 * FX thread. 69 * @since JavaFX 2.0 70 */ 71 final public class WebView extends Parent { 72 73 private static final boolean DEFAULT_CONTEXT_MENU_ENABLED = true; 74 private static final FontSmoothingType DEFAULT_FONT_SMOOTHING_TYPE = FontSmoothingType.LCD; 75 private static final double DEFAULT_ZOOM = 1.0; 76 private static final double DEFAULT_FONT_SCALE = 1.0; 77 private static final double DEFAULT_MIN_WIDTH = 0; 78 private static final double DEFAULT_MIN_HEIGHT = 0; 79 private static final double DEFAULT_PREF_WIDTH = 800; 80 private static final double DEFAULT_PREF_HEIGHT = 600; 81 private static final double DEFAULT_MAX_WIDTH = Double.MAX_VALUE; 82 private static final double DEFAULT_MAX_HEIGHT = Double.MAX_VALUE; 83 84 private final WebEngine engine; 85 // pointer to native WebViewImpl 86 private final long handle; 87 88 /** 89 * The stage pulse listener registered with the toolkit. 90 * This field guarantees that the listener will exist throughout 91 * the whole lifetime of the WebView node. This field is necessary 92 * because the toolkit references its stage pulse listeners weakly. 93 */ 94 private final TKPulseListener stagePulseListener; 95 96 /** 97 * Returns the {@code WebEngine} object. 98 */ 99 public final WebEngine getEngine() { 100 return engine; 101 } 102 103 private final ReadOnlyDoubleWrapper width = new ReadOnlyDoubleWrapper(this, "width"); 104 105 /** 106 * Returns width of this {@code WebView}. 107 */ 108 public final double getWidth() { 109 return width.get(); 110 } 111 112 /** 113 * Width of this {@code WebView}. 114 */ 115 public ReadOnlyDoubleProperty widthProperty() { 116 return width.getReadOnlyProperty(); 117 } 118 119 private final ReadOnlyDoubleWrapper height = new ReadOnlyDoubleWrapper(this, "height"); 120 121 /** 122 * Returns height of this {@code WebView}. 123 */ 124 public final double getHeight() { 125 return height.get(); 126 } 127 128 /** 129 * Height of this {@code WebView}. 130 */ 131 public ReadOnlyDoubleProperty heightProperty() { 132 return height.getReadOnlyProperty(); 133 } 134 135 /** 136 * Zoom factor applied to the whole page contents. 137 * 138 * @defaultValue 1.0 139 */ 140 private DoubleProperty zoom; 141 142 /** 143 * Sets current zoom factor applied to the whole page contents. 144 * @param value zoom factor to be set 145 * @see #zoomProperty() 146 * @see #getZoom() 147 * @since JavaFX 8.0 148 */ 149 public final void setZoom(double value) { 150 WebEngine.checkThread(); 151 zoomProperty().set(value); 152 } 153 154 /** 155 * Returns current zoom factor applied to the whole page contents. 156 * @return current zoom factor 157 * @see #zoomProperty() 158 * @see #setZoom(double value) 159 * @since JavaFX 8.0 160 */ 161 public final double getZoom() { 162 return (this.zoom != null) 163 ? this.zoom.get() 164 : DEFAULT_ZOOM; 165 } 166 167 /** 168 * Returns zoom property object. 169 * @return zoom property object 170 * @see #getZoom() 171 * @see #setZoom(double value) 172 * @since JavaFX 8.0 173 */ 174 public final DoubleProperty zoomProperty() { 175 if (zoom == null) { 176 zoom = new StyleableDoubleProperty(DEFAULT_ZOOM) { 177 @Override public void invalidated() { 178 Toolkit.getToolkit().checkFxUserThread(); 179 } 180 181 @Override public CssMetaData<WebView, Number> getCssMetaData() { 182 return StyleableProperties.ZOOM; 183 } 184 @Override public Object getBean() { 185 return WebView.this; 186 } 187 @Override public String getName() { 188 return "zoom"; 189 } 190 }; 191 } 192 return zoom; 193 } 194 195 /** 196 * Specifies scale factor applied to font. This setting affects 197 * text content but not images and fixed size elements. 198 * 199 * @defaultValue 1.0 200 */ 201 private DoubleProperty fontScale; 202 203 public final void setFontScale(double value) { 204 WebEngine.checkThread(); 205 fontScaleProperty().set(value); 206 } 207 208 public final double getFontScale() { 209 return (this.fontScale != null) 210 ? this.fontScale.get() 211 : DEFAULT_FONT_SCALE; 212 } 213 214 public DoubleProperty fontScaleProperty() { 215 if (fontScale == null) { 216 fontScale = new StyleableDoubleProperty(DEFAULT_FONT_SCALE) { 217 @Override public void invalidated() { 218 Toolkit.getToolkit().checkFxUserThread(); 219 } 220 @Override public CssMetaData<WebView, Number> getCssMetaData() { 221 return StyleableProperties.FONT_SCALE; 222 } 223 @Override public Object getBean() { 224 return WebView.this; 225 } 226 @Override public String getName() { 227 return "fontScale"; 228 } 229 }; 230 } 231 return fontScale; 232 } 233 234 /** 235 * Creates a {@code WebView} object. 236 */ 237 public WebView() { 238 long[] nativeHandle = new long[1]; 239 _initWebView(nativeHandle); 240 getStyleClass().add("web-view"); 241 handle = nativeHandle[0]; 242 engine = new WebEngine(); 243 engine.setView(this); 244 245 stagePulseListener = () -> { 246 handleStagePulse(); 247 }; 248 focusedProperty().addListener((ov, t, t1) -> { 249 }); 250 Toolkit.getToolkit().addStageTkPulseListener(stagePulseListener); 251 252 final ChangeListener<Bounds> chListener = new ChangeListener<Bounds>() { 253 254 @Override 255 public void changed(ObservableValue<? extends Bounds> observable, Bounds oldValue, Bounds newValue) { 256 WebView.this.impl_transformsChanged(); 257 } 258 }; 259 260 parentProperty().addListener(new ChangeListener<Parent>(){ 261 262 @Override 263 public void changed(ObservableValue<? extends Parent> observable, Parent oldValue, Parent newValue) { 264 if (oldValue != null && newValue == null) { 265 // webview has been removed from scene 266 _removeWebView(handle); 267 } 268 269 if (oldValue != null) { 270 do { 271 oldValue.boundsInParentProperty().removeListener(chListener); 272 oldValue = oldValue.getParent(); 273 } while (oldValue != null); 274 } 275 276 if (newValue != null) { 277 do { 278 final Node n = newValue; 279 newValue.boundsInParentProperty().addListener(chListener); 280 newValue = newValue.getParent(); 281 } while (newValue != null); 282 } 283 } 284 285 }); 286 287 layoutBoundsProperty().addListener(new ChangeListener<Bounds>() { 288 289 @Override 290 public void changed(ObservableValue<? extends Bounds> observable, Bounds oldValue, Bounds newValue) { 291 Affine3D trans = calculateNodeToSceneTransform(WebView.this); 292 _setTransform(handle, 293 trans.getMxx(), trans.getMxy(), trans.getMxz(), trans.getMxt(), 294 trans.getMyx(), trans.getMyy(), trans.getMyz(), trans.getMyt(), 295 trans.getMzx(), trans.getMzy(), trans.getMzz(), trans.getMzt()); 296 297 } 298 299 }); 300 301 impl_treeVisibleProperty().addListener(new ChangeListener<Boolean>() { 302 303 @Override 304 public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) { 305 _setVisible(handle, newValue); 306 } 307 }); 308 } 309 // Resizing support. Allows arbitrary growing and shrinking. 310 // Designed after javafx.scene.control.Control 311 312 @Override public boolean isResizable() { 313 return true; 314 } 315 316 @Override public void resize(double width, double height) { 317 this.width.set(width); 318 this.height.set(height); 319 impl_markDirty(DirtyBits.NODE_GEOMETRY); 320 impl_geomChanged(); 321 _setWidth(handle, width); 322 _setHeight(handle, height); 323 } 324 325 /** 326 * Called during layout to determine the minimum width for this node. 327 * 328 * @return the minimum width that this node should be resized to during layout 329 */ 330 @Override public final double minWidth(double height) { 331 return getMinWidth(); 332 } 333 334 /** 335 * Called during layout to determine the minimum height for this node. 336 * 337 * @return the minimum height that this node should be resized to during layout 338 */ 339 @Override public final double minHeight(double width) { 340 return getMinHeight(); 341 } 342 343 344 /** 345 * Called during layout to determine the preferred width for this node. 346 * 347 * @return the preferred width that this node should be resized to during layout 348 */ 349 @Override public final double prefWidth(double height) { 350 return getPrefWidth(); 351 } 352 353 /** 354 * Called during layout to determine the preferred height for this node. 355 * 356 * @return the preferred height that this node should be resized to during layout 357 */ 358 @Override public final double prefHeight(double width) { 359 return getPrefHeight(); 360 } 361 /** 362 * Called during layout to determine the maximum width for this node. 363 * 364 * @return the maximum width that this node should be resized to during layout 365 */ 366 @Override public final double maxWidth(double height) { 367 return getMaxWidth(); 368 } 369 370 /** 371 * Called during layout to determine the maximum height for this node. 372 * 373 * @return the maximum height that this node should be resized to during layout 374 */ 375 @Override public final double maxHeight(double width) { 376 return getMaxHeight(); 377 } 378 379 /** 380 * Minimum width property. 381 */ 382 public DoubleProperty minWidthProperty() { 383 if (minWidth == null) { 384 minWidth = new StyleableDoubleProperty(DEFAULT_MIN_WIDTH) { 385 @Override 386 public void invalidated() { 387 if (getParent() != null) { 388 getParent().requestLayout(); 389 } 390 } 391 @Override 392 public CssMetaData<WebView, Number> getCssMetaData() { 393 return StyleableProperties.MIN_WIDTH; 394 } 395 @Override 396 public Object getBean() { 397 return WebView.this; 398 } 399 @Override 400 public String getName() { 401 return "minWidth"; 402 } 403 }; 404 } 405 return minWidth; 406 } 407 private DoubleProperty minWidth; 408 409 /** 410 * Sets minimum width. 411 */ 412 public final void setMinWidth(double value) { 413 minWidthProperty().set(value); 414 _setWidth(handle, value); 415 } 416 417 /** 418 * Returns minimum width. 419 */ 420 public final double getMinWidth() { 421 return (this.minWidth != null) 422 ? this.minWidth.get() 423 : DEFAULT_MIN_WIDTH; 424 } 425 426 /** 427 * Minimum height property. 428 */ 429 public DoubleProperty minHeightProperty() { 430 if (minHeight == null) { 431 minHeight = new StyleableDoubleProperty(DEFAULT_MIN_HEIGHT) { 432 @Override 433 public void invalidated() { 434 if (getParent() != null) { 435 getParent().requestLayout(); 436 } 437 } 438 @Override 439 public CssMetaData<WebView, Number> getCssMetaData() { 440 return StyleableProperties.MIN_HEIGHT; 441 } 442 @Override 443 public Object getBean() { 444 return WebView.this; 445 } 446 @Override 447 public String getName() { 448 return "minHeight"; 449 } 450 }; 451 } 452 return minHeight; 453 } 454 private DoubleProperty minHeight; 455 456 /** 457 * Sets minimum height. 458 */ 459 public final void setMinHeight(double value) { 460 minHeightProperty().set(value); 461 _setHeight(handle, value); 462 } 463 464 /** 465 * Sets minimum height. 466 */ 467 public final double getMinHeight() { 468 return (this.minHeight != null) 469 ? this.minHeight.get() 470 : DEFAULT_MIN_HEIGHT; 471 } 472 473 /** 474 * Convenience method for setting minimum width and height. 475 */ 476 public void setMinSize(double minWidth, double minHeight) { 477 setMinWidth(minWidth); 478 setMinHeight(minHeight); 479 _setWidth(handle, minWidth); 480 _setHeight(handle, minHeight); 481 } 482 483 /** 484 * Preferred width property. 485 */ 486 public DoubleProperty prefWidthProperty() { 487 if (prefWidth == null) { 488 prefWidth = new StyleableDoubleProperty(DEFAULT_PREF_WIDTH) { 489 @Override 490 public void invalidated() { 491 if (getParent() != null) { 492 getParent().requestLayout(); 493 } 494 } 495 @Override 496 public CssMetaData<WebView, Number> getCssMetaData() { 497 return StyleableProperties.PREF_WIDTH; 498 } 499 @Override 500 public Object getBean() { 501 return WebView.this; 502 } 503 @Override 504 public String getName() { 505 return "prefWidth"; 506 } 507 }; 508 } 509 return prefWidth; 510 } 511 private DoubleProperty prefWidth; 512 513 /** 514 * Sets preferred width. 515 */ 516 public final void setPrefWidth(double value) { 517 prefWidthProperty().set(value); 518 _setWidth(handle, value); 519 } 520 521 /** 522 * Returns preferred width. 523 */ 524 public final double getPrefWidth() { 525 return (this.prefWidth != null) 526 ? this.prefWidth.get() 527 : DEFAULT_PREF_WIDTH; 528 } 529 530 /** 531 * Preferred height property. 532 */ 533 public DoubleProperty prefHeightProperty() { 534 if (prefHeight == null) { 535 prefHeight = new StyleableDoubleProperty(DEFAULT_PREF_HEIGHT) { 536 @Override 537 public void invalidated() { 538 if (getParent() != null) { 539 getParent().requestLayout(); 540 } 541 } 542 @Override 543 public CssMetaData<WebView, Number> getCssMetaData() { 544 return StyleableProperties.PREF_HEIGHT; 545 } 546 @Override 547 public Object getBean() { 548 return WebView.this; 549 } 550 @Override 551 public String getName() { 552 return "prefHeight"; 553 } 554 }; 555 } 556 return prefHeight; 557 } 558 private DoubleProperty prefHeight; 559 560 /** 561 * Sets preferred height. 562 */ 563 public final void setPrefHeight(double value) { 564 prefHeightProperty().set(value); 565 _setHeight(handle, value); 566 } 567 568 /** 569 * Returns preferred height. 570 */ 571 public final double getPrefHeight() { 572 return (this.prefHeight != null) 573 ? this.prefHeight.get() 574 : DEFAULT_PREF_HEIGHT; 575 } 576 577 /** 578 * Convenience method for setting preferred width and height. 579 */ 580 public void setPrefSize(double prefWidth, double prefHeight) { 581 setPrefWidth(prefWidth); 582 setPrefHeight(prefHeight); 583 _setWidth(handle, prefWidth); 584 _setHeight(handle, prefHeight); 585 } 586 587 /** 588 * Maximum width property. 589 */ 590 public DoubleProperty maxWidthProperty() { 591 if (maxWidth == null) { 592 maxWidth = new StyleableDoubleProperty(DEFAULT_MAX_WIDTH) { 593 @Override 594 public void invalidated() { 595 if (getParent() != null) { 596 getParent().requestLayout(); 597 } 598 } 599 @Override 600 public CssMetaData<WebView, Number> getCssMetaData() { 601 return StyleableProperties.MAX_WIDTH; 602 } 603 @Override 604 public Object getBean() { 605 return WebView.this; 606 } 607 @Override 608 public String getName() { 609 return "maxWidth"; 610 } 611 }; 612 } 613 return maxWidth; 614 } 615 private DoubleProperty maxWidth; 616 617 /** 618 * Sets maximum width. 619 */ 620 public final void setMaxWidth(double value) { 621 maxWidthProperty().set(value); 622 _setWidth(handle, value); 623 } 624 625 /** 626 * Returns maximum width. 627 */ 628 public final double getMaxWidth() { 629 return (this.maxWidth != null) 630 ? this.maxWidth.get() 631 : DEFAULT_MAX_WIDTH; 632 } 633 634 /** 635 * Maximum height property. 636 */ 637 public DoubleProperty maxHeightProperty() { 638 if (maxHeight == null) { 639 maxHeight = new StyleableDoubleProperty(DEFAULT_MAX_HEIGHT) { 640 @Override 641 public void invalidated() { 642 if (getParent() != null) { 643 getParent().requestLayout(); 644 } 645 } 646 @Override 647 public CssMetaData<WebView, Number> getCssMetaData() { 648 return StyleableProperties.MAX_HEIGHT; 649 } 650 @Override 651 public Object getBean() { 652 return WebView.this; 653 } 654 @Override 655 public String getName() { 656 return "maxHeight"; 657 } 658 }; 659 } 660 return maxHeight; 661 } 662 private DoubleProperty maxHeight; 663 664 /** 665 * Sets maximum height. 666 */ 667 public final void setMaxHeight(double value) { 668 maxHeightProperty().set(value); 669 _setHeight(handle, value); 670 } 671 672 /** 673 * Returns maximum height. 674 */ 675 public final double getMaxHeight() { 676 return (this.maxHeight != null) 677 ? this.maxHeight.get() 678 : DEFAULT_MAX_HEIGHT; 679 } 680 681 /** 682 * Convenience method for setting maximum width and height. 683 */ 684 public void setMaxSize(double maxWidth, double maxHeight) { 685 setMaxWidth(maxWidth); 686 setMaxHeight(maxHeight); 687 _setWidth(handle, maxWidth); 688 _setHeight(handle, maxHeight); 689 } 690 691 692 /** 693 * Specifies a requested font smoothing type : gray or LCD. 694 * 695 * The width of the bounding box is defined by the widest row. 696 * 697 * Note: LCD mode doesn't apply in numerous cases, such as various 698 * compositing modes, where effects are applied and very large glyphs. 699 * 700 * @defaultValue FontSmoothingType.LCD 701 * @since JavaFX 2.2 702 */ 703 private ObjectProperty<FontSmoothingType> fontSmoothingType; 704 705 public final void setFontSmoothingType(FontSmoothingType value) { 706 fontSmoothingTypeProperty().set(value); 707 } 708 709 public final FontSmoothingType getFontSmoothingType() { 710 return (this.fontSmoothingType != null) 711 ? this.fontSmoothingType.get() 712 : DEFAULT_FONT_SMOOTHING_TYPE; 713 } 714 715 public final ObjectProperty<FontSmoothingType> fontSmoothingTypeProperty() { 716 if (this.fontSmoothingType == null) { 717 this.fontSmoothingType = new StyleableObjectProperty<FontSmoothingType>(DEFAULT_FONT_SMOOTHING_TYPE) { 718 @Override 719 public void invalidated() { 720 Toolkit.getToolkit().checkFxUserThread(); 721 } 722 @Override 723 public CssMetaData<WebView, FontSmoothingType> getCssMetaData() { 724 return StyleableProperties.FONT_SMOOTHING_TYPE; 725 } 726 @Override 727 public Object getBean() { 728 return WebView.this; 729 } 730 @Override 731 public String getName() { 732 return "fontSmoothingType"; 733 } 734 }; 735 } 736 return this.fontSmoothingType; 737 } 738 739 /** 740 * Specifies whether context menu is enabled. 741 * 742 * @defaultValue true 743 * @since JavaFX 2.2 744 */ 745 private BooleanProperty contextMenuEnabled; 746 747 public final void setContextMenuEnabled(boolean value) { 748 contextMenuEnabledProperty().set(value); 749 } 750 751 public final boolean isContextMenuEnabled() { 752 return contextMenuEnabled == null 753 ? DEFAULT_CONTEXT_MENU_ENABLED 754 : contextMenuEnabled.get(); 755 } 756 757 public final BooleanProperty contextMenuEnabledProperty() { 758 if (contextMenuEnabled == null) { 759 contextMenuEnabled = new StyleableBooleanProperty(DEFAULT_CONTEXT_MENU_ENABLED) { 760 @Override public void invalidated() { 761 Toolkit.getToolkit().checkFxUserThread(); 762 } 763 764 @Override public CssMetaData<WebView, Boolean> getCssMetaData() { 765 return StyleableProperties.CONTEXT_MENU_ENABLED; 766 } 767 768 @Override public Object getBean() { 769 return WebView.this; 770 } 771 772 @Override public String getName() { 773 return "contextMenuEnabled"; 774 } 775 }; 776 } 777 return contextMenuEnabled; 778 } 779 780 /** 781 * Super-lazy instantiation pattern from Bill Pugh. 782 */ 783 private static final class StyleableProperties { 784 785 private static final CssMetaData<WebView, Boolean> CONTEXT_MENU_ENABLED 786 = new CssMetaData<WebView, Boolean>( 787 "-fx-context-menu-enabled", 788 BooleanConverter.getInstance(), 789 DEFAULT_CONTEXT_MENU_ENABLED) 790 { 791 @Override public boolean isSettable(WebView view) { 792 return view.contextMenuEnabled == null || !view.contextMenuEnabled.isBound(); 793 } 794 @Override public StyleableProperty<Boolean> getStyleableProperty(WebView view) { 795 return (StyleableProperty<Boolean>)view.contextMenuEnabledProperty(); 796 } 797 }; 798 799 private static final CssMetaData<WebView, FontSmoothingType> FONT_SMOOTHING_TYPE 800 = new CssMetaData<WebView, FontSmoothingType>( 801 "-fx-font-smoothing-type", 802 new EnumConverter<FontSmoothingType>(FontSmoothingType.class), 803 DEFAULT_FONT_SMOOTHING_TYPE) { 804 @Override 805 public boolean isSettable(WebView view) { 806 return view.fontSmoothingType == null || !view.fontSmoothingType.isBound(); 807 } 808 @Override 809 public StyleableProperty<FontSmoothingType> getStyleableProperty(WebView view) { 810 return (StyleableProperty<FontSmoothingType>)view.fontSmoothingTypeProperty(); 811 } 812 }; 813 814 private static final CssMetaData<WebView, Number> ZOOM 815 = new CssMetaData<WebView, Number>( 816 "-fx-zoom", 817 SizeConverter.getInstance(), 818 DEFAULT_ZOOM) { 819 @Override public boolean isSettable(WebView view) { 820 return view.zoom == null || !view.zoom.isBound(); 821 } 822 @Override public StyleableProperty<Number> getStyleableProperty(WebView view) { 823 return (StyleableProperty<Number>)view.zoomProperty(); 824 } 825 }; 826 827 private static final CssMetaData<WebView, Number> FONT_SCALE 828 = new CssMetaData<WebView, Number>( 829 "-fx-font-scale", 830 SizeConverter.getInstance(), 831 DEFAULT_FONT_SCALE) { 832 @Override 833 public boolean isSettable(WebView view) { 834 return view.fontScale == null || !view.fontScale.isBound(); 835 } 836 @Override 837 public StyleableProperty<Number> getStyleableProperty(WebView view) { 838 return (StyleableProperty<Number>)view.fontScaleProperty(); 839 } 840 }; 841 842 private static final CssMetaData<WebView, Number> MIN_WIDTH 843 = new CssMetaData<WebView, Number>( 844 "-fx-min-width", 845 SizeConverter.getInstance(), 846 DEFAULT_MIN_WIDTH) { 847 @Override 848 public boolean isSettable(WebView view) { 849 return view.minWidth == null || !view.minWidth.isBound(); 850 } 851 @Override 852 public StyleableProperty<Number> getStyleableProperty(WebView view) { 853 return (StyleableProperty<Number>)view.minWidthProperty(); 854 } 855 }; 856 857 private static final CssMetaData<WebView, Number> MIN_HEIGHT 858 = new CssMetaData<WebView, Number>( 859 "-fx-min-height", 860 SizeConverter.getInstance(), 861 DEFAULT_MIN_HEIGHT) { 862 @Override 863 public boolean isSettable(WebView view) { 864 return view.minHeight == null || !view.minHeight.isBound(); 865 } 866 @Override 867 public StyleableProperty<Number> getStyleableProperty(WebView view) { 868 return (StyleableProperty<Number>)view.minHeightProperty(); 869 } 870 }; 871 872 private static final CssMetaData<WebView, Number> MAX_WIDTH 873 = new CssMetaData<WebView, Number>( 874 "-fx-max-width", 875 SizeConverter.getInstance(), 876 DEFAULT_MAX_WIDTH) { 877 @Override 878 public boolean isSettable(WebView view) { 879 return view.maxWidth == null || !view.maxWidth.isBound(); 880 } 881 @Override 882 public StyleableProperty<Number> getStyleableProperty(WebView view) { 883 return (StyleableProperty<Number>)view.maxWidthProperty(); 884 } 885 }; 886 887 private static final CssMetaData<WebView, Number> MAX_HEIGHT 888 = new CssMetaData<WebView, Number>( 889 "-fx-max-height", 890 SizeConverter.getInstance(), 891 DEFAULT_MAX_HEIGHT) { 892 @Override 893 public boolean isSettable(WebView view) { 894 return view.maxHeight == null || !view.maxHeight.isBound(); 895 } 896 @Override 897 public StyleableProperty<Number> getStyleableProperty(WebView view) { 898 return (StyleableProperty<Number>)view.maxHeightProperty(); 899 } 900 }; 901 902 private static final CssMetaData<WebView, Number> PREF_WIDTH 903 = new CssMetaData<WebView, Number>( 904 "-fx-pref-width", 905 SizeConverter.getInstance(), 906 DEFAULT_PREF_WIDTH) { 907 @Override 908 public boolean isSettable(WebView view) { 909 return view.prefWidth == null || !view.prefWidth.isBound(); 910 } 911 @Override 912 public StyleableProperty<Number> getStyleableProperty(WebView view) { 913 return (StyleableProperty<Number>)view.prefWidthProperty(); 914 } 915 }; 916 917 private static final CssMetaData<WebView, Number> PREF_HEIGHT 918 = new CssMetaData<WebView, Number>( 919 "-fx-pref-height", 920 SizeConverter.getInstance(), 921 DEFAULT_PREF_HEIGHT) { 922 @Override 923 public boolean isSettable(WebView view) { 924 return view.prefHeight == null || !view.prefHeight.isBound(); 925 } 926 @Override 927 public StyleableProperty<Number> getStyleableProperty(WebView view) { 928 return (StyleableProperty<Number>)view.prefHeightProperty(); 929 } 930 }; 931 932 private static final List<CssMetaData<? extends Styleable, ?>> STYLEABLES; 933 934 static { 935 List<CssMetaData<? extends Styleable, ?>> styleables 936 = new ArrayList<CssMetaData<? extends Styleable, ?>>(Parent.getClassCssMetaData()); 937 styleables.add(CONTEXT_MENU_ENABLED); 938 styleables.add(FONT_SMOOTHING_TYPE); 939 styleables.add(ZOOM); 940 styleables.add(FONT_SCALE); 941 styleables.add(MIN_WIDTH); 942 styleables.add(PREF_WIDTH); 943 styleables.add(MAX_WIDTH); 944 styleables.add(MIN_HEIGHT); 945 styleables.add(PREF_HEIGHT); 946 styleables.add(MAX_HEIGHT); 947 STYLEABLES = Collections.unmodifiableList(styleables); 948 } 949 } 950 951 /** 952 * @return The CssMetaData associated with this class, which may include the 953 * CssMetaData of its super classes. 954 * @since JavaFX 8.0 955 */ 956 public static List<CssMetaData<? extends Styleable, ?>> getClassCssMetaData() { 957 return StyleableProperties.STYLEABLES; 958 } 959 960 /** 961 * {@inheritDoc} 962 * @since JavaFX 8.0 963 */ 964 @Override 965 public List<CssMetaData<? extends Styleable, ?>> getCssMetaData() { 966 return getClassCssMetaData(); 967 } 968 969 // event handling 970 971 private void handleStagePulse() { 972 // The stage pulse occurs before the scene pulse. 973 // Here the page content is updated before CSS/Layout/Sync pass 974 // is initiated by the scene pulse. The update may 975 // change the WebView children and, if so, the children should be 976 // processed right away during the scene pulse. 977 978 // The WebView node does not render its pending render queues 979 // while it is invisible. Therefore, we should not schedule new 980 // render queues while the WebView is invisible to prevent 981 // the list of render queues from growing infinitely. 982 // Also, if and when the WebView becomes invisible, the currently 983 // pending render queues, if any, become obsolete and should be 984 // discarded. 985 986 boolean reallyVisible = impl_isTreeVisible() 987 && getScene() != null 988 && getScene().getWindow() != null 989 && getScene().getWindow().isShowing(); 990 991 if (reallyVisible) { 992 if (impl_isDirty(DirtyBits.WEBVIEW_VIEW)) { 993 Scene.impl_setAllowPGAccess(true); 994 //getPGWebView().update(); // creates new render queues 995 Scene.impl_setAllowPGAccess(false); 996 } 997 } else { 998 _setVisible(handle, false); 999 } 1000 } 1001 1002 /** 1003 * @treatAsPrivate implementation detail 1004 * @deprecated This is an internal API that is not intended for use and will be removed in the next version 1005 */ 1006 @Deprecated 1007 @Override protected void impl_pickNodeLocal(PickRay pickRay, PickResultChooser result) { 1008 impl_intersects(pickRay, result); 1009 } 1010 1011 @Override protected ObservableList<Node> getChildren() { 1012 return super.getChildren(); 1013 } 1014 1015 // Node stuff 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 public BaseBounds impl_computeGeomBounds(BaseBounds bounds, BaseTransform tx) { 1023 bounds.deriveWithNewBounds(0, 0, 0, (float) getWidth(), (float)getHeight(), 0); 1024 tx.transform(bounds, bounds); 1025 return bounds; 1026 } 1027 1028 /** 1029 * @treatAsPrivate implementation detail 1030 * @deprecated This is an internal API that is not intended for use and will be removed in the next version 1031 */ 1032 @Deprecated 1033 @Override protected boolean impl_computeContains(double localX, double localY) { 1034 // Note: Local bounds contain test is already done by the caller. (Node.contains()). 1035 return true; 1036 } 1037 1038 /** 1039 * @treatAsPrivate implementation detail 1040 * @deprecated This is an internal API that is not intended for use and will be removed in the next version 1041 */ 1042 @Deprecated 1043 @Override public void impl_updatePeer() { 1044 super.impl_updatePeer(); 1045 //PGWebView peer = getPGWebView(); 1046 1047 if (impl_isDirty(DirtyBits.NODE_GEOMETRY)) { 1048 //peer.resize((float)getWidth(), (float)getHeight()); 1049 } 1050 if (impl_isDirty(DirtyBits.WEBVIEW_VIEW)) { 1051 //peer.requestRender(); 1052 } 1053 } 1054 1055 private static Affine3D calculateNodeToSceneTransform(Node node) { 1056 final Affine3D transform = new Affine3D(); 1057 do { 1058 transform.preConcatenate(node.impl_getLeafTransform()); 1059 node = node.getParent(); 1060 } while (node != null); 1061 1062 return transform; 1063 } 1064 1065 @Deprecated 1066 @Override public void impl_transformsChanged() { 1067 super.impl_transformsChanged(); 1068 1069 Affine3D trans = calculateNodeToSceneTransform(this); 1070 _setTransform(handle, 1071 trans.getMxx(), trans.getMxy(), trans.getMxz(), trans.getMxt(), 1072 trans.getMyx(), trans.getMyy(), trans.getMyz(), trans.getMyt(), 1073 trans.getMzx(), trans.getMzy(), trans.getMzz(), trans.getMzt()); 1074 } 1075 1076 long getNativeHandle() { 1077 return handle; 1078 } 1079 1080 1081 // native callbacks 1082 private void notifyLoadStarted() { 1083 engine.notifyLoadStarted(); 1084 } 1085 private void notifyLoadFinished(String loc, String content) { 1086 engine.notifyLoadFinished(loc, content); 1087 } 1088 private void notifyLoadFailed() { 1089 engine.notifyLoadFailed(); 1090 } 1091 private void notifyJavaCall(String arg) { 1092 engine.notifyJavaCall(arg); 1093 } 1094 1095 1096 /* Inits native WebView and returns its pointer in the given array */ 1097 private native void _initWebView(long[] nativeHandle); 1098 1099 /* Sets width of the native WebView */ 1100 private native void _setWidth(long handle, double w); 1101 1102 /* Sets height of the native WebView */ 1103 private native void _setHeight(long handle, double h); 1104 1105 /* Sets visibility of the native WebView */ 1106 private native void _setVisible(long handle, boolean v); 1107 1108 /* Removes the native WebView from scene */ 1109 private native void _removeWebView(long handle); 1110 1111 /* Applies transform on the native WebView */ 1112 private native void _setTransform(long handle, 1113 double mxx, double mxy, double mxz, double mxt, 1114 double myx, double myy, double myz, double myt, 1115 double mzx, double mzy, double mzz, double mzt); 1116 }