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