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