WebViewCore.java revision 74008f608af0c567456d37e63d48643689388c74
1/* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.webkit; 18 19import android.content.Context; 20import android.graphics.Canvas; 21import android.graphics.DrawFilter; 22import android.graphics.Paint; 23import android.graphics.PaintFlagsDrawFilter; 24import android.graphics.Picture; 25import android.graphics.Point; 26import android.graphics.Rect; 27import android.graphics.Region; 28import android.os.Handler; 29import android.os.Looper; 30import android.os.Message; 31import android.os.Process; 32import android.util.Log; 33import android.util.SparseBooleanArray; 34import android.view.KeyEvent; 35 36import java.util.ArrayList; 37import java.util.HashMap; 38 39import junit.framework.Assert; 40 41final class WebViewCore { 42 43 private static final String LOGTAG = "webcore"; 44 static final boolean DEBUG = false; 45 static final boolean LOGV_ENABLED = DEBUG; 46 47 static { 48 // Load libwebcore during static initialization. This happens in the 49 // zygote process so it will be shared read-only across all app 50 // processes. 51 System.loadLibrary("webcore"); 52 } 53 54 /* 55 * WebViewCore always executes in the same thread as the native webkit. 56 */ 57 58 // The WebView that corresponds to this WebViewCore. 59 private WebView mWebView; 60 // Proxy for handling callbacks from native code 61 private final CallbackProxy mCallbackProxy; 62 // Settings object for maintaining all settings 63 private final WebSettings mSettings; 64 // Context for initializing the BrowserFrame with the proper assets. 65 private final Context mContext; 66 // The pointer to a native view object. 67 private int mNativeClass; 68 // The BrowserFrame is an interface to the native Frame component. 69 private BrowserFrame mBrowserFrame; 70 71 /* 72 * range is from 200 to 10,000. 0 is a special value means device-width. -1 73 * means undefined. 74 */ 75 private int mViewportWidth = -1; 76 77 /* 78 * range is from 200 to 10,000. 0 is a special value means device-height. -1 79 * means undefined. 80 */ 81 private int mViewportHeight = -1; 82 83 /* 84 * scale in percent, range is from 1 to 1000. 0 means undefined. 85 */ 86 private int mViewportInitialScale = 0; 87 88 /* 89 * scale in percent, range is from 1 to 1000. 0 means undefined. 90 */ 91 private int mViewportMinimumScale = 0; 92 93 /* 94 * scale in percent, range is from 1 to 1000. 0 means undefined. 95 */ 96 private int mViewportMaximumScale = 0; 97 98 private boolean mViewportUserScalable = true; 99 100 private int mRestoredScale = 100; 101 private int mRestoredX = 0; 102 private int mRestoredY = 0; 103 104 private int mWebkitScrollX = 0; 105 private int mWebkitScrollY = 0; 106 107 // The thread name used to identify the WebCore thread and for use in 108 // debugging other classes that require operation within the WebCore thread. 109 /* package */ static final String THREAD_NAME = "WebViewCoreThread"; 110 111 public WebViewCore(Context context, WebView w, CallbackProxy proxy) { 112 // No need to assign this in the WebCore thread. 113 mCallbackProxy = proxy; 114 mWebView = w; 115 // This context object is used to initialize the WebViewCore during 116 // subwindow creation. 117 mContext = context; 118 119 // We need to wait for the initial thread creation before sending 120 // a message to the WebCore thread. 121 // XXX: This is the only time the UI thread will wait for the WebCore 122 // thread! 123 synchronized (WebViewCore.class) { 124 if (sWebCoreHandler == null) { 125 // Create a global thread and start it. 126 Thread t = new Thread(new WebCoreThread()); 127 t.setName(THREAD_NAME); 128 t.start(); 129 try { 130 WebViewCore.class.wait(); 131 } catch (InterruptedException e) { 132 Log.e(LOGTAG, "Caught exception while waiting for thread " + 133 "creation."); 134 Log.e(LOGTAG, Log.getStackTraceString(e)); 135 } 136 } 137 } 138 // Create an EventHub to handle messages before and after the thread is 139 // ready. 140 mEventHub = new EventHub(); 141 // Create a WebSettings object for maintaining all settings 142 mSettings = new WebSettings(mContext); 143 // The WebIconDatabase needs to be initialized within the UI thread so 144 // just request the instance here. 145 WebIconDatabase.getInstance(); 146 // Send a message to initialize the WebViewCore. 147 Message init = sWebCoreHandler.obtainMessage( 148 WebCoreThread.INITIALIZE, this); 149 sWebCoreHandler.sendMessage(init); 150 } 151 152 /* Initialize private data within the WebCore thread. 153 */ 154 private void initialize() { 155 /* Initialize our private BrowserFrame class to handle all 156 * frame-related functions. We need to create a new view which 157 * in turn creates a C level FrameView and attaches it to the frame. 158 */ 159 mBrowserFrame = new BrowserFrame(mContext, this, mCallbackProxy, 160 mSettings); 161 // Sync the native settings and also create the WebCore thread handler. 162 mSettings.syncSettingsAndCreateHandler(mBrowserFrame); 163 // Create the handler and transfer messages for the IconDatabase 164 WebIconDatabase.getInstance().createHandler(); 165 // The transferMessages call will transfer all pending messages to the 166 // WebCore thread handler. 167 mEventHub.transferMessages(); 168 169 // Send a message back to WebView to tell it that we have set up the 170 // WebCore thread. 171 if (mWebView != null) { 172 Message.obtain(mWebView.mPrivateHandler, 173 WebView.WEBCORE_INITIALIZED_MSG_ID, 174 mNativeClass, 0).sendToTarget(); 175 } 176 177 } 178 179 /* Handle the initialization of WebViewCore during subwindow creation. This 180 * method is called from the WebCore thread but it is called before the 181 * INITIALIZE message can be handled. 182 */ 183 /* package */ void initializeSubwindow() { 184 // Go ahead and initialize the core components. 185 initialize(); 186 // Remove the INITIALIZE method so we don't try to initialize twice. 187 sWebCoreHandler.removeMessages(WebCoreThread.INITIALIZE, this); 188 } 189 190 /* Get the BrowserFrame component. This is used for subwindow creation and 191 * is called only from BrowserFrame in the WebCore thread. */ 192 /* package */ BrowserFrame getBrowserFrame() { 193 return mBrowserFrame; 194 } 195 196 //------------------------------------------------------------------------- 197 // Common methods 198 //------------------------------------------------------------------------- 199 200 /** 201 * Causes all timers to pause. This applies to all WebViews in the current 202 * app process. 203 */ 204 public static void pauseTimers() { 205 if (BrowserFrame.sJavaBridge == null) { 206 throw new IllegalStateException( 207 "No WebView has been created in this process!"); 208 } 209 BrowserFrame.sJavaBridge.pause(); 210 } 211 212 /** 213 * Resume all timers. This applies to all WebViews in the current process. 214 */ 215 public static void resumeTimers() { 216 if (BrowserFrame.sJavaBridge == null) { 217 throw new IllegalStateException( 218 "No WebView has been created in this process!"); 219 } 220 BrowserFrame.sJavaBridge.resume(); 221 } 222 223 public WebSettings getSettings() { 224 return mSettings; 225 } 226 227 /** 228 * Invoke a javascript alert. 229 * @param message The message displayed in the alert. 230 */ 231 protected void jsAlert(String url, String message) { 232 mCallbackProxy.onJsAlert(url, message); 233 } 234 235 /** 236 * Invoke a javascript confirm dialog. 237 * @param message The message displayed in the dialog. 238 * @return True if the user confirmed or false if the user cancelled. 239 */ 240 protected boolean jsConfirm(String url, String message) { 241 return mCallbackProxy.onJsConfirm(url, message); 242 } 243 244 /** 245 * Invoke a javascript prompt dialog. 246 * @param message The message to be displayed in the dialog. 247 * @param defaultValue The default value in the prompt input. 248 * @return The input from the user or null to indicate the user cancelled 249 * the dialog. 250 */ 251 protected String jsPrompt(String url, String message, String defaultValue) { 252 return mCallbackProxy.onJsPrompt(url, message, defaultValue); 253 } 254 255 /** 256 * Invoke a javascript before unload dialog. 257 * @param url The url that is requesting the dialog. 258 * @param message The message displayed in the dialog. 259 * @return True if the user confirmed or false if the user cancelled. False 260 * will cancel the navigation. 261 */ 262 protected boolean jsUnload(String url, String message) { 263 return mCallbackProxy.onJsBeforeUnload(url, message); 264 } 265 266 //------------------------------------------------------------------------- 267 // JNI methods 268 //------------------------------------------------------------------------- 269 270 static native String nativeFindAddress(String addr); 271 272 /** 273 * Empty the picture set. 274 */ 275 private native void nativeClearContent(); 276 277 /** 278 * Create a flat picture from the set of pictures. 279 */ 280 private native void nativeCopyContentToPicture(Picture picture); 281 282 /** 283 * Draw the picture set with a background color. Returns true 284 * if some individual picture took too long to draw and can be 285 * split into parts. Called from the UI thread. 286 */ 287 private native boolean nativeDrawContent(Canvas canvas, int color); 288 289 /** 290 * Redraw a portion of the picture set. The Point wh returns the 291 * width and height of the overall picture. 292 */ 293 private native boolean nativeRecordContent(Region invalRegion, Point wh); 294 295 /** 296 * Splits slow parts of the picture set. Called from the webkit 297 * thread after nativeDrawContent returns true. 298 */ 299 private native void nativeSplitContent(); 300 301 private native boolean nativeKey(int keyCode, int unichar, 302 int repeatCount, boolean isShift, boolean isAlt, boolean isDown); 303 304 private native boolean nativeClick(); 305 306 private native void nativeSendListBoxChoices(boolean[] choices, int size); 307 308 private native void nativeSendListBoxChoice(int choice); 309 310 /* Tell webkit what its width and height are, for the purposes 311 of layout/line-breaking. These coordinates are in document space, 312 which is the same as View coords unless we have zoomed the document 313 (see nativeSetZoom). 314 screenWidth is used by layout to wrap column around. If viewport uses 315 fixed size, screenWidth can be different from width with zooming. 316 should this be called nativeSetViewPortSize? 317 */ 318 private native void nativeSetSize(int width, int height, int screenWidth, 319 float scale, int realScreenWidth, int screenHeight); 320 321 private native int nativeGetContentMinPrefWidth(); 322 323 // Start: functions that deal with text editing 324 private native void nativeReplaceTextfieldText(int frame, int node, int x, 325 int y, int oldStart, int oldEnd, String replace, int newStart, 326 int newEnd); 327 328 private native void passToJs(int frame, int node, int x, int y, int gen, 329 String currentText, int keyCode, int keyValue, boolean down, 330 boolean cap, boolean fn, boolean sym); 331 332 private native void nativeSetFocusControllerActive(boolean active); 333 334 private native void nativeSaveDocumentState(int frame); 335 336 private native void nativeSetFinalFocus(int framePtr, int nodePtr, int x, 337 int y, boolean block); 338 339 private native void nativeSetKitFocus(int moveGeneration, 340 int buildGeneration, int framePtr, int nodePtr, int x, int y, 341 boolean ignoreNullFocus); 342 343 private native String nativeRetrieveHref(int framePtr, int nodePtr); 344 345 private native void nativeTouchUp(int touchGeneration, 346 int buildGeneration, int framePtr, int nodePtr, int x, int y, 347 int size, boolean isClick, boolean retry); 348 349 private native boolean nativeHandleTouchEvent(int action, int x, int y); 350 351 private native void nativeUnblockFocus(); 352 353 private native void nativeUpdateFrameCache(); 354 355 private native void nativeSetSnapAnchor(int x, int y); 356 357 private native void nativeSnapToAnchor(); 358 359 private native void nativeSetBackgroundColor(int color); 360 361 private native void nativeDumpDomTree(boolean useFile); 362 363 private native void nativeDumpRenderTree(boolean useFile); 364 365 private native void nativeDumpNavTree(); 366 367 private native void nativeRefreshPlugins(boolean reloadOpenPages); 368 369 /** 370 * Delete text from start to end in the focused textfield. If there is no 371 * focus, or if start == end, silently fail. If start and end are out of 372 * order, swap them. 373 * @param start Beginning of selection to delete. 374 * @param end End of selection to delete. 375 */ 376 private native void nativeDeleteSelection(int frame, int node, int x, int y, 377 int start, int end); 378 379 /** 380 * Set the selection to (start, end) in the focused textfield. If start and 381 * end are out of order, swap them. 382 * @param start Beginning of selection. 383 * @param end End of selection. 384 */ 385 private native void nativeSetSelection(int frame, int node, int x, int y, 386 int start, int end); 387 388 private native String nativeGetSelection(Region sel); 389 390 // Register a scheme to be treated as local scheme so that it can access 391 // local asset files for resources 392 private native void nativeRegisterURLSchemeAsLocal(String scheme); 393 394 // EventHub for processing messages 395 private final EventHub mEventHub; 396 // WebCore thread handler 397 private static Handler sWebCoreHandler; 398 // Class for providing Handler creation inside the WebCore thread. 399 private static class WebCoreThread implements Runnable { 400 // Message id for initializing a new WebViewCore. 401 private static final int INITIALIZE = 0; 402 private static final int REDUCE_PRIORITY = 1; 403 private static final int RESUME_PRIORITY = 2; 404 private static final int CACHE_TICKER = 3; 405 private static final int BLOCK_CACHE_TICKER = 4; 406 private static final int RESUME_CACHE_TICKER = 5; 407 408 private static final int CACHE_TICKER_INTERVAL = 60 * 1000; // 1 minute 409 410 private static boolean mCacheTickersBlocked = true; 411 412 public void run() { 413 Looper.prepare(); 414 Assert.assertNull(sWebCoreHandler); 415 synchronized (WebViewCore.class) { 416 sWebCoreHandler = new Handler() { 417 @Override 418 public void handleMessage(Message msg) { 419 switch (msg.what) { 420 case INITIALIZE: 421 WebViewCore core = (WebViewCore) msg.obj; 422 core.initialize(); 423 break; 424 425 case REDUCE_PRIORITY: 426 // 3 is an adjustable number. 427 Process.setThreadPriority( 428 Process.THREAD_PRIORITY_DEFAULT + 3 * 429 Process.THREAD_PRIORITY_LESS_FAVORABLE); 430 break; 431 432 case RESUME_PRIORITY: 433 Process.setThreadPriority( 434 Process.THREAD_PRIORITY_DEFAULT); 435 break; 436 437 case CACHE_TICKER: 438 if (!mCacheTickersBlocked) { 439 CacheManager.endCacheTransaction(); 440 CacheManager.startCacheTransaction(); 441 sendMessageDelayed( 442 obtainMessage(CACHE_TICKER), 443 CACHE_TICKER_INTERVAL); 444 } 445 break; 446 447 case BLOCK_CACHE_TICKER: 448 if (CacheManager.endCacheTransaction()) { 449 mCacheTickersBlocked = true; 450 } 451 break; 452 453 case RESUME_CACHE_TICKER: 454 if (CacheManager.startCacheTransaction()) { 455 mCacheTickersBlocked = false; 456 } 457 break; 458 } 459 } 460 }; 461 WebViewCore.class.notify(); 462 } 463 Looper.loop(); 464 } 465 } 466 467 static class FocusData { 468 FocusData() {} 469 FocusData(FocusData d) { 470 mMoveGeneration = d.mMoveGeneration; 471 mBuildGeneration = d.mBuildGeneration; 472 mFrame = d.mFrame; 473 mNode = d.mNode; 474 mX = d.mX; 475 mY = d.mY; 476 mIgnoreNullFocus = d.mIgnoreNullFocus; 477 } 478 int mMoveGeneration; 479 int mBuildGeneration; 480 int mFrame; 481 int mNode; 482 int mX; 483 int mY; 484 boolean mIgnoreNullFocus; 485 } 486 487 static class TouchUpData { 488 int mMoveGeneration; 489 int mBuildGeneration; 490 int mFrame; 491 int mNode; 492 int mX; 493 int mY; 494 int mSize; 495 boolean mIsClick; 496 boolean mRetry; 497 } 498 499 static class TouchEventData { 500 int mAction; // MotionEvent.getAction() 501 int mX; 502 int mY; 503 } 504 505 static final String[] HandlerDebugString = { 506 "LOAD_URL", // = 100; 507 "STOP_LOADING", // = 101; 508 "RELOAD", // = 102; 509 "KEY_DOWN", // = 103; 510 "KEY_UP", // = 104; 511 "VIEW_SIZE_CHANGED", // = 105; 512 "GO_BACK_FORWARD", // = 106; 513 "SET_SCROLL_OFFSET", // = 107; 514 "RESTORE_STATE", // = 108; 515 "PAUSE_TIMERS", // = 109; 516 "RESUME_TIMERS", // = 110; 517 "CLEAR_CACHE", // = 111; 518 "CLEAR_HISTORY", // = 112; 519 "SET_SELECTION", // = 113; 520 "REPLACE_TEXT", // = 114; 521 "PASS_TO_JS", // = 115; 522 "SET_GLOBAL_BOUNDS", // = 116; 523 "UPDATE_CACHE_AND_TEXT_ENTRY", // = 117; 524 "CLICK", // = 118; 525 "SET_NETWORK_STATE", // = 119; 526 "DOC_HAS_IMAGES", // = 120; 527 "SET_SNAP_ANCHOR", // = 121; 528 "DELETE_SELECTION", // = 122; 529 "LISTBOX_CHOICES", // = 123; 530 "SINGLE_LISTBOX_CHOICE", // = 124; 531 "MESSAGE_RELAY", // = 125; 532 "SET_BACKGROUND_COLOR", // = 126; 533 "UNBLOCK_FOCUS", // = 127; 534 "SAVE_DOCUMENT_STATE", // = 128; 535 "GET_SELECTION", // = 129; 536 "WEBKIT_DRAW", // = 130; 537 "SYNC_SCROLL", // = 131; 538 "REFRESH_PLUGINS", // = 132; 539 "SPLIT_PICTURE_SET", // = 133; 540 "CLEAR_CONTENT", // = 134; 541 "SET_FINAL_FOCUS", // = 135; 542 "SET_KIT_FOCUS", // = 136; 543 "REQUEST_FOCUS_HREF", // = 137; 544 "ADD_JS_INTERFACE", // = 138; 545 "LOAD_DATA", // = 139; 546 "TOUCH_UP", // = 140; 547 "TOUCH_EVENT", // = 141; 548 }; 549 550 class EventHub { 551 // Message Ids 552 static final int LOAD_URL = 100; 553 static final int STOP_LOADING = 101; 554 static final int RELOAD = 102; 555 static final int KEY_DOWN = 103; 556 static final int KEY_UP = 104; 557 static final int VIEW_SIZE_CHANGED = 105; 558 static final int GO_BACK_FORWARD = 106; 559 static final int SET_SCROLL_OFFSET = 107; 560 static final int RESTORE_STATE = 108; 561 static final int PAUSE_TIMERS = 109; 562 static final int RESUME_TIMERS = 110; 563 static final int CLEAR_CACHE = 111; 564 static final int CLEAR_HISTORY = 112; 565 static final int SET_SELECTION = 113; 566 static final int REPLACE_TEXT = 114; 567 static final int PASS_TO_JS = 115; 568 static final int SET_GLOBAL_BOUNDS = 116; 569 static final int UPDATE_CACHE_AND_TEXT_ENTRY = 117; 570 static final int CLICK = 118; 571 static final int SET_NETWORK_STATE = 119; 572 static final int DOC_HAS_IMAGES = 120; 573 static final int SET_SNAP_ANCHOR = 121; 574 static final int DELETE_SELECTION = 122; 575 static final int LISTBOX_CHOICES = 123; 576 static final int SINGLE_LISTBOX_CHOICE = 124; 577 static final int MESSAGE_RELAY = 125; 578 static final int SET_BACKGROUND_COLOR = 126; 579 static final int UNBLOCK_FOCUS = 127; 580 static final int SAVE_DOCUMENT_STATE = 128; 581 static final int GET_SELECTION = 129; 582 static final int WEBKIT_DRAW = 130; 583 static final int SYNC_SCROLL = 131; 584 static final int REFRESH_PLUGINS = 132; 585 static final int SPLIT_PICTURE_SET = 133; 586 static final int CLEAR_CONTENT = 134; 587 588 // UI nav messages 589 static final int SET_FINAL_FOCUS = 135; 590 static final int SET_KIT_FOCUS = 136; 591 static final int REQUEST_FOCUS_HREF = 137; 592 static final int ADD_JS_INTERFACE = 138; 593 static final int LOAD_DATA = 139; 594 595 // motion 596 static final int TOUCH_UP = 140; 597 // message used to pass UI touch events to WebCore 598 static final int TOUCH_EVENT = 141; 599 600 // Used to tell the focus controller whether to draw the blinking cursor 601 // or not, based on whether the WebView has focus. 602 static final int SET_ACTIVE = 142; 603 604 // Network-based messaging 605 static final int CLEAR_SSL_PREF_TABLE = 150; 606 607 // Test harness messages 608 static final int REQUEST_EXT_REPRESENTATION = 160; 609 static final int REQUEST_DOC_AS_TEXT = 161; 610 611 // debugging 612 static final int DUMP_DOMTREE = 170; 613 static final int DUMP_RENDERTREE = 171; 614 static final int DUMP_NAVTREE = 172; 615 616 // private message ids 617 private static final int DESTROY = 200; 618 619 // flag values passed to message SET_FINAL_FOCUS 620 static final int NO_FOCUS_CHANGE_BLOCK = 0; 621 static final int BLOCK_FOCUS_CHANGE_UNTIL_KEY_UP = 1; 622 623 // Private handler for WebCore messages. 624 private Handler mHandler; 625 // Message queue for containing messages before the WebCore thread is 626 // ready. 627 private ArrayList<Message> mMessages = new ArrayList<Message>(); 628 // Flag for blocking messages. This is used during DESTROY to avoid 629 // posting more messages to the EventHub or to WebView's event handler. 630 private boolean mBlockMessages; 631 632 private int mTid; 633 private int mSavedPriority; 634 635 /** 636 * Prevent other classes from creating an EventHub. 637 */ 638 private EventHub() {} 639 640 /** 641 * Transfer all messages to the newly created webcore thread handler. 642 */ 643 private void transferMessages() { 644 mTid = Process.myTid(); 645 mSavedPriority = Process.getThreadPriority(mTid); 646 647 mHandler = new Handler() { 648 @Override 649 public void handleMessage(Message msg) { 650 if (LOGV_ENABLED) { 651 Log.v(LOGTAG, msg.what < LOAD_URL || msg.what 652 > SET_ACTIVE ? Integer.toString(msg.what) 653 : HandlerDebugString[msg.what - LOAD_URL]); 654 } 655 switch (msg.what) { 656 case WEBKIT_DRAW: 657 webkitDraw(); 658 break; 659 660 case DESTROY: 661 // Time to take down the world. Cancel all pending 662 // loads and destroy the native view and frame. 663 mBrowserFrame.destroy(); 664 mBrowserFrame = null; 665 mNativeClass = 0; 666 break; 667 668 case LOAD_URL: 669 loadUrl((String) msg.obj); 670 break; 671 672 case LOAD_DATA: 673 HashMap loadParams = (HashMap) msg.obj; 674 String baseUrl = (String) loadParams.get("baseUrl"); 675 if (baseUrl != null) { 676 int i = baseUrl.indexOf(':'); 677 if (i > 0) { 678 /* 679 * In 1.0, {@link 680 * WebView#loadDataWithBaseURL} can access 681 * local asset files as long as the data is 682 * valid. In the new WebKit, the restriction 683 * is tightened. To be compatible with 1.0, 684 * we automatically add the scheme of the 685 * baseUrl for local access as long as it is 686 * not http(s)/ftp(s)/about/javascript 687 */ 688 String scheme = baseUrl.substring(0, i); 689 if (!scheme.startsWith("http") && 690 !scheme.startsWith("ftp") && 691 !scheme.startsWith("about") && 692 !scheme.startsWith("javascript")) { 693 nativeRegisterURLSchemeAsLocal(scheme); 694 } 695 } 696 } 697 mBrowserFrame.loadData(baseUrl, 698 (String) loadParams.get("data"), 699 (String) loadParams.get("mimeType"), 700 (String) loadParams.get("encoding"), 701 (String) loadParams.get("failUrl")); 702 break; 703 704 case STOP_LOADING: 705 // If the WebCore has committed the load, but not 706 // finished the first layout yet, we need to set 707 // first layout done to trigger the interpreted side sync 708 // up with native side 709 if (mBrowserFrame.committed() 710 && !mBrowserFrame.firstLayoutDone()) { 711 mBrowserFrame.didFirstLayout(); 712 } 713 // Do this after syncing up the layout state. 714 stopLoading(); 715 break; 716 717 case RELOAD: 718 mBrowserFrame.reload(false); 719 break; 720 721 case KEY_DOWN: 722 key((KeyEvent) msg.obj, true); 723 break; 724 725 case KEY_UP: 726 key((KeyEvent) msg.obj, false); 727 break; 728 729 case CLICK: 730 nativeClick(); 731 break; 732 733 case VIEW_SIZE_CHANGED: 734 viewSizeChanged(msg.arg1, msg.arg2, 735 ((Float) msg.obj).floatValue()); 736 break; 737 738 case SET_SCROLL_OFFSET: 739 // note: these are in document coordinates 740 // (inv-zoom) 741 nativeSetScrollOffset(msg.arg1, msg.arg2); 742 break; 743 744 case SET_GLOBAL_BOUNDS: 745 Rect r = (Rect) msg.obj; 746 nativeSetGlobalBounds(r.left, r.top, r.width(), 747 r.height()); 748 break; 749 750 case GO_BACK_FORWARD: 751 // If it is a standard load and the load is not 752 // committed yet, we interpret BACK as RELOAD 753 if (!mBrowserFrame.committed() && msg.arg1 == -1 && 754 (mBrowserFrame.loadType() == 755 BrowserFrame.FRAME_LOADTYPE_STANDARD)) { 756 mBrowserFrame.reload(true); 757 } else { 758 mBrowserFrame.goBackOrForward(msg.arg1); 759 } 760 break; 761 762 case RESTORE_STATE: 763 stopLoading(); 764 restoreState(msg.arg1); 765 break; 766 767 case PAUSE_TIMERS: 768 mSavedPriority = Process.getThreadPriority(mTid); 769 Process.setThreadPriority(mTid, 770 Process.THREAD_PRIORITY_BACKGROUND); 771 pauseTimers(); 772 if (CacheManager.disableTransaction()) { 773 WebCoreThread.mCacheTickersBlocked = true; 774 sWebCoreHandler.removeMessages( 775 WebCoreThread.CACHE_TICKER); 776 } 777 break; 778 779 case RESUME_TIMERS: 780 Process.setThreadPriority(mTid, mSavedPriority); 781 resumeTimers(); 782 if (CacheManager.enableTransaction()) { 783 WebCoreThread.mCacheTickersBlocked = false; 784 sWebCoreHandler.sendMessageDelayed( 785 sWebCoreHandler.obtainMessage( 786 WebCoreThread.CACHE_TICKER), 787 WebCoreThread.CACHE_TICKER_INTERVAL); 788 } 789 break; 790 791 case SET_NETWORK_STATE: 792 if (BrowserFrame.sJavaBridge == null) { 793 throw new IllegalStateException("No WebView " + 794 "has been created in this process!"); 795 } 796 BrowserFrame.sJavaBridge 797 .setNetworkOnLine(msg.arg1 == 1); 798 break; 799 800 case CLEAR_CACHE: 801 mBrowserFrame.clearCache(); 802 if (msg.arg1 == 1) { 803 CacheManager.removeAllCacheFiles(); 804 } 805 break; 806 807 case CLEAR_HISTORY: 808 mCallbackProxy.getBackForwardList(). 809 close(mBrowserFrame.mNativeFrame); 810 break; 811 812 case REPLACE_TEXT: 813 HashMap jMap = (HashMap) msg.obj; 814 FocusData fData = (FocusData) jMap.get("focusData"); 815 String replace = (String) jMap.get("replace"); 816 int newStart = 817 ((Integer) jMap.get("start")).intValue(); 818 int newEnd = 819 ((Integer) jMap.get("end")).intValue(); 820 nativeReplaceTextfieldText(fData.mFrame, 821 fData.mNode, fData.mX, fData.mY, msg.arg1, 822 msg.arg2, replace, newStart, newEnd); 823 break; 824 825 case PASS_TO_JS: { 826 HashMap jsMap = (HashMap) msg.obj; 827 FocusData fDat = (FocusData) jsMap.get("focusData"); 828 KeyEvent evt = (KeyEvent) jsMap.get("event"); 829 int keyCode = evt.getKeyCode(); 830 int keyValue = evt.getUnicodeChar(); 831 int generation = msg.arg1; 832 passToJs(fDat.mFrame, fDat.mNode, fDat.mX, fDat.mY, 833 generation, 834 (String) jsMap.get("currentText"), 835 keyCode, 836 keyValue, 837 evt.isDown(), 838 evt.isShiftPressed(), evt.isAltPressed(), 839 evt.isSymPressed()); 840 break; 841 } 842 843 case SAVE_DOCUMENT_STATE: { 844 FocusData fDat = (FocusData) msg.obj; 845 nativeSaveDocumentState(fDat.mFrame); 846 break; 847 } 848 849 case CLEAR_SSL_PREF_TABLE: 850 Network.getInstance(mContext) 851 .clearUserSslPrefTable(); 852 break; 853 854 case TOUCH_UP: 855 TouchUpData touchUpData = (TouchUpData) msg.obj; 856 nativeTouchUp(touchUpData.mMoveGeneration, 857 touchUpData.mBuildGeneration, 858 touchUpData.mFrame, touchUpData.mNode, 859 touchUpData.mX, touchUpData.mY, 860 touchUpData.mSize, touchUpData.mIsClick, 861 touchUpData.mRetry); 862 break; 863 864 case TOUCH_EVENT: { 865 TouchEventData ted = (TouchEventData) msg.obj; 866 Message.obtain( 867 mWebView.mPrivateHandler, 868 WebView.PREVENT_TOUCH_ID, ted.mAction, 869 nativeHandleTouchEvent(ted.mAction, ted.mX, 870 ted.mY) ? 1 : 0).sendToTarget(); 871 break; 872 } 873 874 case SET_ACTIVE: 875 nativeSetFocusControllerActive(msg.arg1 == 1); 876 break; 877 878 case ADD_JS_INTERFACE: 879 HashMap map = (HashMap) msg.obj; 880 Object obj = map.get("object"); 881 String interfaceName = (String) 882 map.get("interfaceName"); 883 mBrowserFrame.addJavascriptInterface(obj, 884 interfaceName); 885 break; 886 887 case REQUEST_EXT_REPRESENTATION: 888 mBrowserFrame.externalRepresentation( 889 (Message) msg.obj); 890 break; 891 892 case REQUEST_DOC_AS_TEXT: 893 mBrowserFrame.documentAsText((Message) msg.obj); 894 break; 895 896 case SET_FINAL_FOCUS: 897 FocusData finalData = (FocusData) msg.obj; 898 nativeSetFinalFocus(finalData.mFrame, 899 finalData.mNode, finalData.mX, 900 finalData.mY, msg.arg1 901 != EventHub.NO_FOCUS_CHANGE_BLOCK); 902 break; 903 904 case UNBLOCK_FOCUS: 905 nativeUnblockFocus(); 906 break; 907 908 case SET_KIT_FOCUS: 909 FocusData focusData = (FocusData) msg.obj; 910 nativeSetKitFocus(focusData.mMoveGeneration, 911 focusData.mBuildGeneration, 912 focusData.mFrame, focusData.mNode, 913 focusData.mX, focusData.mY, 914 focusData.mIgnoreNullFocus); 915 break; 916 917 case REQUEST_FOCUS_HREF: { 918 Message hrefMsg = (Message) msg.obj; 919 String res = nativeRetrieveHref(msg.arg1, msg.arg2); 920 hrefMsg.getData().putString("url", res); 921 hrefMsg.sendToTarget(); 922 break; 923 } 924 925 case UPDATE_CACHE_AND_TEXT_ENTRY: 926 nativeUpdateFrameCache(); 927 // FIXME: this should provide a minimal rectangle 928 if (mWebView != null) { 929 mWebView.postInvalidate(); 930 } 931 sendUpdateTextEntry(); 932 break; 933 934 case DOC_HAS_IMAGES: 935 Message imageResult = (Message) msg.obj; 936 imageResult.arg1 = 937 mBrowserFrame.documentHasImages() ? 1 : 0; 938 imageResult.sendToTarget(); 939 break; 940 941 case SET_SNAP_ANCHOR: 942 nativeSetSnapAnchor(msg.arg1, msg.arg2); 943 break; 944 945 case DELETE_SELECTION: 946 FocusData delData = (FocusData) msg.obj; 947 nativeDeleteSelection(delData.mFrame, 948 delData.mNode, delData.mX, 949 delData.mY, msg.arg1, msg.arg2); 950 break; 951 952 case SET_SELECTION: 953 FocusData selData = (FocusData) msg.obj; 954 nativeSetSelection(selData.mFrame, 955 selData.mNode, selData.mX, 956 selData.mY, msg.arg1, msg.arg2); 957 break; 958 959 case LISTBOX_CHOICES: 960 SparseBooleanArray choices = (SparseBooleanArray) 961 msg.obj; 962 int choicesSize = msg.arg1; 963 boolean[] choicesArray = new boolean[choicesSize]; 964 for (int c = 0; c < choicesSize; c++) { 965 choicesArray[c] = choices.get(c); 966 } 967 nativeSendListBoxChoices(choicesArray, 968 choicesSize); 969 break; 970 971 case SINGLE_LISTBOX_CHOICE: 972 nativeSendListBoxChoice(msg.arg1); 973 break; 974 975 case SET_BACKGROUND_COLOR: 976 nativeSetBackgroundColor(msg.arg1); 977 break; 978 979 case GET_SELECTION: 980 String str = nativeGetSelection((Region) msg.obj); 981 Message.obtain(mWebView.mPrivateHandler 982 , WebView.UPDATE_CLIPBOARD, str) 983 .sendToTarget(); 984 break; 985 986 case DUMP_DOMTREE: 987 nativeDumpDomTree(msg.arg1 == 1); 988 break; 989 990 case DUMP_RENDERTREE: 991 nativeDumpRenderTree(msg.arg1 == 1); 992 break; 993 994 case DUMP_NAVTREE: 995 nativeDumpNavTree(); 996 break; 997 998 case SYNC_SCROLL: 999 mWebkitScrollX = msg.arg1; 1000 mWebkitScrollY = msg.arg2; 1001 break; 1002 1003 case REFRESH_PLUGINS: 1004 nativeRefreshPlugins(msg.arg1 != 0); 1005 break; 1006 1007 case SPLIT_PICTURE_SET: 1008 nativeSplitContent(); 1009 mSplitPictureIsScheduled = false; 1010 break; 1011 1012 case CLEAR_CONTENT: 1013 // Clear the view so that onDraw() will draw nothing 1014 // but white background 1015 // (See public method WebView.clearView) 1016 nativeClearContent(); 1017 break; 1018 1019 case MESSAGE_RELAY: 1020 if (msg.obj instanceof Message) { 1021 ((Message) msg.obj).sendToTarget(); 1022 } 1023 break; 1024 } 1025 } 1026 }; 1027 // Take all queued messages and resend them to the new handler. 1028 synchronized (this) { 1029 int size = mMessages.size(); 1030 for (int i = 0; i < size; i++) { 1031 mHandler.sendMessage(mMessages.get(i)); 1032 } 1033 mMessages = null; 1034 } 1035 } 1036 1037 /** 1038 * Send a message internally to the queue or to the handler 1039 */ 1040 private synchronized void sendMessage(Message msg) { 1041 if (mBlockMessages) { 1042 return; 1043 } 1044 if (mMessages != null) { 1045 mMessages.add(msg); 1046 } else { 1047 mHandler.sendMessage(msg); 1048 } 1049 } 1050 1051 private synchronized void removeMessages(int what) { 1052 if (mBlockMessages) { 1053 return; 1054 } 1055 if (what == EventHub.WEBKIT_DRAW) { 1056 mDrawIsScheduled = false; 1057 } 1058 if (mMessages != null) { 1059 Log.w(LOGTAG, "Not supported in this case."); 1060 } else { 1061 mHandler.removeMessages(what); 1062 } 1063 } 1064 1065 private synchronized void sendMessageDelayed(Message msg, long delay) { 1066 if (mBlockMessages) { 1067 return; 1068 } 1069 mHandler.sendMessageDelayed(msg, delay); 1070 } 1071 1072 /** 1073 * Send a message internally to the front of the queue. 1074 */ 1075 private synchronized void sendMessageAtFrontOfQueue(Message msg) { 1076 if (mBlockMessages) { 1077 return; 1078 } 1079 if (mMessages != null) { 1080 mMessages.add(0, msg); 1081 } else { 1082 mHandler.sendMessageAtFrontOfQueue(msg); 1083 } 1084 } 1085 1086 /** 1087 * Remove all the messages. 1088 */ 1089 private synchronized void removeMessages() { 1090 // reset mDrawIsScheduled flag as WEBKIT_DRAW may be removed 1091 mDrawIsScheduled = false; 1092 mSplitPictureIsScheduled = false; 1093 if (mMessages != null) { 1094 mMessages.clear(); 1095 } else { 1096 mHandler.removeCallbacksAndMessages(null); 1097 } 1098 } 1099 1100 /** 1101 * Block sending messages to the EventHub. 1102 */ 1103 private synchronized void blockMessages() { 1104 mBlockMessages = true; 1105 } 1106 } 1107 1108 //------------------------------------------------------------------------- 1109 // Methods called by host activity (in the same thread) 1110 //------------------------------------------------------------------------- 1111 1112 void stopLoading() { 1113 if (LOGV_ENABLED) Log.v(LOGTAG, "CORE stopLoading"); 1114 if (mBrowserFrame != null) { 1115 mBrowserFrame.stopLoading(); 1116 } 1117 } 1118 1119 //------------------------------------------------------------------------- 1120 // Methods called by WebView 1121 // If it refers to local variable, it needs synchronized(). 1122 // If it needs WebCore, it has to send message. 1123 //------------------------------------------------------------------------- 1124 1125 void sendMessage(Message msg) { 1126 mEventHub.sendMessage(msg); 1127 } 1128 1129 void sendMessage(int what) { 1130 mEventHub.sendMessage(Message.obtain(null, what)); 1131 } 1132 1133 void sendMessage(int what, Object obj) { 1134 mEventHub.sendMessage(Message.obtain(null, what, obj)); 1135 } 1136 1137 void sendMessage(int what, int arg1) { 1138 // just ignore the second argument (make it 0) 1139 mEventHub.sendMessage(Message.obtain(null, what, arg1, 0)); 1140 } 1141 1142 void sendMessage(int what, int arg1, int arg2) { 1143 mEventHub.sendMessage(Message.obtain(null, what, arg1, arg2)); 1144 } 1145 1146 void sendMessage(int what, int arg1, Object obj) { 1147 // just ignore the second argument (make it 0) 1148 mEventHub.sendMessage(Message.obtain(null, what, arg1, 0, obj)); 1149 } 1150 1151 void sendMessage(int what, int arg1, int arg2, Object obj) { 1152 mEventHub.sendMessage(Message.obtain(null, what, arg1, arg2, obj)); 1153 } 1154 1155 void sendMessageDelayed(int what, Object obj, long delay) { 1156 mEventHub.sendMessageDelayed(Message.obtain(null, what, obj), delay); 1157 } 1158 1159 void removeMessages(int what) { 1160 mEventHub.removeMessages(what); 1161 } 1162 1163 void removeMessages() { 1164 mEventHub.removeMessages(); 1165 } 1166 1167 /** 1168 * Removes pending messages and trigger a DESTROY message to send to 1169 * WebCore. 1170 * Called from UI thread. 1171 */ 1172 void destroy() { 1173 // We don't want anyone to post a message between removing pending 1174 // messages and sending the destroy message. 1175 synchronized (mEventHub) { 1176 mEventHub.removeMessages(); 1177 mEventHub.sendMessageAtFrontOfQueue( 1178 Message.obtain(null, EventHub.DESTROY)); 1179 mEventHub.blockMessages(); 1180 mWebView = null; 1181 } 1182 } 1183 1184 //------------------------------------------------------------------------- 1185 // WebViewCore private methods 1186 //------------------------------------------------------------------------- 1187 1188 private void loadUrl(String url) { 1189 if (LOGV_ENABLED) Log.v(LOGTAG, " CORE loadUrl " + url); 1190 mBrowserFrame.loadUrl(url); 1191 } 1192 1193 private void key(KeyEvent evt, boolean isDown) { 1194 if (LOGV_ENABLED) { 1195 Log.v(LOGTAG, "CORE key at " + System.currentTimeMillis() + ", " 1196 + evt); 1197 } 1198 if (!nativeKey(evt.getKeyCode(), evt.getUnicodeChar(), 1199 evt.getRepeatCount(), evt.isShiftPressed(), evt.isAltPressed(), 1200 isDown)) { 1201 // bubble up the event handling 1202 mCallbackProxy.onUnhandledKeyEvent(evt); 1203 } 1204 } 1205 1206 // These values are used to avoid requesting a layout based on old values 1207 private int mCurrentViewWidth = 0; 1208 private int mCurrentViewHeight = 0; 1209 1210 // notify webkit that our virtual view size changed size (after inv-zoom) 1211 private void viewSizeChanged(int w, int h, float scale) { 1212 if (LOGV_ENABLED) Log.v(LOGTAG, "CORE onSizeChanged"); 1213 if (w == 0) { 1214 Log.w(LOGTAG, "skip viewSizeChanged as w is 0"); 1215 return; 1216 } 1217 if (mSettings.getUseWideViewPort() 1218 && (w < mViewportWidth || mViewportWidth == -1)) { 1219 int width = mViewportWidth; 1220 if (mViewportWidth == -1) { 1221 if (mSettings.getLayoutAlgorithm() == 1222 WebSettings.LayoutAlgorithm.NORMAL) { 1223 width = WebView.ZOOM_OUT_WIDTH; 1224 } else { 1225 /* 1226 * if a page's minimum preferred width is wider than the 1227 * given "w", use it instead to get better layout result. If 1228 * we start a page with MAX_ZOOM_WIDTH, "w" will be always 1229 * wider. If we start a page with screen width, due to the 1230 * delay between {@link #didFirstLayout} and 1231 * {@link #viewSizeChanged}, 1232 * {@link #nativeGetContentMinPrefWidth} will return a more 1233 * accurate value than initial 0 to result a better layout. 1234 * In the worse case, the native width will be adjusted when 1235 * next zoom or screen orientation change happens. 1236 */ 1237 width = Math.max(w, nativeGetContentMinPrefWidth()); 1238 } 1239 } 1240 nativeSetSize(width, Math.round((float) width * h / w), w, scale, 1241 w, h); 1242 } else { 1243 nativeSetSize(w, h, w, scale, w, h); 1244 } 1245 // Remember the current width and height 1246 boolean needInvalidate = (mCurrentViewWidth == 0); 1247 mCurrentViewWidth = w; 1248 mCurrentViewHeight = h; 1249 if (needInvalidate) { 1250 // ensure {@link #webkitDraw} is called as we were blocking in 1251 // {@link #contentDraw} when mCurrentViewWidth is 0 1252 if (LOGV_ENABLED) Log.v(LOGTAG, "viewSizeChanged"); 1253 contentDraw(); 1254 } 1255 mEventHub.sendMessage(Message.obtain(null, 1256 EventHub.UPDATE_CACHE_AND_TEXT_ENTRY)); 1257 } 1258 1259 private void sendUpdateTextEntry() { 1260 if (mWebView != null) { 1261 Message.obtain(mWebView.mPrivateHandler, 1262 WebView.UPDATE_TEXT_ENTRY_MSG_ID).sendToTarget(); 1263 } 1264 } 1265 1266 // Used to avoid posting more than one draw message. 1267 private boolean mDrawIsScheduled; 1268 1269 // Used to avoid posting more than one split picture message. 1270 private boolean mSplitPictureIsScheduled; 1271 1272 // Used to suspend drawing. 1273 private boolean mDrawIsPaused; 1274 1275 // Used to end scale+scroll mode, accessed by both threads 1276 boolean mEndScaleZoom = false; 1277 1278 public class DrawData { 1279 public DrawData() { 1280 mInvalRegion = new Region(); 1281 mWidthHeight = new Point(); 1282 } 1283 public Region mInvalRegion; 1284 public Point mViewPoint; 1285 public Point mWidthHeight; 1286 } 1287 1288 private void webkitDraw() { 1289 mDrawIsScheduled = false; 1290 DrawData draw = new DrawData(); 1291 if (LOGV_ENABLED) Log.v(LOGTAG, "webkitDraw start"); 1292 if (nativeRecordContent(draw.mInvalRegion, draw.mWidthHeight) 1293 == false) { 1294 if (LOGV_ENABLED) Log.v(LOGTAG, "webkitDraw abort"); 1295 return; 1296 } 1297 if (mWebView != null) { 1298 // Send the native view size that was used during the most recent 1299 // layout. 1300 draw.mViewPoint = new Point(mCurrentViewWidth, mCurrentViewHeight); 1301 if (LOGV_ENABLED) Log.v(LOGTAG, "webkitDraw NEW_PICTURE_MSG_ID"); 1302 Message.obtain(mWebView.mPrivateHandler, 1303 WebView.NEW_PICTURE_MSG_ID, draw).sendToTarget(); 1304 if (mWebkitScrollX != 0 || mWebkitScrollY != 0) { 1305 // as we have the new picture, try to sync the scroll position 1306 Message.obtain(mWebView.mPrivateHandler, 1307 WebView.SYNC_SCROLL_TO_MSG_ID, mWebkitScrollX, 1308 mWebkitScrollY).sendToTarget(); 1309 mWebkitScrollX = mWebkitScrollY = 0; 1310 } 1311 // nativeSnapToAnchor() needs to be called after NEW_PICTURE_MSG_ID 1312 // is sent, so that scroll will be based on the new content size. 1313 nativeSnapToAnchor(); 1314 } 1315 } 1316 1317 /////////////////////////////////////////////////////////////////////////// 1318 // These are called from the UI thread, not our thread 1319 1320 static final int ZOOM_BITS = Paint.FILTER_BITMAP_FLAG | 1321 Paint.DITHER_FLAG | 1322 Paint.SUBPIXEL_TEXT_FLAG; 1323 static final int SCROLL_BITS = Paint.FILTER_BITMAP_FLAG | 1324 Paint.DITHER_FLAG; 1325 1326 final DrawFilter mZoomFilter = 1327 new PaintFlagsDrawFilter(ZOOM_BITS, Paint.LINEAR_TEXT_FLAG); 1328 final DrawFilter mScrollFilter = 1329 new PaintFlagsDrawFilter(SCROLL_BITS, 0); 1330 1331 /* package */ void drawContentPicture(Canvas canvas, int color, 1332 boolean animatingZoom, 1333 boolean animatingScroll) { 1334 DrawFilter df = null; 1335 if (animatingZoom) { 1336 df = mZoomFilter; 1337 } else if (animatingScroll) { 1338 df = mScrollFilter; 1339 } 1340 canvas.setDrawFilter(df); 1341 boolean tookTooLong = nativeDrawContent(canvas, color); 1342 canvas.setDrawFilter(null); 1343 if (tookTooLong && mSplitPictureIsScheduled == false) { 1344 mSplitPictureIsScheduled = true; 1345 sendMessage(EventHub.SPLIT_PICTURE_SET); 1346 } 1347 } 1348 1349 /*package*/ Picture copyContentPicture() { 1350 Picture result = new Picture(); 1351 nativeCopyContentToPicture(result); 1352 return result; 1353 } 1354 1355 static void pauseUpdate(WebViewCore core) { 1356 // remove the pending REDUCE_PRIORITY and RESUME_PRIORITY messages 1357 sWebCoreHandler.removeMessages(WebCoreThread.REDUCE_PRIORITY); 1358 sWebCoreHandler.removeMessages(WebCoreThread.RESUME_PRIORITY); 1359 sWebCoreHandler.sendMessageAtFrontOfQueue(sWebCoreHandler 1360 .obtainMessage(WebCoreThread.REDUCE_PRIORITY)); 1361 // Note: there is one possible failure mode. If pauseUpdate() is called 1362 // from UI thread while in webcore thread WEBKIT_DRAW is just pulled out 1363 // of the queue and about to be executed. mDrawIsScheduled may be set to 1364 // false in webkitDraw(). So update won't be blocked. But at least the 1365 // webcore thread priority is still lowered. 1366 if (core != null) { 1367 synchronized (core) { 1368 core.mDrawIsPaused = true; 1369 core.mEventHub.removeMessages(EventHub.WEBKIT_DRAW); 1370 } 1371 } 1372 } 1373 1374 static void resumeUpdate(WebViewCore core) { 1375 // remove the pending REDUCE_PRIORITY and RESUME_PRIORITY messages 1376 sWebCoreHandler.removeMessages(WebCoreThread.REDUCE_PRIORITY); 1377 sWebCoreHandler.removeMessages(WebCoreThread.RESUME_PRIORITY); 1378 sWebCoreHandler.sendMessageAtFrontOfQueue(sWebCoreHandler 1379 .obtainMessage(WebCoreThread.RESUME_PRIORITY)); 1380 if (core != null) { 1381 synchronized (core) { 1382 core.mDrawIsScheduled = false; 1383 core.mDrawIsPaused = false; 1384 if (LOGV_ENABLED) Log.v(LOGTAG, "resumeUpdate"); 1385 core.contentDraw(); 1386 } 1387 } 1388 } 1389 1390 static void startCacheTransaction() { 1391 sWebCoreHandler.sendMessage(sWebCoreHandler 1392 .obtainMessage(WebCoreThread.RESUME_CACHE_TICKER)); 1393 } 1394 1395 static void endCacheTransaction() { 1396 sWebCoreHandler.sendMessage(sWebCoreHandler 1397 .obtainMessage(WebCoreThread.BLOCK_CACHE_TICKER)); 1398 } 1399 1400 ////////////////////////////////////////////////////////////////////////// 1401 1402 private void restoreState(int index) { 1403 WebBackForwardList list = mCallbackProxy.getBackForwardList(); 1404 int size = list.getSize(); 1405 for (int i = 0; i < size; i++) { 1406 list.getItemAtIndex(i).inflate(mBrowserFrame.mNativeFrame); 1407 } 1408 mBrowserFrame.mLoadInitFromJava = true; 1409 list.restoreIndex(mBrowserFrame.mNativeFrame, index); 1410 mBrowserFrame.mLoadInitFromJava = false; 1411 } 1412 1413 //------------------------------------------------------------------------- 1414 // Implement abstract methods in WebViewCore, native WebKit callback part 1415 //------------------------------------------------------------------------- 1416 1417 // called from JNI or WebView thread 1418 /* package */ void contentDraw() { 1419 // don't update the Picture until we have an initial width and finish 1420 // the first layout 1421 if (mCurrentViewWidth == 0 || !mBrowserFrame.firstLayoutDone()) { 1422 return; 1423 } 1424 // only fire an event if this is our first request 1425 synchronized (this) { 1426 if (mDrawIsPaused || mDrawIsScheduled) { 1427 return; 1428 } 1429 mDrawIsScheduled = true; 1430 mEventHub.sendMessage(Message.obtain(null, EventHub.WEBKIT_DRAW)); 1431 } 1432 } 1433 1434 // called by JNI 1435 private void contentScrollBy(int dx, int dy, boolean animate) { 1436 if (!mBrowserFrame.firstLayoutDone()) { 1437 // Will this happen? If yes, we need to do something here. 1438 return; 1439 } 1440 if (mWebView != null) { 1441 Message msg = Message.obtain(mWebView.mPrivateHandler, 1442 WebView.SCROLL_BY_MSG_ID, dx, dy, new Boolean(animate)); 1443 if (mDrawIsScheduled) { 1444 mEventHub.sendMessage(Message.obtain(null, 1445 EventHub.MESSAGE_RELAY, msg)); 1446 } else { 1447 msg.sendToTarget(); 1448 } 1449 } 1450 } 1451 1452 // called by JNI 1453 private void contentScrollTo(int x, int y) { 1454 if (!mBrowserFrame.firstLayoutDone()) { 1455 /* 1456 * WebKit restore state will be called before didFirstLayout(), 1457 * remember the position as it has to be applied after restoring 1458 * zoom factor which is controlled by screenWidth. 1459 */ 1460 mRestoredX = x; 1461 mRestoredY = y; 1462 return; 1463 } 1464 if (mWebView != null) { 1465 Message msg = Message.obtain(mWebView.mPrivateHandler, 1466 WebView.SCROLL_TO_MSG_ID, x, y); 1467 if (mDrawIsScheduled) { 1468 mEventHub.sendMessage(Message.obtain(null, 1469 EventHub.MESSAGE_RELAY, msg)); 1470 } else { 1471 msg.sendToTarget(); 1472 } 1473 } 1474 } 1475 1476 // called by JNI 1477 private void contentSpawnScrollTo(int x, int y) { 1478 if (!mBrowserFrame.firstLayoutDone()) { 1479 /* 1480 * WebKit restore state will be called before didFirstLayout(), 1481 * remember the position as it has to be applied after restoring 1482 * zoom factor which is controlled by screenWidth. 1483 */ 1484 mRestoredX = x; 1485 mRestoredY = y; 1486 return; 1487 } 1488 if (mWebView != null) { 1489 Message msg = Message.obtain(mWebView.mPrivateHandler, 1490 WebView.SPAWN_SCROLL_TO_MSG_ID, x, y); 1491 if (mDrawIsScheduled) { 1492 mEventHub.sendMessage(Message.obtain(null, 1493 EventHub.MESSAGE_RELAY, msg)); 1494 } else { 1495 msg.sendToTarget(); 1496 } 1497 } 1498 } 1499 1500 // called by JNI 1501 private void sendMarkNodeInvalid(int node) { 1502 if (mWebView != null) { 1503 Message.obtain(mWebView.mPrivateHandler, 1504 WebView.MARK_NODE_INVALID_ID, node, 0).sendToTarget(); 1505 } 1506 } 1507 1508 // called by JNI 1509 private void sendNotifyFocusSet() { 1510 if (mWebView != null) { 1511 Message.obtain(mWebView.mPrivateHandler, 1512 WebView.NOTIFY_FOCUS_SET_MSG_ID).sendToTarget(); 1513 } 1514 } 1515 1516 // called by JNI 1517 private void sendNotifyProgressFinished() { 1518 sendUpdateTextEntry(); 1519 // as CacheManager can behave based on database transaction, we need to 1520 // call tick() to trigger endTransaction 1521 sWebCoreHandler.removeMessages(WebCoreThread.CACHE_TICKER); 1522 sWebCoreHandler.sendMessage(sWebCoreHandler 1523 .obtainMessage(WebCoreThread.CACHE_TICKER)); 1524 contentDraw(); 1525 } 1526 1527 // called by JNI 1528 private void sendRecomputeFocus() { 1529 if (mWebView != null) { 1530 Message.obtain(mWebView.mPrivateHandler, 1531 WebView.RECOMPUTE_FOCUS_MSG_ID).sendToTarget(); 1532 } 1533 } 1534 1535 /* Called by JNI. The coordinates are in doc coordinates, so they need to 1536 be scaled before they can be used by the view system, which happens 1537 in WebView since it (and its thread) know the current scale factor. 1538 */ 1539 private void sendViewInvalidate(int left, int top, int right, int bottom) { 1540 if (mWebView != null) { 1541 Message.obtain(mWebView.mPrivateHandler, 1542 WebView.INVAL_RECT_MSG_ID, 1543 new Rect(left, top, right, bottom)).sendToTarget(); 1544 } 1545 } 1546 1547 /* package */ WebView getWebView() { 1548 return mWebView; 1549 } 1550 1551 private native void setViewportSettingsFromNative(); 1552 1553 // called by JNI 1554 private void didFirstLayout(boolean standardLoad) { 1555 // Trick to ensure that the Picture has the exact height for the content 1556 // by forcing to layout with 0 height after the page is ready, which is 1557 // indicated by didFirstLayout. This is essential to get rid of the 1558 // white space in the GMail which uses WebView for message view. 1559 if (mWebView != null && mWebView.mHeightCanMeasure) { 1560 mWebView.mLastHeightSent = 0; 1561 // Send a negative scale to indicate that WebCore should reuse the 1562 // current scale 1563 mEventHub.sendMessage(Message.obtain(null, 1564 EventHub.VIEW_SIZE_CHANGED, mWebView.mLastWidthSent, 1565 mWebView.mLastHeightSent, -1.0f)); 1566 } 1567 1568 mBrowserFrame.didFirstLayout(); 1569 1570 // reset the scroll position as it is a new page now 1571 mWebkitScrollX = mWebkitScrollY = 0; 1572 1573 // set the viewport settings from WebKit 1574 setViewportSettingsFromNative(); 1575 1576 // infer the values if they are not defined. 1577 if (mViewportWidth == 0) { 1578 if (mViewportInitialScale == 0) { 1579 mViewportInitialScale = 100; 1580 } 1581 if (mViewportMinimumScale == 0) { 1582 mViewportMinimumScale = 100; 1583 } 1584 } 1585 if (mViewportUserScalable == false) { 1586 mViewportInitialScale = 100; 1587 mViewportMinimumScale = 100; 1588 mViewportMaximumScale = 100; 1589 } 1590 if (mViewportMinimumScale > mViewportInitialScale) { 1591 if (mViewportInitialScale == 0) { 1592 mViewportInitialScale = mViewportMinimumScale; 1593 } else { 1594 mViewportMinimumScale = mViewportInitialScale; 1595 } 1596 } 1597 if (mViewportMaximumScale > 0) { 1598 if (mViewportMaximumScale < mViewportInitialScale) { 1599 mViewportMaximumScale = mViewportInitialScale; 1600 } else if (mViewportInitialScale == 0) { 1601 mViewportInitialScale = mViewportMaximumScale; 1602 } 1603 } 1604 if (mViewportWidth < 0 && mViewportInitialScale == 100) { 1605 mViewportWidth = 0; 1606 } 1607 1608 // now notify webview 1609 if (mWebView != null) { 1610 HashMap scaleLimit = new HashMap(); 1611 scaleLimit.put("minScale", mViewportMinimumScale); 1612 scaleLimit.put("maxScale", mViewportMaximumScale); 1613 1614 if (mRestoredScale > 0) { 1615 Message.obtain(mWebView.mPrivateHandler, 1616 WebView.DID_FIRST_LAYOUT_MSG_ID, mRestoredScale, 0, 1617 scaleLimit).sendToTarget(); 1618 mRestoredScale = 0; 1619 } else { 1620 // if standardLoad is true, use mViewportInitialScale, otherwise 1621 // pass -1 to the WebView to indicate no change of the scale. 1622 Message.obtain(mWebView.mPrivateHandler, 1623 WebView.DID_FIRST_LAYOUT_MSG_ID, 1624 standardLoad ? mViewportInitialScale : -1, 1625 mViewportWidth, scaleLimit).sendToTarget(); 1626 } 1627 1628 // force an early draw for quick feedback after the first layout 1629 if (mCurrentViewWidth != 0) { 1630 synchronized (this) { 1631 if (mDrawIsScheduled) { 1632 mEventHub.removeMessages(EventHub.WEBKIT_DRAW); 1633 } 1634 mDrawIsScheduled = true; 1635 // if no restored offset, move the new page to (0, 0) 1636 mEventHub.sendMessageAtFrontOfQueue(Message.obtain(null, 1637 EventHub.MESSAGE_RELAY, Message.obtain( 1638 mWebView.mPrivateHandler, 1639 WebView.SCROLL_TO_MSG_ID, mRestoredX, 1640 mRestoredY))); 1641 mEventHub.sendMessageAtFrontOfQueue(Message.obtain(null, 1642 EventHub.WEBKIT_DRAW)); 1643 } 1644 } 1645 1646 // reset restored offset 1647 mRestoredX = mRestoredY = 0; 1648 } 1649 } 1650 1651 // called by JNI 1652 private void restoreScale(int scale) { 1653 if (mBrowserFrame.firstLayoutDone() == false) { 1654 mRestoredScale = scale; 1655 } 1656 } 1657 1658 // called by JNI 1659 private void needTouchEvents(boolean need) { 1660 if (mWebView != null) { 1661 Message.obtain(mWebView.mPrivateHandler, 1662 WebView.WEBCORE_NEED_TOUCH_EVENTS, need ? 1 : 0, 0) 1663 .sendToTarget(); 1664 } 1665 } 1666 1667 // called by JNI 1668 private void updateTextfield(int ptr, boolean changeToPassword, 1669 String text, int textGeneration) { 1670 if (mWebView != null) { 1671 Message msg = Message.obtain(mWebView.mPrivateHandler, 1672 WebView.UPDATE_TEXTFIELD_TEXT_MSG_ID, ptr, 1673 textGeneration, text); 1674 msg.getData().putBoolean("password", changeToPassword); 1675 msg.sendToTarget(); 1676 } 1677 } 1678 1679 // these must be in document space (i.e. not scaled/zoomed). 1680 private native void nativeSetScrollOffset(int dx, int dy); 1681 1682 private native void nativeSetGlobalBounds(int x, int y, int w, int h); 1683 1684 // called by JNI 1685 private void requestListBox(String[] array, boolean[] enabledArray, 1686 int[] selectedArray) { 1687 if (mWebView != null) { 1688 mWebView.requestListBox(array, enabledArray, selectedArray); 1689 } 1690 } 1691 1692 // called by JNI 1693 private void requestListBox(String[] array, boolean[] enabledArray, 1694 int selection) { 1695 if (mWebView != null) { 1696 mWebView.requestListBox(array, enabledArray, selection); 1697 } 1698 1699 } 1700} 1701