1 /* 2 * Copyright (c) 2011, 2014, 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 com.sun.webkit; 27 28 import com.sun.glass.utils.NativeLibLoader; 29 import com.sun.webkit.event.WCFocusEvent; 30 import com.sun.webkit.event.WCInputMethodEvent; 31 import com.sun.webkit.event.WCKeyEvent; 32 import com.sun.webkit.event.WCMouseEvent; 33 import com.sun.webkit.event.WCMouseWheelEvent; 34 import com.sun.webkit.graphics.*; 35 import com.sun.webkit.network.CookieManager; 36 import static com.sun.webkit.network.URLs.newURL; 37 import java.net.CookieHandler; 38 import java.net.MalformedURLException; 39 import java.net.URL; 40 import java.nio.ByteBuffer; 41 import java.nio.ByteOrder; 42 import java.security.AccessControlContext; 43 import java.security.AccessController; 44 import java.security.PrivilegedAction; 45 import java.util.ArrayList; 46 import java.util.HashMap; 47 import java.util.HashSet; 48 import java.util.Iterator; 49 import java.util.LinkedList; 50 import java.util.List; 51 import java.util.Map; 52 import java.util.Queue; 53 import java.util.Set; 54 import java.util.concurrent.CountDownLatch; 55 import java.util.concurrent.ExecutionException; 56 import java.util.concurrent.FutureTask; 57 import java.util.concurrent.locks.ReentrantLock; 58 import java.util.logging.Level; 59 import java.util.logging.Logger; 60 import netscape.javascript.JSException; 61 import org.w3c.dom.Document; 62 import org.w3c.dom.Element; 63 64 /** 65 * This class provides two-side interaction between native webkit core and 66 * number of clients representing different subsystems of the WebPane component 67 * such as 68 * <ul> 69 * <li>webpage rendering({@link WebPageClient}) 70 * <li>creating/disposing web frames ({@link WebFrameClient}) 71 * <li>creating new windows, alert dialogues ... ({@link UIClient}) 72 * <li>handling menus {@link MenuClient} 73 * <li>supporting policy checking {@link PolicyClient} 74 * </ul> 75 */ 76 77 public final class WebPage { 78 private final static Logger log = Logger.getLogger(WebPage.class.getName()); 79 private final static Logger paintLog = Logger.getLogger(WebPage.class.getName() + ".paint"); 80 81 private static final int MAX_FRAME_QUEUE_SIZE = 10; 82 83 // Native WebPage* pointer 84 private long pPage = 0; 85 86 // A flag to distinguish whether the web page hasn't been created 87 // yet or had been already disposed - in both cases pPage is 0 88 private boolean isDisposed = false; 89 90 private int width, height; 91 92 private int fontSmoothingType; 93 94 private final WCFrameView hostWindow; 95 96 // List of created frames 97 private final Set<Long> frames = new HashSet<Long>(); 98 99 // The access control context associated with this object 100 private final AccessControlContext accessControlContext; 101 102 // Maps load request identifiers to URLs 103 private final Map<Integer, String> requestURLs = 104 new HashMap<Integer, String>(); 105 106 // There may be several RESOURCE_STARTED events for a resource, 107 // so this map is used to convert them to RESOURCE_REDIRECTED 108 private final Set<Integer> requestStarted = new HashSet<Integer>(); 109 110 // PAGE_LOCK is used to synchronize the following operations b/w Event & Main threads: 111 // - rendering of the page (Main thread) 112 // - native calls & other manipulations on the page (Event & Main threads) 113 // - timer invocations (Event thread) 114 private static final ReentrantLock PAGE_LOCK = new ReentrantLock(); 115 116 // The queue of render frames awaiting rendering. 117 // Access to this object is synchronized on its monitor. 118 // Accessed on: Event thread and Main thread. 119 private final Queue<RenderFrame> frameQueue = new LinkedList<RenderFrame>(); 120 121 // The current frame being generated. 122 // Accessed on: Event thread only. 123 private RenderFrame currentFrame = new RenderFrame(); 124 125 static { 126 AccessController.doPrivileged((PrivilegedAction<Void>) () -> { 127 NativeLibLoader.loadLibrary("jfxwebkit"); 128 log.finer("jfxwebkit loaded"); 129 130 if (CookieHandler.getDefault() == null) { 131 boolean setDefault = Boolean.valueOf(System.getProperty( 132 "com.sun.webkit.setDefaultCookieHandler", 133 "true")); 134 if (setDefault) { 135 CookieHandler.setDefault(new CookieManager()); 136 } 137 } 138 return null; 139 }); 140 } 141 142 public WebPage(WebPageClient pageClient, 143 UIClient uiClient, 144 PolicyClient policyClient, 145 InspectorClient inspectorClient, 146 ThemeClient themeClient, 147 boolean editable) 148 { 149 Invoker.getInvoker().checkEventThread(); 150 151 this.pageClient = pageClient; 152 this.uiClient = uiClient; 153 this.policyClient = policyClient; 154 this.inspectorClient = inspectorClient; 155 if (themeClient != null) { 156 this.renderTheme = themeClient.createRenderTheme(); 157 this.scrollbarTheme = themeClient.createScrollBarTheme(); 158 } else { 159 this.renderTheme = null; 160 this.scrollbarTheme = null; 161 } 162 163 accessControlContext = AccessController.getContext(); 164 165 hostWindow = new WCFrameView(this); 166 pPage = twkCreatePage(editable); 167 168 twkInit(pPage, false); 169 170 if (pageClient != null && pageClient.isBackBufferSupported()) { 171 backbuffer = pageClient.createBackBuffer(); 172 backbuffer.ref(); 173 } 174 } 175 176 long getPage() { 177 return pPage; 178 } 179 180 // Called from the native code 181 private WCWidget getHostWindow() { 182 return hostWindow; 183 } 184 185 /** 186 * Returns the access control context associated with this object. 187 * May be called on any thread. 188 * @return the access control context associated with this object 189 */ 190 public AccessControlContext getAccessControlContext() { 191 return accessControlContext; 192 } 193 194 static boolean lockPage() { 195 return Invoker.getInvoker().lock(PAGE_LOCK); 196 } 197 198 static boolean unlockPage() { 199 return Invoker.getInvoker().unlock(PAGE_LOCK); 200 } 201 202 // ************************************************************************* 203 // Backbuffer support 204 // ************************************************************************* 205 206 private WCPageBackBuffer backbuffer; 207 private List<WCRectangle> dirtyRects = new LinkedList<WCRectangle>(); 208 209 private void addDirtyRect(WCRectangle toPaint) { 210 for (Iterator<WCRectangle> it = dirtyRects.iterator(); it.hasNext();) { 211 WCRectangle rect = it.next(); 212 // if already covered 213 if (rect.contains(toPaint)) { 214 return; 215 } 216 // if covers an existing one 217 if (toPaint.contains(rect)) { 218 it.remove(); 219 continue; 220 } 221 WCRectangle u = rect.createUnion(toPaint); 222 // if squre of union is less than summary of squares 223 if (u.getIntWidth() * u.getIntHeight() < 224 rect.getIntWidth() * rect.getIntHeight() + 225 toPaint.getIntWidth() * toPaint.getIntHeight()) 226 { 227 it.remove(); 228 toPaint = u; // replace both the rects with their union 229 continue; 230 } 231 } 232 dirtyRects.add(toPaint); 233 } 234 235 public boolean isDirty() { 236 lockPage(); 237 try { 238 return !dirtyRects.isEmpty(); 239 } finally { 240 unlockPage(); 241 } 242 } 243 244 private void updateDirty(WCRectangle clip) { 245 if (paintLog.isLoggable(Level.FINEST)) { 246 paintLog.log(Level.FINEST, "Entering, " 247 + "dirtyRects: {0}, currentFrame: {1}", 248 new Object[] {dirtyRects, currentFrame}); 249 } 250 251 if (isDisposed || width <= 0 || height <= 0) { 252 // If there're any dirty rects left, they are invalid. 253 // Clear the list so that the platform doesn't consider 254 // the page dirty. 255 dirtyRects.clear(); 256 return; 257 } 258 if (clip == null) { 259 clip = new WCRectangle(0, 0, width, height); 260 } 261 List<WCRectangle> oldDirtyRects = dirtyRects; 262 dirtyRects = new LinkedList<WCRectangle>(); 263 twkPrePaint(getPage()); 264 while (!oldDirtyRects.isEmpty()) { 265 WCRectangle r = oldDirtyRects.remove(0).intersection(clip); 266 if (r.getWidth() <= 0 || r.getHeight() <= 0) { 267 continue; 268 } 269 paintLog.log(Level.FINEST, "Updating: {0}", r); 270 WCRenderQueue rq = WCGraphicsManager.getGraphicsManager() 271 .createRenderQueue(r, true); 272 twkUpdateContent(getPage(), rq, r.getIntX() - 1, r.getIntY() - 1, 273 r.getIntWidth() + 2, r.getIntHeight() + 2); 274 currentFrame.addRenderQueue(rq); 275 } 276 { 277 WCRenderQueue rq = WCGraphicsManager.getGraphicsManager() 278 .createRenderQueue(clip, false); 279 twkPostPaint(getPage(), rq, 280 clip.getIntX(), clip.getIntY(), 281 clip.getIntWidth(), clip.getIntHeight()); 282 currentFrame.addRenderQueue(rq); 283 } 284 285 if (paintLog.isLoggable(Level.FINEST)) { 286 paintLog.log(Level.FINEST, "Dirty rects processed, " 287 + "dirtyRects: {0}, currentFrame: {1}", 288 new Object[] {dirtyRects, currentFrame}); 289 } 290 291 if (currentFrame.getRQList().size() > 0) { 292 synchronized (frameQueue) { 293 paintLog.log(Level.FINEST, "About to update frame queue, " 294 + "frameQueue: {0}", frameQueue); 295 296 Iterator<RenderFrame> it = frameQueue.iterator(); 297 while (it.hasNext()) { 298 RenderFrame frame = it.next(); 299 for (WCRenderQueue rq : currentFrame.getRQList()) { 300 WCRectangle rqRect = rq.getClip(); 301 if (rq.isOpaque() 302 && rqRect.contains(frame.getEnclosingRect())) 303 { 304 paintLog.log(Level.FINEST, "Dropping: {0}", frame); 305 frame.drop(); 306 it.remove(); 307 break; 308 } 309 } 310 } 311 312 frameQueue.add(currentFrame); 313 currentFrame = new RenderFrame(); 314 315 if (frameQueue.size() > MAX_FRAME_QUEUE_SIZE) { 316 paintLog.log(Level.FINEST, "Frame queue exceeded maximum " 317 + "size, clearing and requesting full repaint"); 318 dropRenderFrames(); 319 repaintAll(); 320 } 321 322 paintLog.log(Level.FINEST, "Frame queue updated, " 323 + "frameQueue: {0}", frameQueue); 324 } 325 } 326 327 if (paintLog.isLoggable(Level.FINEST)) { 328 paintLog.log(Level.FINEST, 329 "Exiting, dirtyRects: {0}, currentFrame: {1}", 330 new Object[] {dirtyRects, currentFrame}); 331 } 332 } 333 334 private void scroll(int x, int y, int w, int h, int dx, int dy) { 335 if (paintLog.isLoggable(Level.FINEST)) { 336 paintLog.finest("rect=[" + x + ", " + y + " " + w + "x" + h + 337 "] delta=[" + dx + ", " + dy + "]"); 338 } 339 if (Math.abs(dx) < w && Math.abs(dy) < h) { 340 int cx = (dx >= 0) ? x : x - dx; 341 int cy = (dy >= 0) ? y : y - dy; 342 int cw = (dx == 0) ? w : w - Math.abs(dx); 343 int ch = (dy == 0) ? h : h - Math.abs(dy); 344 345 WCRenderQueue rq = WCGraphicsManager.getGraphicsManager() 346 .createRenderQueue( 347 new WCRectangle(0, 0, width, height), false); 348 ByteBuffer buffer = ByteBuffer.allocate(32) 349 .order(ByteOrder.nativeOrder()) 350 .putInt(GraphicsDecoder.COPYREGION) 351 .putInt(backbuffer.getID()) 352 .putInt(cx).putInt(cy).putInt(cw).putInt(ch) 353 .putInt(dx).putInt(dy); 354 buffer.flip(); 355 rq.addBuffer(buffer); 356 currentFrame.addRenderQueue(rq); 357 358 // Now we have to translate "old" dirty rects that fit to the frame's 359 // content as the content is already scrolled at the moment by webkit. 360 if (!dirtyRects.isEmpty()) { 361 WCRectangle scrollRect = new WCRectangle(x, y, w, h); 362 363 for (WCRectangle r: dirtyRects) { 364 if (scrollRect.contains(r)) { 365 if (paintLog.isLoggable(Level.FINEST)) { 366 paintLog.log(Level.FINEST, "translating old dirty rect by the delta: " + r); 367 } 368 r.translate(dx, dy); 369 } 370 } 371 } 372 } 373 374 // Add the dirty (not copied) rect 375 addDirtyRect(new WCRectangle(dx >= 0 ? x : x + w + dx, 376 dy >= 0 ? y : y + h + dy, 377 dx == 0 ? w : Math.abs(dx), 378 dy == 0 ? h : Math.abs(dy))); 379 } 380 381 // Instances of this class may not be accessed and modified concurrently 382 // by multiple threads 383 private static final class RenderFrame { 384 private final List<WCRenderQueue> rqList = 385 new LinkedList<WCRenderQueue>(); 386 private final WCRectangle enclosingRect = new WCRectangle(); 387 388 // Called on: Event thread only 389 private void addRenderQueue(WCRenderQueue rq) { 390 if (rq.isEmpty()) { 391 return; 392 } 393 rqList.add(rq); 394 WCRectangle rqRect = rq.getClip(); 395 if (enclosingRect.isEmpty()) { 396 enclosingRect.setFrame(rqRect.getX(), rqRect.getY(), 397 rqRect.getWidth(), rqRect.getHeight()); 398 } else if (rqRect.isEmpty()) { 399 // do nothing 400 } else { 401 WCRectangle.union(enclosingRect, rqRect, enclosingRect); 402 } 403 } 404 405 // Called on: Event thread and Main thread 406 private List<WCRenderQueue> getRQList() { 407 return rqList; 408 } 409 410 // Called on: Event thread only 411 private WCRectangle getEnclosingRect() { 412 return enclosingRect; 413 } 414 415 // Called on: Event thread only 416 private void drop() { 417 for (WCRenderQueue rq : rqList) { 418 rq.dispose(); 419 } 420 rqList.clear(); 421 enclosingRect.setFrame(0, 0, 0, 0); 422 } 423 424 @Override 425 public String toString() { 426 return "RenderFrame{" 427 + "rqList=" + rqList + ", " 428 + "enclosingRect=" + enclosingRect 429 + "}"; 430 } 431 } 432 433 // ************************************************************************* 434 // Callback API 435 // ************************************************************************* 436 437 private final WebPageClient pageClient; 438 private final UIClient uiClient; 439 private final PolicyClient policyClient; 440 private InputMethodClient imClient; 441 private final List<LoadListenerClient> loadListenerClients = 442 new LinkedList<LoadListenerClient>(); 443 private final InspectorClient inspectorClient; 444 private final RenderTheme renderTheme; 445 private final ScrollBarTheme scrollbarTheme; 446 447 public WebPageClient getPageClient() { 448 return pageClient; 449 } 450 451 public void setInputMethodClient(InputMethodClient imClient) { 452 this.imClient = imClient; 453 } 454 455 public void setInputMethodState(boolean state) { 456 if (imClient != null) { 457 // A web page containing multiple clients is a single client from Java 458 // Input Method Framework's viewpoint. We need to control activation and 459 // deactivation for each text field/area here. Also, we need to control 460 // enabling and disabling input methods here so that input method events 461 // won't get delivered to wrong places (e.g., background). 462 imClient.activateInputMethods(state); 463 } 464 } 465 466 public void addLoadListenerClient(LoadListenerClient l) { 467 if (!loadListenerClients.contains(l)) { 468 loadListenerClients.add(l); 469 } 470 } 471 472 private RenderTheme getRenderTheme() { 473 return renderTheme; 474 } 475 476 private static RenderTheme fwkGetDefaultRenderTheme() { 477 return ThemeClient.getDefaultRenderTheme(); 478 } 479 480 private ScrollBarTheme getScrollBarTheme() { 481 return scrollbarTheme; 482 } 483 484 // ************************************************************************* 485 // UI stuff API 486 // ************************************************************************* 487 488 public void setBounds(int x, int y, int w, int h) { 489 lockPage(); 490 try { 491 log.log(Level.FINE, "setBounds: " + x + " " + y + " " + w + " " + h); 492 if (isDisposed) { 493 log.log(Level.FINE, "setBounds() request for a disposed web page."); 494 return; 495 } 496 width = w; 497 height = h; 498 twkSetBounds(getPage(), 0, 0, w, h); 499 // In response to the above call, WebKit will issue many 500 // repaint requests, one of which will be meant to invalidate 501 // the entire visible area. However, if the current scroll 502 // offset is non-zero, that repaint request will contain 503 // incorrect coordinates. 504 // As of time of writing this, this problem exists in both 505 // MiniBrowser and WinLauncher. 506 // MiniBrowser is based on WebKit2, and WebKit2 workarounds 507 // this problem by calling m_drawingArea->setNeedsDisplay() 508 // for the entire visible area from within the WebKit2's 509 // WebPage::setSize(). 510 // WinLauncher workarounds this problem by setting the main 511 // window class style to CS_HREDRAW | CS_VREDRAW and calling 512 // MoveWindow() with bRepaint = TRUE when resizing the web 513 // view. 514 // We workaround this problem by invalidating the entire 515 // visible area here. 516 repaintAll(); 517 518 } finally { 519 unlockPage(); 520 } 521 } 522 523 public void setOpaque(long frameID, boolean isOpaque) { 524 lockPage(); 525 try { 526 log.log(Level.FINE, "setOpaque: " + isOpaque); 527 if (isDisposed) { 528 log.log(Level.FINE, "setOpaque() request for a disposed web page."); 529 return; 530 } 531 if (!frames.contains(frameID)) { 532 return; 533 } 534 twkSetTransparent(frameID, !isOpaque); 535 536 } finally { 537 unlockPage(); 538 } 539 } 540 541 public void setBackgroundColor(long frameID, int backgroundColor) { 542 lockPage(); 543 try { 544 log.log(Level.FINE, "setBackgroundColor: " + backgroundColor); 545 if (isDisposed) { 546 log.log(Level.FINE, "setBackgroundColor() request for a disposed web page."); 547 return; 548 } 549 if (!frames.contains(frameID)) { 550 return; 551 } 552 twkSetBackgroundColor(frameID, backgroundColor); 553 554 } finally { 555 unlockPage(); 556 } 557 } 558 559 public void setBackgroundColor(int backgroundColor) { 560 lockPage(); 561 try { 562 log.log(Level.FINE, "setBackgroundColor: " + backgroundColor + 563 " for all frames"); 564 if (isDisposed) { 565 log.log(Level.FINE, "setBackgroundColor() request for a disposed web page."); 566 return; 567 } 568 569 for (long frameID: frames) { 570 twkSetBackgroundColor(frameID, backgroundColor); 571 } 572 573 } finally { 574 unlockPage(); 575 } 576 } 577 578 /* 579 * Executed on the Event Thread. 580 */ 581 public void updateContent(WCRectangle toPaint) { 582 lockPage(); 583 try { 584 paintLog.log(Level.FINEST, "toPaint: {0}", toPaint); 585 if (isDisposed) { 586 paintLog.fine("updateContent() request for a disposed web page."); 587 return; 588 } 589 updateDirty(toPaint); 590 591 } finally { 592 unlockPage(); 593 } 594 } 595 596 public boolean isRepaintPending() { 597 lockPage(); 598 try { 599 synchronized (frameQueue) { 600 return !frameQueue.isEmpty(); 601 } 602 } finally { 603 unlockPage(); 604 } 605 } 606 607 /* 608 * Executed on printing thread. 609 */ 610 public void print(WCGraphicsContext gc, 611 final int x, final int y, final int w, final int h) 612 { 613 lockPage(); 614 try { 615 final WCRenderQueue rq = WCGraphicsManager.getGraphicsManager(). 616 createRenderQueue(new WCRectangle(x, y, w, h), true); 617 FutureTask<Void> f = new FutureTask<Void>(() -> { 618 twkUpdateContent(getPage(), rq, x, y, w, h); 619 }, null); 620 Invoker.getInvoker().invokeOnEventThread(f); 621 622 try { 623 // block until job is complete 624 f.get(); 625 } catch (ExecutionException ex) { 626 throw new AssertionError(ex); 627 } catch (InterruptedException ex) { 628 // ignore; recovery is impossible 629 } 630 631 rq.decode(gc); 632 } finally { 633 unlockPage(); 634 } 635 } 636 637 /* 638 * Executed on the Render Thread. 639 */ 640 public void paint(WCGraphicsContext gc, int x, int y, int w, int h) { 641 lockPage(); 642 try { 643 if (pageClient != null && pageClient.isBackBufferSupported()) { 644 if (!backbuffer.validate(width, height)) { 645 // We need to repaint the whole page on the next turn 646 Invoker.getInvoker().invokeOnEventThread(() -> { 647 repaintAll(); 648 }); 649 return; 650 } 651 WCGraphicsContext bgc = backbuffer.createGraphics(); 652 try { 653 paint2GC(bgc); 654 bgc.flush(); 655 } finally { 656 backbuffer.disposeGraphics(bgc); 657 } 658 backbuffer.flush(gc, x, y, w, h); 659 } else { 660 paint2GC(gc); 661 } 662 } finally { 663 unlockPage(); 664 } 665 } 666 667 private void paint2GC(WCGraphicsContext gc) { 668 paintLog.finest("Entering"); 669 gc.setFontSmoothingType(this.fontSmoothingType); 670 671 List<RenderFrame> framesToRender; 672 synchronized (frameQueue) { 673 framesToRender = new ArrayList(frameQueue); 674 frameQueue.clear(); 675 } 676 677 paintLog.log(Level.FINEST, "Frames to render: {0}", framesToRender); 678 679 for (RenderFrame frame : framesToRender) { 680 paintLog.log(Level.FINEST, "Rendering: {0}", frame); 681 for (WCRenderQueue rq : frame.getRQList()) { 682 gc.saveState(); 683 if (rq.getClip() != null) { 684 gc.setClip(rq.getClip()); 685 } 686 rq.decode(gc); 687 gc.restoreState(); 688 } 689 } 690 paintLog.finest("Exiting"); 691 } 692 693 /* 694 * Executed on the Event Thread. 695 */ 696 public void dropRenderFrames() { 697 lockPage(); 698 try { 699 currentFrame.drop(); 700 synchronized (frameQueue) { 701 for (RenderFrame frame = frameQueue.poll(); frame != null; frame = frameQueue.poll()) { 702 frame.drop(); 703 } 704 } 705 } finally { 706 unlockPage(); 707 } 708 } 709 710 public void dispatchFocusEvent(WCFocusEvent fe) { 711 lockPage(); 712 try { 713 log.log(Level.FINEST, "dispatchFocusEvent: " + fe); 714 if (isDisposed) { 715 log.log(Level.FINE, "Focus event for a disposed web page."); 716 return; 717 } 718 twkProcessFocusEvent(getPage(), fe.getID(), fe.getDirection()); 719 720 } finally { 721 unlockPage(); 722 } 723 } 724 725 public boolean dispatchKeyEvent(WCKeyEvent ke) { 726 lockPage(); 727 try { 728 log.log(Level.FINEST, "dispatchKeyEvent: " + ke); 729 if (isDisposed) { 730 log.log(Level.FINE, "Key event for a disposed web page."); 731 return false; 732 } 733 if (WCKeyEvent.filterEvent(ke)) { 734 log.log(Level.FINEST, "filtered"); 735 return false; 736 } 737 return twkProcessKeyEvent(getPage(), ke.getType(), ke.getText(), 738 ke.getKeyIdentifier(), 739 ke.getWindowsVirtualKeyCode(), 740 ke.isShiftDown(), ke.isCtrlDown(), 741 ke.isAltDown(), ke.isMetaDown()); 742 } finally { 743 unlockPage(); 744 } 745 } 746 747 public boolean dispatchMouseEvent(WCMouseEvent me) { 748 lockPage(); 749 try { 750 log.log(Level.FINEST, "dispatchMouseEvent: " + me.getX() + "," + me.getY()); 751 if (isDisposed) { 752 log.log(Level.FINE, "Mouse event for a disposed web page."); 753 return false; 754 } 755 756 return !isDragConfirmed() //When Webkit informes FX about drag start, it waits 757 //for system DnD loop and not intereasted in 758 //intermediate mouse events that can change text selection. 759 && twkProcessMouseEvent(getPage(), me.getID(), 760 me.getButton(), me.getClickCount(), 761 me.getX(), me.getY(), me.getScreenX(), me.getScreenY(), 762 me.isShiftDown(), me.isControlDown(), me.isAltDown(), me.isMetaDown(), me.isPopupTrigger(), 763 me.getWhen() / 1000.0f); 764 } finally { 765 unlockPage(); 766 } 767 } 768 769 public boolean dispatchMouseWheelEvent(WCMouseWheelEvent me) { 770 lockPage(); 771 try { 772 log.log(Level.FINEST, "dispatchMouseWheelEvent: " + me); 773 if (isDisposed) { 774 log.log(Level.FINE, "MouseWheel event for a disposed web page."); 775 return false; 776 } 777 return twkProcessMouseWheelEvent(getPage(), 778 me.getX(), me.getY(), me.getScreenX(), me.getScreenY(), 779 me.getDeltaX(), me.getDeltaY(), 780 me.isShiftDown(), me.isControlDown(), me.isAltDown(), me.isMetaDown(), 781 me.getWhen() / 1000.0f); 782 } finally { 783 unlockPage(); 784 } 785 } 786 787 public boolean dispatchInputMethodEvent(WCInputMethodEvent ie) { 788 lockPage(); 789 try { 790 log.log(Level.FINEST, "dispatchInputMethodEvent: " + ie); 791 if (isDisposed) { 792 log.log(Level.FINE, "InputMethod event for a disposed web page."); 793 return false; 794 } 795 switch (ie.getID()) { 796 case WCInputMethodEvent.INPUT_METHOD_TEXT_CHANGED: 797 return twkProcessInputTextChange(getPage(), 798 ie.getComposed(), ie.getCommitted(), 799 ie.getAttributes(), ie.getCaretPosition()); 800 801 case WCInputMethodEvent.CARET_POSITION_CHANGED: 802 return twkProcessCaretPositionChange(getPage(), 803 ie.getCaretPosition()); 804 } 805 return false; 806 807 } finally { 808 unlockPage(); 809 } 810 } 811 812 public final static int DND_DST_ENTER = 0; 813 public final static int DND_DST_OVER = 1; 814 public final static int DND_DST_CHANGE = 2; 815 public final static int DND_DST_EXIT = 3; 816 public final static int DND_DST_DROP = 4; 817 818 public final static int DND_SRC_ENTER = 100; 819 public final static int DND_SRC_OVER = 101; 820 public final static int DND_SRC_CHANGE = 102; 821 public final static int DND_SRC_EXIT = 103; 822 public final static int DND_SRC_DROP = 104; 823 824 public int dispatchDragOperation( 825 int commandId, 826 String[] mimeTypes, String[] values, 827 int x, int y, 828 int screenX, int screenY, 829 int dndActionId) 830 { 831 lockPage(); 832 try { 833 log.log(Level.FINEST, "dispatchDragOperation: " + x + "," + y 834 + " dndCommand:" + commandId 835 + " dndAction" + dndActionId); 836 if (isDisposed) { 837 log.log(Level.FINE, "DnD event for a disposed web page."); 838 return 0; 839 } 840 return twkProcessDrag(getPage(), 841 commandId, 842 mimeTypes, values, 843 x, y, 844 screenX, screenY, 845 dndActionId); 846 } finally { 847 unlockPage(); 848 } 849 } 850 851 public void confirmStartDrag() { 852 if (uiClient != null) 853 uiClient.confirmStartDrag(); 854 } 855 856 public boolean isDragConfirmed(){ 857 return (uiClient != null) 858 ? uiClient.isDragConfirmed() 859 : false; 860 } 861 862 // ************************************************************************* 863 // Input methods 864 // ************************************************************************* 865 866 public int[] getClientTextLocation(int index) { 867 lockPage(); 868 try { 869 if (isDisposed) { 870 log.log(Level.FINE, "getClientTextLocation() request for a disposed web page."); 871 return new int[] { 0, 0, 0, 0 }; 872 } 873 return twkGetTextLocation(getPage(), index); 874 875 } finally { 876 unlockPage(); 877 } 878 } 879 880 public int getClientLocationOffset(int x, int y) { 881 lockPage(); 882 try { 883 if (isDisposed) { 884 log.log(Level.FINE, "getClientLocationOffset() request for a disposed web page."); 885 return 0; 886 } 887 return twkGetInsertPositionOffset(getPage()); 888 889 } finally { 890 unlockPage(); 891 } 892 } 893 894 public int getClientInsertPositionOffset() { 895 lockPage(); 896 try { 897 if (isDisposed) { 898 log.log(Level.FINE, "getClientInsertPositionOffset() request for a disposed web page."); 899 return 0; 900 } 901 return twkGetInsertPositionOffset(getPage()); 902 903 } finally { 904 unlockPage(); 905 } 906 } 907 908 public int getClientCommittedTextLength() { 909 lockPage(); 910 try { 911 if (isDisposed) { 912 log.log(Level.FINE, "getClientCommittedTextOffset() request for a disposed web page."); 913 return 0; 914 } 915 return twkGetCommittedTextLength(getPage()); 916 917 } finally { 918 unlockPage(); 919 } 920 } 921 922 public String getClientCommittedText() { 923 lockPage(); 924 try { 925 if (isDisposed) { 926 log.log(Level.FINE, "getClientCommittedText() request for a disposed web page."); 927 return ""; 928 } 929 return twkGetCommittedText(getPage()); 930 931 } finally { 932 unlockPage(); 933 } 934 } 935 936 public String getClientSelectedText() { 937 lockPage(); 938 try { 939 if (isDisposed) { 940 log.log(Level.FINE, "getClientSelectedText() request for a disposed web page."); 941 return ""; 942 } 943 return twkGetSelectedText(getPage()); 944 945 } finally { 946 unlockPage(); 947 } 948 } 949 950 // ************************************************************************* 951 // Browser API 952 // ************************************************************************* 953 954 public void dispose() { 955 lockPage(); 956 try { 957 log.log(Level.FINER, "dispose"); 958 959 stop(); 960 dropRenderFrames(); 961 isDisposed = true; 962 963 twkDestroyPage(pPage); 964 pPage = 0; 965 966 for (long frameID : frames) { 967 log.log(Level.FINE, "Undestroyed frame view: " + frameID); 968 } 969 frames.clear(); 970 971 if (backbuffer != null) { 972 backbuffer.deref(); 973 backbuffer = null; 974 } 975 } finally { 976 unlockPage(); 977 } 978 } 979 980 public String getName(long frameID) { 981 lockPage(); 982 try { 983 log.log(Level.FINE, "Get Name: frame = " + frameID); 984 if (isDisposed) { 985 log.log(Level.FINE, "getName() request for a disposed web page."); 986 return null; 987 } 988 if (!frames.contains(frameID)) { 989 return null; 990 } 991 return twkGetName(frameID); 992 993 } finally { 994 unlockPage(); 995 } 996 } 997 998 public String getURL(long frameID) { 999 lockPage(); 1000 try { 1001 log.log(Level.FINE, "Get URL: frame = " + frameID); 1002 if (isDisposed) { 1003 log.log(Level.FINE, "getURL() request for a disposed web page."); 1004 return null; 1005 } 1006 if (!frames.contains(frameID)) { 1007 return null; 1008 } 1009 return twkGetURL(frameID); 1010 1011 } finally { 1012 unlockPage(); 1013 } 1014 } 1015 1016 public String getEncoding() { 1017 lockPage(); 1018 try { 1019 log.log(Level.FINE, "Get encoding"); 1020 if (isDisposed) { 1021 log.log(Level.FINE, "getEncoding() request for a disposed web page."); 1022 return null; 1023 } 1024 return twkGetEncoding(getPage()); 1025 1026 } finally { 1027 unlockPage(); 1028 } 1029 } 1030 1031 public void setEncoding(String encoding) { 1032 lockPage(); 1033 try { 1034 log.log(Level.FINE, "Set encoding: encoding = " + encoding); 1035 if (isDisposed) { 1036 log.log(Level.FINE, "setEncoding() request for a disposed web page."); 1037 return; 1038 } 1039 if (encoding != null && !encoding.isEmpty()) { 1040 twkSetEncoding(getPage(), encoding); 1041 } 1042 1043 } finally { 1044 unlockPage(); 1045 } 1046 } 1047 1048 // DRT support 1049 public String getInnerText(long frameID) { 1050 lockPage(); 1051 try { 1052 log.log(Level.FINE, "Get inner text: frame = " + frameID); 1053 if (isDisposed) { 1054 log.log(Level.FINE, "getInnerText() request for a disposed web page."); 1055 return null; 1056 } 1057 if (!frames.contains(frameID)) { 1058 return null; 1059 } 1060 return twkGetInnerText(frameID); 1061 1062 } finally { 1063 unlockPage(); 1064 } 1065 } 1066 1067 // DRT support 1068 public String getRenderTree(long frameID) { 1069 lockPage(); 1070 try { 1071 log.log(Level.FINE, "Get render tree: frame = " + frameID); 1072 if (isDisposed) { 1073 log.log(Level.FINE, "getRenderTree() request for a disposed web page."); 1074 return null; 1075 } 1076 if (!frames.contains(frameID)) { 1077 return null; 1078 } 1079 return twkGetRenderTree(frameID); 1080 1081 } finally { 1082 unlockPage(); 1083 } 1084 } 1085 1086 // DRT support 1087 public int getUnloadEventListenersCount(long frameID) { 1088 lockPage(); 1089 try { 1090 log.log(Level.FINE, "frame: " + frameID); 1091 if (isDisposed) { 1092 log.log(Level.FINE, "request for a disposed web page."); 1093 return 0; 1094 } 1095 if (!frames.contains(frameID)) { 1096 return 0; 1097 } 1098 return twkGetUnloadEventListenersCount(frameID); 1099 1100 } finally { 1101 unlockPage(); 1102 } 1103 } 1104 1105 public String getContentType(long frameID) { 1106 lockPage(); 1107 try { 1108 log.log(Level.FINE, "Get content type: frame = " + frameID); 1109 if (isDisposed) { 1110 log.log(Level.FINE, "getContentType() request for a disposed web page."); 1111 return null; 1112 } 1113 if (!frames.contains(frameID)) { 1114 return null; 1115 } 1116 return twkGetContentType(frameID); 1117 1118 } finally { 1119 unlockPage(); 1120 } 1121 } 1122 1123 public String getTitle(long frameID) { 1124 lockPage(); 1125 try { 1126 log.log(Level.FINE, "Get title: frame = " + frameID); 1127 if (isDisposed) { 1128 log.log(Level.FINE, "getTitle() request for a disposed web page."); 1129 return null; 1130 } 1131 if (!frames.contains(frameID)) { 1132 return null; 1133 } 1134 return twkGetTitle(frameID); 1135 1136 } finally { 1137 unlockPage(); 1138 } 1139 } 1140 1141 public WCImage getIcon(long frameID) { 1142 lockPage(); 1143 try { 1144 log.log(Level.FINE, "Get icon: frame = " + frameID); 1145 if (isDisposed) { 1146 log.log(Level.FINE, "getIcon() request for a disposed web page."); 1147 return null; 1148 } 1149 if (!frames.contains(frameID)) { 1150 return null; 1151 } 1152 String iconURL = twkGetIconURL(frameID); 1153 // do we need any cache for icons here? 1154 if (iconURL != null && !iconURL.isEmpty()) { 1155 return WCGraphicsManager.getGraphicsManager().getIconImage(iconURL); 1156 } 1157 return null; 1158 1159 } finally { 1160 unlockPage(); 1161 } 1162 } 1163 1164 public void open(final long frameID, final String url) { 1165 lockPage(); 1166 try { 1167 log.log(Level.FINE, "Open URL: " + url); 1168 if (isDisposed) { 1169 log.log(Level.FINE, "open() request for a disposed web page."); 1170 return; 1171 } 1172 if (!frames.contains(frameID)) { 1173 return; 1174 } 1175 twkOpen(frameID, url); 1176 1177 } finally { 1178 unlockPage(); 1179 } 1180 } 1181 1182 public void load(final long frameID, final String text, final String contentType) { 1183 lockPage(); 1184 try { 1185 log.log(Level.FINE, "Load text: " + text); 1186 if (text == null) { 1187 return; 1188 } 1189 if (isDisposed) { 1190 log.log(Level.FINE, "load() request for a disposed web page."); 1191 return; 1192 } 1193 if (!frames.contains(frameID)) { 1194 return; 1195 } 1196 // TODO: handle contentType 1197 twkLoad(frameID, text, contentType); 1198 1199 } finally { 1200 unlockPage(); 1201 } 1202 } 1203 1204 public void stop(final long frameID) { 1205 lockPage(); 1206 try { 1207 log.log(Level.FINE, "Stop loading: frame = " + frameID); 1208 1209 String url; 1210 String contentType; 1211 if (isDisposed) { 1212 log.log(Level.FINE, "cancel() request for a disposed web page."); 1213 return; 1214 } 1215 if (!frames.contains(frameID)) { 1216 return; 1217 } 1218 url = twkGetURL(frameID); 1219 contentType = twkGetContentType(frameID); 1220 twkStop(frameID); 1221 // WebKit doesn't send any notifications about loading stopped, 1222 // so sending it here 1223 fireLoadEvent(frameID, LoadListenerClient.LOAD_STOPPED, url, contentType, 1.0, 0); 1224 1225 } finally { 1226 unlockPage(); 1227 } 1228 } 1229 1230 // stops all loading synchronously 1231 public void stop() { 1232 lockPage(); 1233 try { 1234 log.log(Level.FINE, "Stop loading sync"); 1235 if (isDisposed) { 1236 log.log(Level.FINE, "stopAll() request for a disposed web page."); 1237 return; 1238 } 1239 twkStopAll(getPage()); 1240 1241 } finally { 1242 unlockPage(); 1243 } 1244 } 1245 1246 public void refresh(final long frameID) { 1247 lockPage(); 1248 try { 1249 log.log(Level.FINE, "Refresh: frame = " + frameID); 1250 if (isDisposed) { 1251 log.log(Level.FINE, "refresh() request for a disposed web page."); 1252 return; 1253 } 1254 if (!frames.contains(frameID)) { 1255 return; 1256 } 1257 twkRefresh(frameID); 1258 1259 } finally { 1260 unlockPage(); 1261 } 1262 } 1263 1264 public BackForwardList createBackForwardList() { 1265 return new BackForwardList(this); 1266 } 1267 1268 public boolean goBack() { 1269 lockPage(); 1270 try { 1271 log.log(Level.FINE, "Go back"); 1272 if (isDisposed) { 1273 log.log(Level.FINE, "goBack() request for a disposed web page."); 1274 return false; 1275 } 1276 return twkGoBackForward(getPage(), -1); 1277 1278 } finally { 1279 unlockPage(); 1280 } 1281 } 1282 1283 public boolean goForward() { 1284 lockPage(); 1285 try { 1286 log.log(Level.FINE, "Go forward"); 1287 if (isDisposed) { 1288 log.log(Level.FINE, "goForward() request for a disposed web page."); 1289 return false; 1290 } 1291 return twkGoBackForward(getPage(), 1); 1292 1293 } finally { 1294 unlockPage(); 1295 } 1296 } 1297 1298 public boolean copy() { 1299 lockPage(); 1300 try { 1301 log.log(Level.FINE, "Copy"); 1302 if (isDisposed) { 1303 log.log(Level.FINE, "copy() request for a disposed web page."); 1304 return false; 1305 } 1306 long frameID = getMainFrame(); 1307 if (!frames.contains(frameID)) { 1308 return false; 1309 } 1310 return twkCopy(frameID); 1311 1312 } finally { 1313 unlockPage(); 1314 } 1315 } 1316 1317 // Find in page 1318 public boolean find(String stringToFind, boolean forward, boolean wrap, boolean matchCase) { 1319 lockPage(); 1320 try { 1321 log.log(Level.FINE, "Find in page: stringToFind = " + stringToFind + ", " + 1322 (forward ? "forward" : "backward") + (wrap ? ", wrap" : "") + (matchCase ? ", matchCase" : "")); 1323 if (isDisposed) { 1324 log.log(Level.FINE, "find() request for a disposed web page."); 1325 return false; 1326 } 1327 return twkFindInPage(getPage(), stringToFind, forward, wrap, matchCase); 1328 1329 } finally { 1330 unlockPage(); 1331 } 1332 } 1333 1334 // Find in frame 1335 public boolean find(long frameID, 1336 String stringToFind, boolean forward, boolean wrap, boolean matchCase) 1337 { 1338 lockPage(); 1339 try { 1340 log.log(Level.FINE, "Find in frame: stringToFind = " + stringToFind + ", " + 1341 (forward ? "forward" : "backward") + (wrap ? ", wrap" : "") + (matchCase ? ", matchCase" : "")); 1342 if (isDisposed) { 1343 log.log(Level.FINE, "find() request for a disposed web page."); 1344 return false; 1345 } 1346 if (!frames.contains(frameID)) { 1347 return false; 1348 } 1349 return twkFindInFrame(frameID, stringToFind, forward, wrap, matchCase); 1350 1351 } finally { 1352 unlockPage(); 1353 } 1354 } 1355 1356 public float getZoomFactor(boolean textOnly) { 1357 lockPage(); 1358 try { 1359 log.log(Level.FINE, "Get zoom factor, textOnly=" + textOnly); 1360 if (isDisposed) { 1361 log.log(Level.FINE, "getZoomFactor() request for a disposed web page."); 1362 return 1.0f; 1363 } 1364 long frameID = getMainFrame(); 1365 if (!frames.contains(frameID)) { 1366 return 1.0f; 1367 } 1368 return twkGetZoomFactor(frameID, textOnly); 1369 } finally { 1370 unlockPage(); 1371 } 1372 } 1373 1374 public void setZoomFactor(float zoomFactor, boolean textOnly) { 1375 lockPage(); 1376 try { 1377 log.fine(String.format("Set zoom factor %.2f, textOnly=%b", zoomFactor, textOnly)); 1378 if (isDisposed) { 1379 log.log(Level.FINE, "setZoomFactor() request for a disposed web page."); 1380 return; 1381 } 1382 long frameID = getMainFrame(); 1383 if ((frameID == 0) || !frames.contains(frameID)) { 1384 return; 1385 } 1386 twkSetZoomFactor(frameID, zoomFactor, textOnly); 1387 } finally { 1388 unlockPage(); 1389 } 1390 } 1391 1392 public void setFontSmoothingType(int fontSmoothingType) { 1393 this.fontSmoothingType = fontSmoothingType; 1394 repaintAll(); 1395 } 1396 1397 // DRT support 1398 public void reset(long frameID) { 1399 lockPage(); 1400 try { 1401 log.log(Level.FINE, "Reset: frame = " + frameID); 1402 if (isDisposed) { 1403 log.log(Level.FINE, "reset() request for a disposed web page."); 1404 return; 1405 } 1406 if ((frameID == 0) || !frames.contains(frameID)) { 1407 return; 1408 } 1409 twkReset(frameID); 1410 1411 } finally { 1412 unlockPage(); 1413 } 1414 } 1415 1416 public Object executeScript(long frameID, String script) throws JSException { 1417 lockPage(); 1418 try { 1419 log.log(Level.FINE, "execute script: \"" + script + "\" in frame = " + frameID); 1420 if (isDisposed) { 1421 log.log(Level.FINE, "executeScript() request for a disposed web page."); 1422 return null; 1423 } 1424 if ((frameID == 0) || !frames.contains(frameID)) { 1425 return null; 1426 } 1427 return twkExecuteScript(frameID, script); 1428 1429 } finally { 1430 unlockPage(); 1431 } 1432 } 1433 1434 public long getMainFrame() { 1435 lockPage(); 1436 try { 1437 log.log(Level.FINER, "getMainFrame: page = " + pPage); 1438 if (isDisposed) { 1439 log.log(Level.FINE, "getMainFrame() request for a disposed web page."); 1440 return 0L; 1441 } 1442 long mainFrameID = twkGetMainFrame(getPage()); 1443 log.log(Level.FINER, "Main frame = " + mainFrameID); 1444 frames.add(mainFrameID); 1445 return mainFrameID; 1446 } finally { 1447 unlockPage(); 1448 } 1449 } 1450 1451 public long getParentFrame(long childID) { 1452 lockPage(); 1453 try { 1454 log.log(Level.FINE, "getParentFrame: child = " + childID); 1455 if (isDisposed) { 1456 log.log(Level.FINE, "getParentFrame() request for a disposed web page."); 1457 return 0L; 1458 } 1459 if (!frames.contains(childID)) { 1460 return 0L; 1461 } 1462 return twkGetParentFrame(childID); 1463 } finally { 1464 unlockPage(); 1465 } 1466 } 1467 1468 public List<Long> getChildFrames(long parentID) { 1469 lockPage(); 1470 try { 1471 log.log(Level.FINE, "getChildFrames: parent = " + parentID); 1472 if (isDisposed) { 1473 log.log(Level.FINE, "getChildFrames() request for a disposed web page."); 1474 return null; 1475 } 1476 if (!frames.contains(parentID)) { 1477 return null; 1478 } 1479 long[] children = twkGetChildFrames(parentID); 1480 List<Long> childrenList = new LinkedList<Long>(); 1481 for (long child : children) { 1482 childrenList.add(Long.valueOf(child)); 1483 } 1484 return childrenList; 1485 } finally { 1486 unlockPage(); 1487 } 1488 } 1489 1490 public WCRectangle getVisibleRect(long frameID) { 1491 lockPage(); 1492 try { 1493 if (!frames.contains(frameID)) { 1494 return null; 1495 } 1496 int[] arr = twkGetVisibleRect(frameID); 1497 if (arr != null) { 1498 return new WCRectangle(arr[0], arr[1], arr[2], arr[3]); 1499 } 1500 return null; 1501 } finally { 1502 unlockPage(); 1503 } 1504 } 1505 1506 public void scrollToPosition(long frameID, WCPoint p) { 1507 lockPage(); 1508 try { 1509 if (!frames.contains(frameID)) { 1510 return; 1511 } 1512 twkScrollToPosition(frameID, p.getIntX(), p.getIntY()); 1513 } finally { 1514 unlockPage(); 1515 } 1516 } 1517 1518 public WCSize getContentSize(long frameID) { 1519 lockPage(); 1520 try { 1521 if (!frames.contains(frameID)) { 1522 return null; 1523 } 1524 int[] arr = twkGetContentSize(frameID); 1525 if (arr != null) { 1526 return new WCSize(arr[0], arr[1]); 1527 } 1528 return null; 1529 } finally { 1530 unlockPage(); 1531 } 1532 } 1533 1534 // ---- DOM ---- // 1535 1536 public Document getDocument(long frameID) { 1537 lockPage(); 1538 try { 1539 log.log(Level.FINE, "getDocument"); 1540 if (isDisposed) { 1541 log.log(Level.FINE, "getDocument() request for a disposed web page."); 1542 return null; 1543 } 1544 1545 if (!frames.contains(frameID)) { 1546 return null; 1547 } 1548 return twkGetDocument(frameID); 1549 } finally { 1550 unlockPage(); 1551 } 1552 } 1553 1554 public Element getOwnerElement(long frameID) { 1555 lockPage(); 1556 try { 1557 log.log(Level.FINE, "getOwnerElement"); 1558 if (isDisposed) { 1559 log.log(Level.FINE, "getOwnerElement() request for a disposed web page."); 1560 return null; 1561 } 1562 1563 if (!frames.contains(frameID)) { 1564 return null; 1565 } 1566 return twkGetOwnerElement(frameID); 1567 } finally { 1568 unlockPage(); 1569 } 1570 } 1571 1572 // ---- EDITING SUPPORT ---- // 1573 1574 public boolean executeCommand(String command, String value) { 1575 lockPage(); 1576 try { 1577 if (log.isLoggable(Level.FINE)) { 1578 log.log(Level.FINE, "command: [{0}], value: [{1}]", 1579 new Object[] {command, value}); 1580 } 1581 if (isDisposed) { 1582 log.log(Level.FINE, "Web page is already disposed"); 1583 return false; 1584 } 1585 1586 boolean result = twkExecuteCommand(getPage(), command, value); 1587 1588 log.log(Level.FINE, "result: [{0}]", result); 1589 return result; 1590 } finally { 1591 unlockPage(); 1592 } 1593 } 1594 1595 public boolean queryCommandEnabled(String command) { 1596 lockPage(); 1597 try { 1598 log.log(Level.FINE, "command: [{0}]", command); 1599 if (isDisposed) { 1600 log.log(Level.FINE, "Web page is already disposed"); 1601 return false; 1602 } 1603 1604 boolean result = twkQueryCommandEnabled(getPage(), command); 1605 1606 log.log(Level.FINE, "result: [{0}]", result); 1607 return result; 1608 } finally { 1609 unlockPage(); 1610 } 1611 } 1612 1613 public boolean queryCommandState(String command) { 1614 lockPage(); 1615 try { 1616 log.log(Level.FINE, "command: [{0}]", command); 1617 if (isDisposed) { 1618 log.log(Level.FINE, "Web page is already disposed"); 1619 return false; 1620 } 1621 1622 boolean result = twkQueryCommandState(getPage(), command); 1623 1624 log.log(Level.FINE, "result: [{0}]", result); 1625 return result; 1626 } finally { 1627 unlockPage(); 1628 } 1629 } 1630 1631 public String queryCommandValue(String command) { 1632 lockPage(); 1633 try { 1634 log.log(Level.FINE, "command: [{0}]", command); 1635 if (isDisposed) { 1636 log.log(Level.FINE, "Web page is already disposed"); 1637 return null; 1638 } 1639 1640 String result = twkQueryCommandValue(getPage(), command); 1641 1642 log.log(Level.FINE, "result: [{0}]", result); 1643 return result; 1644 } finally { 1645 unlockPage(); 1646 } 1647 } 1648 1649 public boolean isEditable() { 1650 lockPage(); 1651 try { 1652 log.log(Level.FINE, "isEditable"); 1653 if (isDisposed) { 1654 log.log(Level.FINE, "isEditable() request for a disposed web page."); 1655 return false; 1656 } 1657 1658 return twkIsEditable(getPage()); 1659 } finally { 1660 unlockPage(); 1661 } 1662 } 1663 1664 public void setEditable(boolean editable) { 1665 lockPage(); 1666 try { 1667 log.log(Level.FINE, "setEditable"); 1668 if (isDisposed) { 1669 log.log(Level.FINE, "setEditable() request for a disposed web page."); 1670 return; 1671 } 1672 1673 twkSetEditable(getPage(), editable); 1674 } finally { 1675 unlockPage(); 1676 } 1677 } 1678 1679 /** 1680 * @return HTML content of the frame, 1681 * or null if frame document is absent or non-HTML. 1682 */ 1683 public String getHtml(long frameID) { 1684 lockPage(); 1685 try { 1686 log.log(Level.FINE, "getHtml"); 1687 if (isDisposed) { 1688 log.log(Level.FINE, "getHtml() request for a disposed web page."); 1689 return null; 1690 } 1691 if (!frames.contains(frameID)) { 1692 return null; 1693 } 1694 return twkGetHtml(frameID); 1695 } finally { 1696 unlockPage(); 1697 } 1698 } 1699 1700 // ---- PRINTING SUPPORT ---- // 1701 1702 public int beginPrinting(float width, float height) { 1703 lockPage(); 1704 try { 1705 if (isDisposed) { 1706 log.warning("beginPrinting() called for a disposed web page."); 1707 return 0; 1708 } 1709 return twkBeginPrinting(getPage(), width, height); 1710 } finally { 1711 unlockPage(); 1712 } 1713 } 1714 1715 public void endPrinting() { 1716 lockPage(); 1717 try { 1718 if (isDisposed) { 1719 log.warning("endPrinting() called for a disposed web page."); 1720 return; 1721 } 1722 twkEndPrinting(getPage()); 1723 } finally { 1724 unlockPage(); 1725 } 1726 } 1727 1728 public void print(final WCGraphicsContext gc, final int pageNumber, final float width) { 1729 lockPage(); 1730 try { 1731 if (isDisposed) { 1732 log.warning("print() called for a disposed web page."); 1733 return; 1734 } 1735 final WCRenderQueue rq = WCGraphicsManager.getGraphicsManager(). 1736 createRenderQueue(null, true); 1737 final CountDownLatch l = new CountDownLatch(1); 1738 Invoker.getInvoker().invokeOnEventThread(() -> { 1739 try { 1740 twkPrint(getPage(), rq, pageNumber, width); 1741 } finally { 1742 l.countDown(); 1743 } 1744 }); 1745 1746 try { 1747 l.await(); 1748 } catch (InterruptedException e) { 1749 rq.dispose(); 1750 return; 1751 } 1752 rq.decode(gc); 1753 } finally { 1754 unlockPage(); 1755 } 1756 } 1757 1758 public int getPageHeight() { 1759 return getFrameHeight(getMainFrame()); 1760 } 1761 1762 public int getFrameHeight(long frameID) { 1763 lockPage(); 1764 try { 1765 log.log(Level.FINE, "Get page height"); 1766 if (isDisposed) { 1767 log.log(Level.FINE, "getFrameHeight() request for a disposed web page."); 1768 return 0; 1769 } 1770 if (!frames.contains(frameID)) { 1771 return 0; 1772 } 1773 int height = twkGetFrameHeight(frameID); 1774 log.log(Level.FINE, "Height = " + height); 1775 return height; 1776 } finally { 1777 unlockPage(); 1778 } 1779 } 1780 1781 public float adjustFrameHeight(long frameID, 1782 float oldTop, float oldBottom, float bottomLimit) 1783 { 1784 lockPage(); 1785 try { 1786 log.log(Level.FINE, "Adjust page height"); 1787 if (isDisposed) { 1788 log.log(Level.FINE, "adjustFrameHeight() request for a disposed web page."); 1789 return 0; 1790 } 1791 if (!frames.contains(frameID)) { 1792 return 0; 1793 } 1794 return twkAdjustFrameHeight(frameID, oldTop, oldBottom, bottomLimit); 1795 } finally { 1796 unlockPage(); 1797 } 1798 } 1799 1800 // ---- SETTINGS ---- // 1801 1802 /** 1803 * Returns the usePageCache settings field. 1804 * @return {@code true} if this object uses the page cache, 1805 * {@code false} otherwise. 1806 */ 1807 public boolean getUsePageCache() { 1808 lockPage(); 1809 try { 1810 return twkGetUsePageCache(getPage()); 1811 } finally { 1812 unlockPage(); 1813 } 1814 } 1815 1816 /** 1817 * Sets the usePageCache settings field. 1818 * @param usePageCache {@code true} to use the page cache, 1819 * {@code false} to not use the page cache. 1820 */ 1821 public void setUsePageCache(boolean usePageCache) { 1822 lockPage(); 1823 try { 1824 twkSetUsePageCache(getPage(), usePageCache); 1825 } finally { 1826 unlockPage(); 1827 } 1828 } 1829 1830 public boolean getDeveloperExtrasEnabled() { 1831 lockPage(); 1832 try { 1833 boolean result = twkGetDeveloperExtrasEnabled(getPage()); 1834 log.log(Level.FINE, 1835 "Getting developerExtrasEnabled, result: [{0}]", 1836 result); 1837 return result; 1838 } finally { 1839 unlockPage(); 1840 } 1841 } 1842 1843 public void setDeveloperExtrasEnabled(boolean enabled) { 1844 lockPage(); 1845 try { 1846 log.log(Level.FINE, 1847 "Setting developerExtrasEnabled, value: [{0}]", 1848 enabled); 1849 twkSetDeveloperExtrasEnabled(getPage(), enabled); 1850 } finally { 1851 unlockPage(); 1852 } 1853 } 1854 1855 public boolean isJavaScriptEnabled() { 1856 lockPage(); 1857 try { 1858 return twkIsJavaScriptEnabled(getPage()); 1859 } finally { 1860 unlockPage(); 1861 } 1862 } 1863 1864 public void setJavaScriptEnabled(boolean enable) { 1865 lockPage(); 1866 try { 1867 twkSetJavaScriptEnabled(getPage(), enable); 1868 } finally { 1869 unlockPage(); 1870 } 1871 } 1872 1873 public boolean isContextMenuEnabled() { 1874 lockPage(); 1875 try { 1876 return twkIsContextMenuEnabled(getPage()); 1877 } finally { 1878 unlockPage(); 1879 } 1880 } 1881 1882 public void setContextMenuEnabled(boolean enable) { 1883 lockPage(); 1884 try { 1885 twkSetContextMenuEnabled(getPage(), enable); 1886 } finally { 1887 unlockPage(); 1888 } 1889 } 1890 1891 public void setUserStyleSheetLocation(String url) { 1892 lockPage(); 1893 try { 1894 twkSetUserStyleSheetLocation(getPage(), url); 1895 } finally { 1896 unlockPage(); 1897 } 1898 } 1899 1900 public String getUserAgent() { 1901 lockPage(); 1902 try { 1903 return twkGetUserAgent(getPage()); 1904 } finally { 1905 unlockPage(); 1906 } 1907 } 1908 1909 public void setUserAgent(String userAgent) { 1910 lockPage(); 1911 try { 1912 twkSetUserAgent(getPage(), userAgent); 1913 } finally { 1914 unlockPage(); 1915 } 1916 } 1917 1918 public void setLocalStorageDatabasePath(String path) { 1919 lockPage(); 1920 try { 1921 twkSetLocalStorageDatabasePath(getPage(), path); 1922 } finally { 1923 unlockPage(); 1924 } 1925 } 1926 1927 public void setLocalStorageEnabled(boolean enabled) { 1928 lockPage(); 1929 try { 1930 twkSetLocalStorageEnabled(getPage(), enabled); 1931 } finally { 1932 unlockPage(); 1933 } 1934 } 1935 1936 // ---- INSPECTOR SUPPORT ---- // 1937 1938 public void connectInspectorFrontend() { 1939 lockPage(); 1940 try { 1941 log.log(Level.FINE, "Connecting inspector frontend"); 1942 twkConnectInspectorFrontend(getPage()); 1943 } finally { 1944 unlockPage(); 1945 } 1946 } 1947 1948 public void disconnectInspectorFrontend() { 1949 lockPage(); 1950 try { 1951 log.log(Level.FINE, "Disconnecting inspector frontend"); 1952 twkDisconnectInspectorFrontend(getPage()); 1953 } finally { 1954 unlockPage(); 1955 } 1956 } 1957 1958 public void dispatchInspectorMessageFromFrontend(String message) { 1959 lockPage(); 1960 try { 1961 if (log.isLoggable(Level.FINE)) { 1962 log.log(Level.FINE, 1963 "Dispatching inspector message from frontend, " 1964 + "message: [{0}]", 1965 message); 1966 } 1967 twkDispatchInspectorMessageFromFrontend(getPage(), message); 1968 } finally { 1969 unlockPage(); 1970 } 1971 } 1972 1973 // ************************************************************************* 1974 // Native callbacks 1975 // ************************************************************************* 1976 1977 private void fwkFrameCreated(long frameID) { 1978 log.log(Level.FINE, "Frame created: frame = " + frameID); 1979 if (frames.contains(frameID)) { 1980 log.log(Level.FINE, "Error in fwkFrameCreated: frame is already in frames"); 1981 return; 1982 } 1983 frames.add(frameID); 1984 } 1985 1986 private void fwkFrameDestroyed(long frameID) { 1987 log.log(Level.FINE, "Frame destroyed: frame = " + frameID); 1988 if (!frames.contains(frameID)) { 1989 log.log(Level.FINE, "Error in fwkFrameDestroyed: frame is not found in frames"); 1990 return; 1991 } 1992 frames.remove(frameID); 1993 } 1994 1995 private void fwkRepaint(int x, int y, int w, int h) { 1996 lockPage(); 1997 try { 1998 if (paintLog.isLoggable(Level.FINEST)) { 1999 paintLog.log(Level.FINEST, "x: {0}, y: {1}, w: {2}, h: {3}", 2000 new Object[] {x, y, w, h}); 2001 } 2002 addDirtyRect(new WCRectangle(x, y, w, h)); 2003 } finally { 2004 unlockPage(); 2005 } 2006 } 2007 2008 private void fwkScroll(int x, int y, int w, int h, int deltaX, int deltaY) { 2009 if (paintLog.isLoggable(Level.FINEST)) { 2010 paintLog.finest("Scroll: " + x + " " + y + " " + w + " " + h + " " + deltaX + " " + deltaY); 2011 } 2012 if (pageClient == null || !pageClient.isBackBufferSupported()) { 2013 paintLog.finest("blit scrolling is switched off"); 2014 // TODO: check why we return void, not boolean (see ScrollView::m_canBlitOnScroll) 2015 return; 2016 } 2017 scroll(x, y, w, h, deltaX, deltaY); 2018 } 2019 2020 private void fwkTransferFocus(boolean forward) { 2021 log.log(Level.FINER, "Transfer focus " + (forward ? "forward" : "backward")); 2022 2023 if (pageClient != null) { 2024 pageClient.transferFocus(forward); 2025 } 2026 } 2027 2028 private void fwkSetCursor(long id) { 2029 log.log(Level.FINER, "Set cursor: " + id); 2030 2031 if (pageClient != null) { 2032 pageClient.setCursor(id); 2033 } 2034 } 2035 2036 private void fwkSetFocus(boolean focus) { 2037 log.log(Level.FINER, "Set focus: " + (focus ? "true" : "false")); 2038 2039 if (pageClient != null) { 2040 pageClient.setFocus(focus); 2041 } 2042 } 2043 2044 private void fwkSetTooltip(String tooltip) { 2045 log.log(Level.FINER, "Set tooltip: " + tooltip); 2046 2047 if (pageClient != null) { 2048 pageClient.setTooltip(tooltip); 2049 } 2050 } 2051 2052 private void fwkPrint() { 2053 log.log(Level.FINER, "Print"); 2054 2055 if (uiClient != null) { 2056 uiClient.print(); 2057 } 2058 } 2059 2060 private void fwkSetRequestURL(long pFrame, int id, String url) { 2061 log.log(Level.FINER, "Set request URL: id = " + id + ", url = " + url); 2062 2063 synchronized (requestURLs) { 2064 requestURLs.put(id, url); 2065 } 2066 } 2067 2068 private void fwkRemoveRequestURL(long pFrame, int id) { 2069 log.log(Level.FINER, "Set request URL: id = " + id); 2070 2071 synchronized (requestURLs) { 2072 requestURLs.remove(id); 2073 requestStarted.remove(id); 2074 } 2075 } 2076 2077 private WebPage fwkCreateWindow( 2078 boolean menu, boolean status, boolean toolbar, boolean resizable) { 2079 log.log(Level.FINER, "Create window"); 2080 2081 if (uiClient != null) { 2082 return uiClient.createPage(menu, status, toolbar, resizable); 2083 } 2084 return null; 2085 } 2086 2087 private void fwkShowWindow() { 2088 log.log(Level.FINER, "Show window"); 2089 2090 if (uiClient != null) { 2091 uiClient.showView(); 2092 } 2093 } 2094 2095 private void fwkCloseWindow() { 2096 log.log(Level.FINER, "Close window"); 2097 2098 if (permitCloseWindowAction()) { 2099 if (uiClient != null) { 2100 uiClient.closePage(); 2101 } 2102 } 2103 } 2104 2105 private WCRectangle fwkGetWindowBounds() { 2106 log.log(Level.FINE, "Get window bounds"); 2107 2108 if (uiClient != null) { 2109 WCRectangle bounds = uiClient.getViewBounds(); 2110 if (bounds != null) { 2111 return bounds; 2112 } 2113 } 2114 return fwkGetPageBounds(); 2115 } 2116 2117 private void fwkSetWindowBounds(int x, int y, int w, int h) { 2118 log.log(Level.FINER, "Set window bounds: " + x + " " + y + " " + w + " " + h); 2119 2120 if (uiClient != null) { 2121 uiClient.setViewBounds(new WCRectangle(x, y, w, h)); 2122 } 2123 } 2124 2125 private WCRectangle fwkGetPageBounds() { 2126 log.log(Level.FINER, "Get page bounds"); 2127 return new WCRectangle(0, 0, width, height); 2128 } 2129 2130 private void fwkSetScrollbarsVisible(boolean visible) { 2131 // TODO: handle this request internally 2132 } 2133 2134 private void fwkSetStatusbarText(String text) { 2135 log.log(Level.FINER, "Set statusbar text: " + text); 2136 2137 if (uiClient != null) { 2138 uiClient.setStatusbarText(text); 2139 } 2140 } 2141 2142 private String[] fwkChooseFile(String initialFileName, boolean multiple) { 2143 log.log(Level.FINER, "Choose file, initial=" + initialFileName); 2144 2145 return uiClient != null 2146 ? uiClient.chooseFile(initialFileName, multiple) 2147 : null; 2148 } 2149 2150 private void fwkStartDrag( 2151 Object image, 2152 int imageOffsetX, int imageOffsetY, 2153 int eventPosX, int eventPosY, 2154 String[] mimeTypes, 2155 Object[] values) 2156 { 2157 log.log(Level.FINER, "Start drag: "); 2158 2159 if (uiClient != null) { 2160 uiClient.startDrag( 2161 WCImage.getImage(image), 2162 imageOffsetX, imageOffsetY, 2163 eventPosX, eventPosY, 2164 mimeTypes, 2165 values); 2166 } 2167 } 2168 2169 private WCPoint fwkScreenToWindow(WCPoint ptScreen) { 2170 log.log(Level.FINER, "fwkScreenToWindow"); 2171 2172 if (pageClient != null) { 2173 return pageClient.screenToWindow(ptScreen); 2174 } 2175 return ptScreen; 2176 } 2177 2178 private WCPoint fwkWindowToScreen(WCPoint ptWindow) { 2179 log.log(Level.FINER, "fwkWindowToScreen"); 2180 2181 if (pageClient != null) { 2182 return pageClient.windowToScreen(ptWindow); 2183 } 2184 return ptWindow; 2185 } 2186 2187 2188 private void fwkAlert(String text) { 2189 log.log(Level.FINE, "JavaScript alert(): text = " + text); 2190 2191 if (uiClient != null) { 2192 uiClient.alert(text); 2193 } 2194 } 2195 2196 private boolean fwkConfirm(String text) { 2197 log.log(Level.FINE, "JavaScript confirm(): text = " + text); 2198 2199 if (uiClient != null) { 2200 return uiClient.confirm(text); 2201 } 2202 return false; 2203 } 2204 2205 private String fwkPrompt(String text, String defaultValue) { 2206 log.log(Level.FINE, "JavaScript prompt(): text = " + text + ", default = " + defaultValue); 2207 2208 if (uiClient != null) { 2209 return uiClient.prompt(text, defaultValue); 2210 } 2211 return null; 2212 } 2213 2214 private void fwkAddMessageToConsole(String message, int lineNumber, 2215 String sourceId) 2216 { 2217 log.log(Level.FINE, "fwkAddMessageToConsole(): message = " + message 2218 + ", lineNumber = " + lineNumber + ", sourceId = " + sourceId); 2219 if (pageClient != null) { 2220 pageClient.addMessageToConsole(message, lineNumber, sourceId); 2221 } 2222 } 2223 2224 private void fwkFireLoadEvent(long frameID, int state, 2225 String url, String contentType, 2226 double progress, int errorCode) 2227 { 2228 log.log(Level.FINER, "Load event: pFrame = " + frameID + ", state = " + state + 2229 ", url = " + url + ", contenttype=" + contentType + 2230 ", progress = " + progress + ", error = " + errorCode); 2231 2232 fireLoadEvent(frameID, state, url, contentType, progress, errorCode); 2233 } 2234 2235 private void fwkFireResourceLoadEvent(long frameID, int state, 2236 int id, String contentType, 2237 double progress, int errorCode) 2238 { 2239 log.log(Level.FINER, "Resource load event: pFrame = " + frameID + ", state = " + state + 2240 ", id = " + id + ", contenttype=" + contentType + 2241 ", progress = " + progress + ", error = " + errorCode); 2242 2243 String url = requestURLs.get(id); 2244 if (url == null) { 2245 log.log(Level.FINE, "Error in fwkFireResourceLoadEvent: unknown request id " + id); 2246 return; 2247 } 2248 2249 int eventState = state; 2250 // convert second and all subsequent STARTED into REDIRECTED 2251 if (state == LoadListenerClient.RESOURCE_STARTED) { 2252 if (requestStarted.contains(id)) { 2253 eventState = LoadListenerClient.RESOURCE_REDIRECTED; 2254 } else { 2255 requestStarted.add(id); 2256 } 2257 } 2258 2259 fireResourceLoadEvent(frameID, eventState, url, contentType, progress, errorCode); 2260 } 2261 2262 private boolean fwkPermitNavigateAction(long pFrame, String url) { 2263 log.log(Level.FINE, "Policy: permit NAVIGATE: pFrame = " + pFrame + ", url = " + url); 2264 2265 if (policyClient != null) { 2266 return policyClient.permitNavigateAction(pFrame, str2url(url)); 2267 } 2268 return true; 2269 } 2270 2271 private boolean fwkPermitRedirectAction(long pFrame, String url) { 2272 log.log(Level.FINE, "Policy: permit REDIRECT: pFrame = " + pFrame + ", url = " + url); 2273 2274 if (policyClient != null) { 2275 return policyClient.permitRedirectAction(pFrame, str2url(url)); 2276 } 2277 return true; 2278 } 2279 2280 private boolean fwkPermitAcceptResourceAction(long pFrame, String url) { 2281 log.log(Level.FINE, "Policy: permit ACCEPT_RESOURCE: pFrame + " + pFrame + ", url = " + url); 2282 2283 if (policyClient != null) { 2284 return policyClient.permitAcceptResourceAction(pFrame, str2url(url)); 2285 } 2286 return true; 2287 } 2288 2289 private boolean fwkPermitSubmitDataAction(long pFrame, String url, 2290 String httpMethod, boolean isSubmit) 2291 { 2292 log.log(Level.FINE, "Policy: permit " + (isSubmit ? "" : "RE") + "SUBMIT_DATA: pFrame = " + 2293 pFrame + ", url = " + url + ", httpMethod = " + httpMethod); 2294 2295 if (policyClient != null) { 2296 if (isSubmit) { 2297 return policyClient.permitSubmitDataAction(pFrame, str2url(url), httpMethod); 2298 } else { 2299 return policyClient.permitResubmitDataAction(pFrame, str2url(url), httpMethod); 2300 } 2301 } 2302 return true; 2303 } 2304 2305 private boolean fwkPermitEnableScriptsAction(long pFrame, String url) { 2306 log.log(Level.FINE, "Policy: permit ENABLE_SCRIPTS: pFrame + " + pFrame + ", url = " + url); 2307 2308 if (policyClient != null) { 2309 return policyClient.permitEnableScriptsAction(pFrame, str2url(url)); 2310 } 2311 return true; 2312 } 2313 2314 private boolean fwkPermitNewWindowAction(long pFrame, String url) { 2315 log.log(Level.FINE, "Policy: permit NEW_PAGE: pFrame = " + pFrame + ", url = " + url); 2316 2317 if (policyClient != null) { 2318 return policyClient.permitNewPageAction(pFrame, str2url(url)); 2319 } 2320 return true; 2321 } 2322 2323 // Called from fwkCloseWindow, that's why no "fwk" prefix 2324 private boolean permitCloseWindowAction() { 2325 log.log(Level.FINE, "Policy: permit CLOSE_PAGE"); 2326 2327 if (policyClient != null) { 2328 // Unfortunately, webkit doesn't provide an information about what 2329 // web frame initiated close window request, so using main frame here 2330 return policyClient.permitClosePageAction(getMainFrame()); 2331 } 2332 return true; 2333 } 2334 2335 private void fwkRepaintAll() { 2336 log.log(Level.FINE, "Repainting the entire page"); 2337 repaintAll(); 2338 } 2339 2340 private boolean fwkSendInspectorMessageToFrontend(String message) { 2341 if (log.isLoggable(Level.FINE)) { 2342 log.log(Level.FINE, 2343 "Sending inspector message to frontend, message: [{0}]", 2344 message); 2345 } 2346 boolean result = false; 2347 if (inspectorClient != null) { 2348 log.log(Level.FINE, "Invoking inspector client"); 2349 result = inspectorClient.sendMessageToFrontend(message); 2350 } 2351 if (log.isLoggable(Level.FINE)) { 2352 log.log(Level.FINE, "Result: [{0}]", result); 2353 } 2354 return result; 2355 } 2356 2357 // ---- DumpRenderTree support ---- // 2358 2359 public static int getWorkerThreadCount() { 2360 return twkWorkerThreadCount(); 2361 } 2362 2363 private static native int twkWorkerThreadCount(); 2364 2365 private void fwkDidClearWindowObject(long pContext, long pWindowObject) { 2366 if (pageClient != null) { 2367 pageClient.didClearWindowObject(pContext, pWindowObject); 2368 } 2369 } 2370 2371 // ************************************************************************* 2372 // Private methods 2373 // ************************************************************************* 2374 2375 private URL str2url(String url) { 2376 try { 2377 return newURL(url); 2378 } catch (MalformedURLException ex) { 2379 log.log(Level.FINE, "Exception while converting \"" + url + "\" to URL", ex); 2380 } 2381 return null; 2382 } 2383 2384 private void fireLoadEvent(long frameID, int state, String url, 2385 String contentType, double progress, int errorCode) 2386 { 2387 for (LoadListenerClient l : loadListenerClients) { 2388 l.dispatchLoadEvent(frameID, state, url, contentType, progress, errorCode); 2389 } 2390 } 2391 2392 private void fireResourceLoadEvent(long frameID, int state, String url, 2393 String contentType, double progress, int errorCode) 2394 { 2395 for (LoadListenerClient l : loadListenerClients) { 2396 l.dispatchResourceLoadEvent(frameID, state, url, contentType, progress, errorCode); 2397 } 2398 } 2399 2400 private void repaintAll() { 2401 dirtyRects.clear(); 2402 addDirtyRect(new WCRectangle(0, 0, width, height)); 2403 } 2404 2405 // ************************************************************************* 2406 // Native methods 2407 // ************************************************************************* 2408 2409 private native long twkCreatePage(boolean editable); 2410 private native void twkInit(long pPage, boolean usePlugins); 2411 private native void twkDestroyPage(long pPage); 2412 2413 private native long twkGetMainFrame(long pPage); 2414 private native long twkGetParentFrame(long pFrame); 2415 private native long[] twkGetChildFrames(long pFrame); 2416 2417 private native String twkGetName(long pFrame); 2418 private native String twkGetURL(long pFrame); 2419 private native String twkGetInnerText(long pFrame); 2420 private native String twkGetRenderTree(long pFrame); 2421 private native String twkGetContentType(long pFrame); 2422 private native String twkGetTitle(long pFrame); 2423 private native String twkGetIconURL(long pFrame); 2424 private native static Document twkGetDocument(long pFrame); 2425 private native static Element twkGetOwnerElement(long pFrame); 2426 2427 private native void twkOpen(long pFrame, String url); 2428 private native void twkLoad(long pFrame, String text, String contentType); 2429 private native void twkStop(long pFrame); 2430 private native void twkStopAll(long pPage); // sync 2431 private native void twkRefresh(long pFrame); 2432 2433 private native boolean twkGoBackForward(long pPage, int distance); 2434 2435 private native boolean twkCopy(long pFrame); 2436 private native boolean twkFindInPage(long pPage, 2437 String stringToFind, boolean forward, 2438 boolean wrap, boolean matchCase); 2439 private native boolean twkFindInFrame(long pFrame, 2440 String stringToFind, boolean forward, 2441 boolean wrap, boolean matchCase); 2442 2443 private native float twkGetZoomFactor(long pFrame, boolean textOnly); 2444 private native void twkSetZoomFactor(long pFrame, float zoomFactor, boolean textOnly); 2445 2446 private native Object twkExecuteScript(long pFrame, String script); 2447 2448 private native void twkReset(long pFrame); 2449 2450 private native int twkGetFrameHeight(long pFrame); 2451 private native int twkBeginPrinting(long pPage, float width, float height); 2452 private native void twkEndPrinting(long pPage); 2453 private native void twkPrint(long pPage, WCRenderQueue gc, int pageNumber, float width); 2454 private native float twkAdjustFrameHeight(long pFrame, float oldTop, float oldBottom, float bottomLimit); 2455 2456 private native int[] twkGetVisibleRect(long pFrame); 2457 private native void twkScrollToPosition(long pFrame, int x, int y); 2458 private native int[] twkGetContentSize(long pFrame); 2459 private native void twkSetTransparent(long pFrame, boolean isTransparent); 2460 private native void twkSetBackgroundColor(long pFrame, int backgroundColor); 2461 2462 private native void twkSetBounds(long pPage, int x, int y, int w, int h); 2463 private native void twkPrePaint(long pPage); 2464 private native void twkUpdateContent(long pPage, WCRenderQueue rq, int x, int y, int w, int h); 2465 private native void twkPostPaint(long pPage, WCRenderQueue rq, 2466 int x, int y, int w, int h); 2467 2468 private native String twkGetEncoding(long pPage); 2469 private native void twkSetEncoding(long pPage, String encoding); 2470 2471 private native void twkProcessFocusEvent(long pPage, int id, int direction); 2472 private native boolean twkProcessKeyEvent(long pPage, int type, String text, 2473 String keyIdentifier, 2474 int windowsVirtualKeyCode, 2475 boolean shift, boolean ctrl, 2476 boolean alt, boolean meta); 2477 private native boolean twkProcessMouseEvent(long pPage, int id, 2478 int button, int clickCount, 2479 int x, int y, int sx, int sy, 2480 boolean shift, boolean control, boolean alt, boolean meta, 2481 boolean popupTrigger, float when); 2482 private native boolean twkProcessMouseWheelEvent(long pPage, 2483 int x, int y, int sx, int sy, 2484 float dx, float dy, 2485 boolean shift, boolean control, boolean alt, boolean meta, 2486 float when); 2487 private native boolean twkProcessInputTextChange(long pPage, String committed, String composed, 2488 int[] attributes, int caretPosition); 2489 private native boolean twkProcessCaretPositionChange(long pPage, int caretPosition); 2490 private native int[] twkGetTextLocation(long pPage, int charIndex); 2491 private native int twkGetInsertPositionOffset(long pPage); 2492 private native int twkGetCommittedTextLength(long pPage); 2493 private native String twkGetCommittedText(long pPage); 2494 private native String twkGetSelectedText(long pPage); 2495 2496 private native int twkProcessDrag(long page, 2497 int commandId, 2498 String[] mimeTypes, String[] values, 2499 int x, int y, 2500 int screenX, int screenY, 2501 int dndActionId); 2502 2503 private native boolean twkExecuteCommand(long page, String command, 2504 String value); 2505 private native boolean twkQueryCommandEnabled(long page, String command); 2506 private native boolean twkQueryCommandState(long page, String command); 2507 private native String twkQueryCommandValue(long page, String command); 2508 private native boolean twkIsEditable(long page); 2509 private native void twkSetEditable(long page, boolean editable); 2510 private native String twkGetHtml(long pFrame); 2511 2512 private native boolean twkGetUsePageCache(long page); 2513 private native void twkSetUsePageCache(long page, boolean usePageCache); 2514 private native boolean twkGetDeveloperExtrasEnabled(long page); 2515 private native void twkSetDeveloperExtrasEnabled(long page, 2516 boolean enabled); 2517 private native boolean twkIsJavaScriptEnabled(long page); 2518 private native void twkSetJavaScriptEnabled(long page, boolean enable); 2519 private native boolean twkIsContextMenuEnabled(long page); 2520 private native void twkSetContextMenuEnabled(long page, boolean enable); 2521 private native void twkSetUserStyleSheetLocation(long page, String url); 2522 private native String twkGetUserAgent(long page); 2523 private native void twkSetUserAgent(long page, String userAgent); 2524 private native void twkSetLocalStorageDatabasePath(long page, String path); 2525 private native void twkSetLocalStorageEnabled(long page, boolean enabled); 2526 2527 private native int twkGetUnloadEventListenersCount(long pFrame); 2528 2529 private native void twkConnectInspectorFrontend(long pPage); 2530 private native void twkDisconnectInspectorFrontend(long pPage); 2531 private native void twkDispatchInspectorMessageFromFrontend(long pPage, 2532 String message); 2533 }