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