2 * Copyright 2006, The Android Open Source Project
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 #define LOG_TAG "webcoreglue"
29 #include "WebViewCore.h"
31 #include "AtomicString.h"
32 #include "CachedNode.h"
33 #include "CachedRoot.h"
35 #include "ChromeClientAndroid.h"
37 #include "DatabaseTracker.h"
39 #include "DOMWindow.h"
40 #include "DOMSelection.h"
43 #include "EditorClientAndroid.h"
44 #include "EventHandler.h"
45 #include "EventNames.h"
46 #include "FocusController.h"
49 #include "FrameLoader.h"
50 #include "FrameLoaderClientAndroid.h"
51 #include "FrameTree.h"
52 #include "FrameView.h"
53 #include "Geolocation.h"
54 #include "GraphicsContext.h"
55 #include "GraphicsJNI.h"
56 #include "HTMLAnchorElement.h"
57 #include "HTMLAreaElement.h"
58 #include "HTMLElement.h"
59 #include "HTMLImageElement.h"
60 #include "HTMLInputElement.h"
61 #include "HTMLLabelElement.h"
62 #include "HTMLMapElement.h"
63 #include "HTMLNames.h"
64 #include "HTMLOptGroupElement.h"
65 #include "HTMLOptionElement.h"
66 #include "HTMLSelectElement.h"
67 #include "HTMLTextAreaElement.h"
68 #include "HistoryItem.h"
69 #include "HitTestRequest.h"
70 #include "HitTestResult.h"
71 #include "InlineTextBox.h"
72 #include "Navigator.h"
76 #include "PageGroup.h"
77 #include "PlatformKeyboardEvent.h"
78 #include "PlatformString.h"
79 #include "PluginWidgetAndroid.h"
80 #include "PluginView.h"
82 #include "ProgressTracker.h"
84 #include "RenderBox.h"
85 #include "RenderInline.h"
86 #include "RenderLayer.h"
87 #include "RenderPart.h"
88 #include "RenderText.h"
89 #include "RenderTextControl.h"
90 #include "RenderThemeAndroid.h"
91 #include "RenderView.h"
92 #include "ResourceRequest.h"
93 #include "SelectionController.h"
96 #include "SkTemplates.h"
97 #include "SkTDArray.h"
100 #include "SkPicture.h"
102 #include "StringImpl.h"
104 #include "TypingCommand.h"
105 #include "WebCoreFrameBridge.h"
106 #include "WebFrameView.h"
107 #include "WindowsKeyboardCodes.h"
108 #include "android_graphics.h"
111 #include <JNIUtility.h>
112 #include <ui/KeycodeLabels.h>
113 #include <wtf/CurrentTime.h>
116 #include "ScriptController.h"
117 #include "V8Counters.h"
118 #include <wtf/text/CString.h>
125 #if ENABLE(TOUCH_EVENTS) // Android
126 #include "PlatformTouchEvent.h"
129 #ifdef ANDROID_DOM_LOGGING
130 #include "AndroidLog.h"
131 #include "RenderTreeAsText.h"
132 #include <wtf/text/CString.h>
134 FILE* gDomTreeFile = 0;
135 FILE* gRenderTreeFile = 0;
138 #ifdef ANDROID_INSTRUMENT
139 #include "TimeCounter.h"
142 #if USE(ACCELERATED_COMPOSITING)
143 #include "GraphicsLayerAndroid.h"
144 #include "RenderLayerCompositor.h"
147 /* We pass this flag when recording the actual content, so that we don't spend
148 time actually regionizing complex path clips, when all we really want to do
151 #define PICT_RECORD_FLAGS SkPicture::kUsePathBoundsForClip_RecordingFlag
153 ////////////////////////////////////////////////////////////////////////////////////////////////
157 static SkTDArray<WebViewCore*> gInstanceList;
159 void WebViewCore::addInstance(WebViewCore* inst) {
160 *gInstanceList.append() = inst;
163 void WebViewCore::removeInstance(WebViewCore* inst) {
164 int index = gInstanceList.find(inst);
165 LOG_ASSERT(index >= 0, "RemoveInstance inst not found");
167 gInstanceList.removeShuffle(index);
171 bool WebViewCore::isInstance(WebViewCore* inst) {
172 return gInstanceList.find(inst) >= 0;
175 jobject WebViewCore::getApplicationContext() {
177 // check to see if there is a valid webviewcore object
178 if (gInstanceList.isEmpty())
181 // get the context from the webview
182 jobject context = gInstanceList[0]->getContext();
187 // get the application context using JNI
188 JNIEnv* env = JSC::Bindings::getJNIEnv();
189 jclass contextClass = env->GetObjectClass(context);
190 jmethodID appContextMethod = env->GetMethodID(contextClass, "getApplicationContext", "()Landroid/content/Context;");
191 jobject result = env->CallObjectMethod(context, appContextMethod);
196 // ----------------------------------------------------------------------------
198 #define GET_NATIVE_VIEW(env, obj) ((WebViewCore*)env->GetIntField(obj, gWebViewCoreFields.m_nativeClass))
200 // Field ids for WebViewCore
201 struct WebViewCoreFields {
202 jfieldID m_nativeClass;
203 jfieldID m_viewportWidth;
204 jfieldID m_viewportHeight;
205 jfieldID m_viewportInitialScale;
206 jfieldID m_viewportMinimumScale;
207 jfieldID m_viewportMaximumScale;
208 jfieldID m_viewportUserScalable;
209 jfieldID m_viewportDensityDpi;
211 } gWebViewCoreFields;
213 // ----------------------------------------------------------------------------
215 struct WebViewCore::JavaGlue {
217 jmethodID m_spawnScrollTo;
218 jmethodID m_scrollTo;
219 jmethodID m_scrollBy;
220 jmethodID m_contentDraw;
221 jmethodID m_requestListBox;
222 jmethodID m_openFileChooser;
223 jmethodID m_requestSingleListBox;
225 jmethodID m_jsConfirm;
226 jmethodID m_jsPrompt;
227 jmethodID m_jsUnload;
228 jmethodID m_jsInterrupt;
229 jmethodID m_didFirstLayout;
230 jmethodID m_updateViewport;
231 jmethodID m_sendNotifyProgressFinished;
232 jmethodID m_sendViewInvalidate;
233 jmethodID m_sendImmediateRepaint;
234 jmethodID m_setRootLayer;
235 jmethodID m_updateTextfield;
236 jmethodID m_updateTextSelection;
237 jmethodID m_clearTextEntry;
238 jmethodID m_restoreScale;
239 jmethodID m_needTouchEvents;
240 jmethodID m_requestKeyboard;
241 jmethodID m_requestKeyboardWithSelection;
242 jmethodID m_exceededDatabaseQuota;
243 jmethodID m_reachedMaxAppCacheSize;
244 jmethodID m_populateVisitedLinks;
245 jmethodID m_geolocationPermissionsShowPrompt;
246 jmethodID m_geolocationPermissionsHidePrompt;
247 jmethodID m_addMessageToConsole;
248 jmethodID m_getPluginClass;
249 jmethodID m_showFullScreenPlugin;
250 jmethodID m_hideFullScreenPlugin;
251 jmethodID m_addSurface;
252 jmethodID m_updateSurface;
253 jmethodID m_destroySurface;
254 jmethodID m_getContext;
255 jmethodID m_sendFindAgain;
256 jmethodID m_showRect;
257 jmethodID m_centerFitRect;
258 jmethodID m_setScrollbarModes;
259 jmethodID m_setInstallableWebApp;
260 AutoJObject object(JNIEnv* env) {
261 return getRealObject(env, m_obj);
266 * WebViewCore Implementation
269 static jmethodID GetJMethod(JNIEnv* env, jclass clazz, const char name[], const char signature[])
271 jmethodID m = env->GetMethodID(clazz, name, signature);
272 LOG_ASSERT(m, "Could not find method %s", name);
276 Mutex WebViewCore::gFrameCacheMutex;
277 Mutex WebViewCore::gButtonMutex;
278 Mutex WebViewCore::gCursorBoundsMutex;
279 Mutex WebViewCore::m_contentMutex;
281 WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* mainframe)
282 : m_pluginInvalTimer(this, &WebViewCore::pluginInvalTimerFired)
284 m_mainFrame = mainframe;
287 m_moveGeneration = 0;
288 m_lastGeneration = 0;
289 m_touchGeneration = 0;
290 m_blockTextfieldUpdates = false;
291 // just initial values. These should be set by client
292 m_maxXScroll = 320/4;
293 m_maxYScroll = 240/4;
294 m_textGeneration = 0;
296 m_textWrapWidth = 320;
298 #if ENABLE(TOUCH_EVENTS)
299 m_forwardingTouchEvents = false;
303 LOG_ASSERT(m_mainFrame, "Uh oh, somehow a frameview was made without an initial frame!");
305 jclass clazz = env->GetObjectClass(javaWebViewCore);
306 m_javaGlue = new JavaGlue;
307 m_javaGlue->m_obj = env->NewWeakGlobalRef(javaWebViewCore);
308 m_javaGlue->m_spawnScrollTo = GetJMethod(env, clazz, "contentSpawnScrollTo", "(II)V");
309 m_javaGlue->m_scrollTo = GetJMethod(env, clazz, "contentScrollTo", "(II)V");
310 m_javaGlue->m_scrollBy = GetJMethod(env, clazz, "contentScrollBy", "(IIZ)V");
311 m_javaGlue->m_contentDraw = GetJMethod(env, clazz, "contentDraw", "()V");
312 m_javaGlue->m_requestListBox = GetJMethod(env, clazz, "requestListBox", "([Ljava/lang/String;[I[I)V");
313 m_javaGlue->m_openFileChooser = GetJMethod(env, clazz, "openFileChooser", "(Ljava/lang/String;)Ljava/lang/String;");
314 m_javaGlue->m_requestSingleListBox = GetJMethod(env, clazz, "requestListBox", "([Ljava/lang/String;[II)V");
315 m_javaGlue->m_jsAlert = GetJMethod(env, clazz, "jsAlert", "(Ljava/lang/String;Ljava/lang/String;)V");
316 m_javaGlue->m_jsConfirm = GetJMethod(env, clazz, "jsConfirm", "(Ljava/lang/String;Ljava/lang/String;)Z");
317 m_javaGlue->m_jsPrompt = GetJMethod(env, clazz, "jsPrompt", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
318 m_javaGlue->m_jsUnload = GetJMethod(env, clazz, "jsUnload", "(Ljava/lang/String;Ljava/lang/String;)Z");
319 m_javaGlue->m_jsInterrupt = GetJMethod(env, clazz, "jsInterrupt", "()Z");
320 m_javaGlue->m_didFirstLayout = GetJMethod(env, clazz, "didFirstLayout", "(Z)V");
321 m_javaGlue->m_updateViewport = GetJMethod(env, clazz, "updateViewport", "()V");
322 m_javaGlue->m_sendNotifyProgressFinished = GetJMethod(env, clazz, "sendNotifyProgressFinished", "()V");
323 m_javaGlue->m_sendViewInvalidate = GetJMethod(env, clazz, "sendViewInvalidate", "(IIII)V");
324 m_javaGlue->m_sendImmediateRepaint = GetJMethod(env, clazz, "sendImmediateRepaint", "()V");
325 m_javaGlue->m_setRootLayer = GetJMethod(env, clazz, "setRootLayer", "(I)V");
326 m_javaGlue->m_updateTextfield = GetJMethod(env, clazz, "updateTextfield", "(IZLjava/lang/String;I)V");
327 m_javaGlue->m_updateTextSelection = GetJMethod(env, clazz, "updateTextSelection", "(IIII)V");
328 m_javaGlue->m_clearTextEntry = GetJMethod(env, clazz, "clearTextEntry", "()V");
329 m_javaGlue->m_restoreScale = GetJMethod(env, clazz, "restoreScale", "(II)V");
330 m_javaGlue->m_needTouchEvents = GetJMethod(env, clazz, "needTouchEvents", "(Z)V");
331 m_javaGlue->m_requestKeyboard = GetJMethod(env, clazz, "requestKeyboard", "(Z)V");
332 m_javaGlue->m_requestKeyboardWithSelection = GetJMethod(env, clazz, "requestKeyboardWithSelection", "(IIII)V");
333 m_javaGlue->m_exceededDatabaseQuota = GetJMethod(env, clazz, "exceededDatabaseQuota", "(Ljava/lang/String;Ljava/lang/String;JJ)V");
334 m_javaGlue->m_reachedMaxAppCacheSize = GetJMethod(env, clazz, "reachedMaxAppCacheSize", "(J)V");
335 m_javaGlue->m_populateVisitedLinks = GetJMethod(env, clazz, "populateVisitedLinks", "()V");
336 m_javaGlue->m_geolocationPermissionsShowPrompt = GetJMethod(env, clazz, "geolocationPermissionsShowPrompt", "(Ljava/lang/String;)V");
337 m_javaGlue->m_geolocationPermissionsHidePrompt = GetJMethod(env, clazz, "geolocationPermissionsHidePrompt", "()V");
338 m_javaGlue->m_addMessageToConsole = GetJMethod(env, clazz, "addMessageToConsole", "(Ljava/lang/String;ILjava/lang/String;I)V");
339 m_javaGlue->m_getPluginClass = GetJMethod(env, clazz, "getPluginClass", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Class;");
340 m_javaGlue->m_showFullScreenPlugin = GetJMethod(env, clazz, "showFullScreenPlugin", "(Landroid/webkit/ViewManager$ChildView;I)V");
341 m_javaGlue->m_hideFullScreenPlugin = GetJMethod(env, clazz, "hideFullScreenPlugin", "()V");
342 m_javaGlue->m_addSurface = GetJMethod(env, clazz, "addSurface", "(Landroid/view/View;IIII)Landroid/webkit/ViewManager$ChildView;");
343 m_javaGlue->m_updateSurface = GetJMethod(env, clazz, "updateSurface", "(Landroid/webkit/ViewManager$ChildView;IIII)V");
344 m_javaGlue->m_destroySurface = GetJMethod(env, clazz, "destroySurface", "(Landroid/webkit/ViewManager$ChildView;)V");
345 m_javaGlue->m_getContext = GetJMethod(env, clazz, "getContext", "()Landroid/content/Context;");
346 m_javaGlue->m_sendFindAgain = GetJMethod(env, clazz, "sendFindAgain", "()V");
347 m_javaGlue->m_showRect = GetJMethod(env, clazz, "showRect", "(IIIIIIFFFF)V");
348 m_javaGlue->m_centerFitRect = GetJMethod(env, clazz, "centerFitRect", "(IIII)V");
349 m_javaGlue->m_setScrollbarModes = GetJMethod(env, clazz, "setScrollbarModes", "(II)V");
350 m_javaGlue->m_setInstallableWebApp = GetJMethod(env, clazz, "setInstallableWebApp", "()V");
352 env->SetIntField(javaWebViewCore, gWebViewCoreFields.m_nativeClass, (jint)this);
354 m_scrollOffsetX = m_scrollOffsetY = 0;
356 PageGroup::setShouldTrackVisitedLinks(true);
360 WebViewCore::addInstance(this);
363 WebViewCore::~WebViewCore()
365 WebViewCore::removeInstance(this);
367 // Release the focused view
368 Release(m_popupReply);
370 if (m_javaGlue->m_obj) {
371 JNIEnv* env = JSC::Bindings::getJNIEnv();
372 env->DeleteWeakGlobalRef(m_javaGlue->m_obj);
373 m_javaGlue->m_obj = 0;
376 delete m_frameCacheKit;
377 delete m_navPictureKit;
380 WebViewCore* WebViewCore::getWebViewCore(const WebCore::FrameView* view)
382 return getWebViewCore(static_cast<const WebCore::ScrollView*>(view));
385 WebViewCore* WebViewCore::getWebViewCore(const WebCore::ScrollView* view)
390 WebFrameView* webFrameView = static_cast<WebFrameView*>(view->platformWidget());
393 return webFrameView->webViewCore();
396 void WebViewCore::reset(bool fromConstructor)
399 if (fromConstructor) {
403 gFrameCacheMutex.lock();
404 delete m_frameCacheKit;
405 delete m_navPictureKit;
408 gFrameCacheMutex.unlock();
412 m_lastFocusedBounds = WebCore::IntRect(0,0,0,0);
413 m_focusBoundsChanged = false;
414 m_lastFocusedSelStart = 0;
415 m_lastFocusedSelEnd = 0;
417 m_updatedFrameCache = true;
418 m_frameCacheOutOfDate = true;
419 m_skipContentDraw = false;
421 m_domtree_version = 0;
422 m_check_domtree_version = true;
423 m_progressDone = false;
424 m_hasCursorBounds = false;
430 m_groupForVisitedLinks = NULL;
433 static bool layoutIfNeededRecursive(WebCore::Frame* f)
438 WebCore::FrameView* v = f->view();
442 if (v->needsLayout())
443 v->layout(f->tree()->parent());
445 WebCore::Frame* child = f->tree()->firstChild();
448 success &= layoutIfNeededRecursive(child);
449 child = child->tree()->nextSibling();
452 return success && !v->needsLayout();
455 CacheBuilder& WebViewCore::cacheBuilder()
457 return FrameLoaderClientAndroid::get(m_mainFrame)->getCacheBuilder();
460 WebCore::Node* WebViewCore::currentFocus()
462 return cacheBuilder().currentFocus();
465 void WebViewCore::recordPicture(SkPicture* picture)
467 // if there is no document yet, just return
468 if (!m_mainFrame->document()) {
469 DBG_NAV_LOG("no document");
472 // Call layout to ensure that the contentWidth and contentHeight are correct
473 if (!layoutIfNeededRecursive(m_mainFrame)) {
474 DBG_NAV_LOG("layout failed");
477 // draw into the picture's recording canvas
478 WebCore::FrameView* view = m_mainFrame->view();
479 DBG_NAV_LOGD("view=(w=%d,h=%d)", view->contentsWidth(),
480 view->contentsHeight());
481 SkAutoPictureRecord arp(picture, view->contentsWidth(),
482 view->contentsHeight(), PICT_RECORD_FLAGS);
483 SkAutoMemoryUsageProbe mup(__FUNCTION__);
485 // Copy m_buttons so we can pass it to our graphics context.
487 WTF::Vector<Container> buttons(m_buttons);
488 gButtonMutex.unlock();
490 WebCore::PlatformGraphicsContext pgc(arp.getRecordingCanvas(), &buttons);
491 WebCore::GraphicsContext gc(&pgc);
492 view->platformWidget()->draw(&gc, WebCore::IntRect(0, 0,
493 view->contentsWidth(), view->contentsHeight()));
496 updateButtonList(&buttons);
497 gButtonMutex.unlock();
500 void WebViewCore::recordPictureSet(PictureSet* content)
502 // if there is no document yet, just return
503 if (!m_mainFrame->document()) {
504 DBG_SET_LOG("!m_mainFrame->document()");
507 if (m_addInval.isEmpty()) {
508 DBG_SET_LOG("m_addInval.isEmpty()");
511 // Call layout to ensure that the contentWidth and contentHeight are correct
512 // it's fine for layout to gather invalidates, but defeat sending a message
513 // back to java to call webkitDraw, since we're already in the middle of
515 m_skipContentDraw = true;
516 bool success = layoutIfNeededRecursive(m_mainFrame);
517 m_skipContentDraw = false;
519 // We may be mid-layout and thus cannot draw.
523 { // collect WebViewCoreRecordTimeCounter after layoutIfNeededRecursive
524 #ifdef ANDROID_INSTRUMENT
525 TimeCounterAuto counter(TimeCounter::WebViewCoreRecordTimeCounter);
528 // if the webkit page dimensions changed, discard the pictureset and redraw.
529 WebCore::FrameView* view = m_mainFrame->view();
530 int width = view->contentsWidth();
531 int height = view->contentsHeight();
533 // Use the contents width and height as a starting point.
535 contentRect.set(0, 0, width, height);
536 SkIRect total(contentRect);
538 // Traverse all the frames and add their sizes if they are in the visible
540 for (WebCore::Frame* frame = m_mainFrame->tree()->traverseNext(); frame;
541 frame = frame->tree()->traverseNext()) {
542 // If the frame doesn't have an owner then it is the top frame and the
543 // view size is the frame size.
544 WebCore::RenderPart* owner = frame->ownerRenderer();
545 if (owner && owner->style()->visibility() == VISIBLE) {
549 // Traverse the tree up to the parent to find the absolute position
551 WebCore::Frame* parent = frame->tree()->parent();
553 WebCore::RenderPart* parentOwner = parent->ownerRenderer();
555 x += parentOwner->x();
556 y += parentOwner->y();
558 parent = parent->tree()->parent();
560 // Use the owner dimensions so that padding and border are
562 int right = x + owner->width();
563 int bottom = y + owner->height();
564 SkIRect frameRect = {x, y, right, bottom};
565 // Ignore a width or height that is smaller than 1. Some iframes
566 // have small dimensions in order to be hidden. The iframe
567 // expansion code does not expand in that case so we should ignore
569 if (frameRect.width() > 1 && frameRect.height() > 1
570 && SkIRect::Intersects(total, frameRect))
571 total.join(x, y, right, bottom);
575 // If the new total is larger than the content, resize the view to include
577 if (!contentRect.contains(total)) {
578 // Resize the view to change the overflow clip.
579 view->resize(total.fRight, total.fBottom);
581 // We have to force a layout in order for the clip to change.
582 m_mainFrame->contentRenderer()->setNeedsLayoutAndPrefWidthsRecalc();
585 // Relayout similar to above
586 m_skipContentDraw = true;
587 bool success = layoutIfNeededRecursive(m_mainFrame);
588 m_skipContentDraw = false;
592 // Set the computed content width
593 width = view->contentsWidth();
594 height = view->contentsHeight();
597 if (cacheBuilder().pictureSetDisabled())
600 content->checkDimensions(width, height, &m_addInval);
602 // The inval region may replace existing pictures. The existing pictures
603 // may have already been split into pieces. If reuseSubdivided() returns
604 // true, the split pieces are the last entries in the picture already. They
605 // are marked as invalid, and are rebuilt by rebuildPictureSet().
607 // If the new region doesn't match a set of split pieces, add it to the end.
608 if (!content->reuseSubdivided(m_addInval)) {
609 const SkIRect& inval = m_addInval.getBounds();
610 SkPicture* picture = rebuildPicture(inval);
611 DBG_SET_LOGD("{%d,%d,w=%d,h=%d}", inval.fLeft,
612 inval.fTop, inval.width(), inval.height());
613 content->add(m_addInval, picture, 0, false);
614 picture->safeUnref();
616 // Remove any pictures already in the set that are obscured by the new one,
617 // and check to see if any already split pieces need to be redrawn.
618 if (content->build())
619 rebuildPictureSet(content);
620 } // WebViewCoreRecordTimeCounter
621 WebCore::Node* oldFocusNode = currentFocus();
622 m_frameCacheOutOfDate = true;
623 WebCore::IntRect oldBounds;
627 oldBounds = oldFocusNode->getRect();
628 RenderObject* renderer = oldFocusNode->renderer();
629 if (renderer && (renderer->isTextArea() || renderer->isTextField())) {
630 WebCore::RenderTextControl* rtc =
631 static_cast<WebCore::RenderTextControl*>(renderer);
632 oldSelStart = rtc->selectionStart();
633 oldSelEnd = rtc->selectionEnd();
636 oldBounds = WebCore::IntRect(0,0,0,0);
637 unsigned latestVersion = 0;
638 if (m_check_domtree_version) {
639 // as domTreeVersion only increment, we can just check the sum to see
640 // whether we need to update the frame cache
641 for (Frame* frame = m_mainFrame; frame; frame = frame->tree()->traverseNext()) {
642 latestVersion += frame->document()->domTreeVersion();
645 DBG_NAV_LOGD("m_lastFocused=%p oldFocusNode=%p"
646 " m_lastFocusedBounds={%d,%d,%d,%d} oldBounds={%d,%d,%d,%d}"
647 " m_lastFocusedSelection={%d,%d} oldSelection={%d,%d}"
648 " m_check_domtree_version=%s latestVersion=%d m_domtree_version=%d",
649 m_lastFocused, oldFocusNode,
650 m_lastFocusedBounds.x(), m_lastFocusedBounds.y(),
651 m_lastFocusedBounds.width(), m_lastFocusedBounds.height(),
652 oldBounds.x(), oldBounds.y(), oldBounds.width(), oldBounds.height(),
653 m_lastFocusedSelStart, m_lastFocusedSelEnd, oldSelStart, oldSelEnd,
654 m_check_domtree_version ? "true" : "false",
655 latestVersion, m_domtree_version);
656 if (m_lastFocused == oldFocusNode && m_lastFocusedBounds == oldBounds
657 && m_lastFocusedSelStart == oldSelStart
658 && m_lastFocusedSelEnd == oldSelEnd
660 && (!m_check_domtree_version || latestVersion == m_domtree_version))
664 m_focusBoundsChanged |= m_lastFocused == oldFocusNode
665 && m_lastFocusedBounds != oldBounds;
666 m_lastFocused = oldFocusNode;
667 m_lastFocusedBounds = oldBounds;
668 m_lastFocusedSelStart = oldSelStart;
669 m_lastFocusedSelEnd = oldSelEnd;
670 m_domtree_version = latestVersion;
671 DBG_NAV_LOG("call updateFrameCache");
674 LOG_ASSERT(m_javaGlue->m_obj,
675 "A Java widget was not associated with this view bridge!");
676 JNIEnv* env = JSC::Bindings::getJNIEnv();
677 env->CallVoidMethod(m_javaGlue->object(env).get(),
678 m_javaGlue->m_sendFindAgain);
683 void WebViewCore::updateButtonList(WTF::Vector<Container>* buttons)
685 // All the entries in buttons are either updates of previous entries in
686 // m_buttons or they need to be added to it.
687 Container* end = buttons->end();
688 for (Container* updatedContainer = buttons->begin();
689 updatedContainer != end; updatedContainer++) {
690 bool updated = false;
691 // Search for a previous entry that references the same node as our new
693 Container* lastPossibleMatch = m_buttons.end();
694 for (Container* possibleMatch = m_buttons.begin();
695 possibleMatch != lastPossibleMatch; possibleMatch++) {
696 if (updatedContainer->matches(possibleMatch->node())) {
697 // Update our record, and skip to the next one.
698 possibleMatch->setRect(updatedContainer->rect());
704 // This is a brand new button, so append it to m_buttons
705 m_buttons.append(*updatedContainer);
709 // count will decrease each time one is removed, so check count each time.
710 while (i < m_buttons.size()) {
711 if (m_buttons[i].canBeRemoved()) {
712 m_buttons[i] = m_buttons.last();
713 m_buttons.removeLast();
720 // note: updateCursorBounds is called directly by the WebView thread
721 // This needs to be called each time we call CachedRoot::setCursor() with
722 // non-null CachedNode/CachedFrame, since otherwise the WebViewCore's data
723 // about the cursor is incorrect. When we call setCursor(0,0), we need
724 // to set hasCursorBounds to false.
725 void WebViewCore::updateCursorBounds(const CachedRoot* root,
726 const CachedFrame* cachedFrame, const CachedNode* cachedNode)
728 LOG_ASSERT(root, "updateCursorBounds: root cannot be null");
729 LOG_ASSERT(cachedNode, "updateCursorBounds: cachedNode cannot be null");
730 LOG_ASSERT(cachedFrame, "updateCursorBounds: cachedFrame cannot be null");
731 gCursorBoundsMutex.lock();
732 m_hasCursorBounds = !cachedNode->isHidden();
733 // If m_hasCursorBounds is false, we never look at the other
734 // values, so do not bother setting them.
735 if (m_hasCursorBounds) {
736 WebCore::IntRect bounds = cachedNode->bounds(cachedFrame);
737 if (m_cursorBounds != bounds)
738 DBG_NAV_LOGD("new cursor bounds=(%d,%d,w=%d,h=%d)",
739 bounds.x(), bounds.y(), bounds.width(), bounds.height());
740 m_cursorBounds = bounds;
741 m_cursorHitBounds = cachedNode->hitBounds(cachedFrame);
742 m_cursorFrame = cachedFrame->framePointer();
743 root->getSimulatedMousePosition(&m_cursorLocation);
744 m_cursorNode = cachedNode->nodePointer();
746 gCursorBoundsMutex.unlock();
749 void WebViewCore::clearContent()
752 m_contentMutex.lock();
754 m_contentMutex.unlock();
755 m_addInval.setEmpty();
756 m_rebuildInval.setEmpty();
759 void WebViewCore::copyContentToPicture(SkPicture* picture)
761 DBG_SET_LOG("start");
762 m_contentMutex.lock();
763 PictureSet copyContent = PictureSet(m_content);
764 m_contentMutex.unlock();
766 int w = copyContent.width();
767 int h = copyContent.height();
768 copyContent.draw(picture->beginRecording(w, h, PICT_RECORD_FLAGS));
769 picture->endRecording();
773 bool WebViewCore::drawContent(SkCanvas* canvas, SkColor color)
775 #ifdef ANDROID_INSTRUMENT
776 TimeCounterAuto counter(TimeCounter::WebViewUIDrawTimeCounter);
778 DBG_SET_LOG("start");
779 m_contentMutex.lock();
780 PictureSet copyContent = PictureSet(m_content);
781 m_contentMutex.unlock();
782 int sc = canvas->save(SkCanvas::kClip_SaveFlag);
784 clip.set(0, 0, copyContent.width(), copyContent.height());
785 canvas->clipRect(clip, SkRegion::kDifference_Op);
786 canvas->drawColor(color);
787 canvas->restoreToCount(sc);
788 bool tookTooLong = copyContent.draw(canvas);
789 m_contentMutex.lock();
790 m_content.setDrawTimes(copyContent);
791 m_contentMutex.unlock();
796 bool WebViewCore::focusBoundsChanged()
798 bool result = m_focusBoundsChanged;
799 m_focusBoundsChanged = false;
803 bool WebViewCore::pictureReady()
806 m_contentMutex.lock();
807 PictureSet copyContent = PictureSet(m_content);
808 done = m_progressDone;
809 m_contentMutex.unlock();
810 DBG_NAV_LOGD("done=%s empty=%s", done ? "true" : "false",
811 copyContent.isEmpty() ? "true" : "false");
812 return done || !copyContent.isEmpty();
815 SkPicture* WebViewCore::rebuildPicture(const SkIRect& inval)
817 WebCore::FrameView* view = m_mainFrame->view();
818 int width = view->contentsWidth();
819 int height = view->contentsHeight();
820 SkPicture* picture = new SkPicture();
821 SkAutoPictureRecord arp(picture, width, height, PICT_RECORD_FLAGS);
822 SkAutoMemoryUsageProbe mup(__FUNCTION__);
823 SkCanvas* recordingCanvas = arp.getRecordingCanvas();
826 WTF::Vector<Container> buttons(m_buttons);
827 gButtonMutex.unlock();
829 WebCore::PlatformGraphicsContext pgc(recordingCanvas, &buttons);
830 WebCore::GraphicsContext gc(&pgc);
831 recordingCanvas->translate(-inval.fLeft, -inval.fTop);
832 recordingCanvas->save();
833 view->platformWidget()->draw(&gc, WebCore::IntRect(inval.fLeft,
834 inval.fTop, inval.width(), inval.height()));
835 m_rebuildInval.op(inval, SkRegion::kUnion_Op);
836 DBG_SET_LOGD("m_rebuildInval={%d,%d,r=%d,b=%d}",
837 m_rebuildInval.getBounds().fLeft, m_rebuildInval.getBounds().fTop,
838 m_rebuildInval.getBounds().fRight, m_rebuildInval.getBounds().fBottom);
841 updateButtonList(&buttons);
842 gButtonMutex.unlock();
847 void WebViewCore::rebuildPictureSet(PictureSet* pictureSet)
849 WebCore::FrameView* view = m_mainFrame->view();
850 size_t size = pictureSet->size();
851 for (size_t index = 0; index < size; index++) {
852 if (pictureSet->upToDate(index))
854 const SkIRect& inval = pictureSet->bounds(index);
855 DBG_SET_LOGD("pictSet=%p [%d] {%d,%d,w=%d,h=%d}", pictureSet, index,
856 inval.fLeft, inval.fTop, inval.width(), inval.height());
857 pictureSet->setPicture(index, rebuildPicture(inval));
859 pictureSet->validate(__FUNCTION__);
862 bool WebViewCore::recordContent(SkRegion* region, SkIPoint* point)
864 DBG_SET_LOG("start");
865 float progress = (float) m_mainFrame->page()->progress()->estimatedProgress();
866 m_contentMutex.lock();
867 PictureSet contentCopy(m_content);
868 m_progressDone = progress <= 0.0f || progress >= 1.0f;
869 m_contentMutex.unlock();
870 recordPictureSet(&contentCopy);
871 if (!m_progressDone && contentCopy.isEmpty()) {
872 DBG_SET_LOGD("empty (progress=%g)", progress);
875 region->set(m_addInval);
876 m_addInval.setEmpty();
877 region->op(m_rebuildInval, SkRegion::kUnion_Op);
878 m_rebuildInval.setEmpty();
879 m_contentMutex.lock();
880 contentCopy.setDrawTimes(m_content);
881 m_content.set(contentCopy);
882 point->fX = m_content.width();
883 point->fY = m_content.height();
884 m_contentMutex.unlock();
885 DBG_SET_LOGD("region={%d,%d,r=%d,b=%d}", region->getBounds().fLeft,
886 region->getBounds().fTop, region->getBounds().fRight,
887 region->getBounds().fBottom);
890 #if USE(ACCELERATED_COMPOSITING)
891 // We update the layers
892 ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(m_mainFrame->page()->chrome()->client());
893 chromeC->layersSync();
898 void WebViewCore::splitContent()
900 bool layoutSuceeded = layoutIfNeededRecursive(m_mainFrame);
901 LOG_ASSERT(layoutSuceeded, "Can never be called recursively");
902 PictureSet tempPictureSet;
903 m_contentMutex.lock();
904 m_content.split(&tempPictureSet);
905 m_contentMutex.unlock();
906 rebuildPictureSet(&tempPictureSet);
907 m_contentMutex.lock();
908 m_content.set(tempPictureSet);
909 m_contentMutex.unlock();
912 void WebViewCore::scrollTo(int x, int y, bool animate)
914 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
916 // LOGD("WebViewCore::scrollTo(%d %d)\n", x, y);
918 JNIEnv* env = JSC::Bindings::getJNIEnv();
919 env->CallVoidMethod(m_javaGlue->object(env).get(),
920 animate ? m_javaGlue->m_spawnScrollTo : m_javaGlue->m_scrollTo,
925 void WebViewCore::sendNotifyProgressFinished()
927 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
928 JNIEnv* env = JSC::Bindings::getJNIEnv();
929 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_sendNotifyProgressFinished);
933 void WebViewCore::viewInvalidate(const WebCore::IntRect& rect)
935 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
936 JNIEnv* env = JSC::Bindings::getJNIEnv();
937 env->CallVoidMethod(m_javaGlue->object(env).get(),
938 m_javaGlue->m_sendViewInvalidate,
939 rect.x(), rect.y(), rect.right(), rect.bottom());
943 void WebViewCore::scrollBy(int dx, int dy, bool animate)
947 JNIEnv* env = JSC::Bindings::getJNIEnv();
948 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_scrollBy,
953 #if USE(ACCELERATED_COMPOSITING)
955 void WebViewCore::immediateRepaint()
957 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
958 JNIEnv* env = JSC::Bindings::getJNIEnv();
959 env->CallVoidMethod(m_javaGlue->object(env).get(),
960 m_javaGlue->m_sendImmediateRepaint);
964 void WebViewCore::setUIRootLayer(const LayerAndroid* layer)
966 JNIEnv* env = JSC::Bindings::getJNIEnv();
967 env->CallVoidMethod(m_javaGlue->object(env).get(),
968 m_javaGlue->m_setRootLayer,
969 reinterpret_cast<jint>(layer));
973 #endif // USE(ACCELERATED_COMPOSITING)
975 void WebViewCore::contentDraw()
977 JNIEnv* env = JSC::Bindings::getJNIEnv();
978 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_contentDraw);
982 void WebViewCore::contentInvalidate(const WebCore::IntRect &r)
984 DBG_SET_LOGD("rect={%d,%d,w=%d,h=%d}", r.x(), r.y(), r.width(), r.height());
986 if (!rect.intersect(0, 0, INT_MAX, INT_MAX))
988 m_addInval.op(rect, SkRegion::kUnion_Op);
989 DBG_SET_LOGD("m_addInval={%d,%d,r=%d,b=%d}",
990 m_addInval.getBounds().fLeft, m_addInval.getBounds().fTop,
991 m_addInval.getBounds().fRight, m_addInval.getBounds().fBottom);
992 if (!m_skipContentDraw)
996 void WebViewCore::offInvalidate(const WebCore::IntRect &r)
998 // FIXME: these invalidates are offscreen, and can be throttled or
999 // deferred until the area is visible. For now, treat them as
1000 // regular invals so that drawing happens (inefficiently) for now.
1001 contentInvalidate(r);
1004 static int pin_pos(int x, int width, int targetWidth)
1006 if (x + width > targetWidth)
1007 x = targetWidth - width;
1013 void WebViewCore::didFirstLayout()
1015 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
1016 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
1018 WebCore::FrameLoader* loader = m_mainFrame->loader();
1019 const WebCore::KURL& url = loader->url();
1022 LOGV("::WebCore:: didFirstLayout %s", url.string().ascii().data());
1024 WebCore::FrameLoadType loadType = loader->loadType();
1026 JNIEnv* env = JSC::Bindings::getJNIEnv();
1027 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_didFirstLayout,
1028 loadType == WebCore::FrameLoadTypeStandard
1029 // When redirect with locked history, we would like to reset the
1030 // scale factor. This is important for www.yahoo.com as it is
1031 // redirected to www.yahoo.com/?rs=1 on load.
1032 || loadType == WebCore::FrameLoadTypeRedirectWithLockedBackForwardList);
1033 checkException(env);
1035 DBG_NAV_LOG("call updateFrameCache");
1036 m_check_domtree_version = false;
1038 m_history.setDidFirstLayout(true);
1041 void WebViewCore::updateViewport()
1043 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
1044 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
1046 JNIEnv* env = JSC::Bindings::getJNIEnv();
1047 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_updateViewport);
1048 checkException(env);
1051 void WebViewCore::restoreScale(int scale, int textWrapScale)
1053 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
1054 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
1056 JNIEnv* env = JSC::Bindings::getJNIEnv();
1057 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_restoreScale, scale, textWrapScale);
1058 checkException(env);
1061 void WebViewCore::needTouchEvents(bool need)
1063 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
1064 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
1066 #if ENABLE(TOUCH_EVENTS)
1067 if (m_forwardingTouchEvents == need)
1070 JNIEnv* env = JSC::Bindings::getJNIEnv();
1071 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_needTouchEvents, need);
1072 checkException(env);
1074 m_forwardingTouchEvents = need;
1078 void WebViewCore::requestKeyboardWithSelection(const WebCore::Node* node,
1079 int selStart, int selEnd)
1081 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
1082 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
1084 JNIEnv* env = JSC::Bindings::getJNIEnv();
1085 env->CallVoidMethod(m_javaGlue->object(env).get(),
1086 m_javaGlue->m_requestKeyboardWithSelection,
1087 reinterpret_cast<int>(node), selStart, selEnd, m_textGeneration);
1088 checkException(env);
1091 void WebViewCore::requestKeyboard(bool showKeyboard)
1093 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
1094 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
1096 JNIEnv* env = JSC::Bindings::getJNIEnv();
1097 env->CallVoidMethod(m_javaGlue->object(env).get(),
1098 m_javaGlue->m_requestKeyboard, showKeyboard);
1099 checkException(env);
1102 void WebViewCore::notifyProgressFinished()
1104 DBG_NAV_LOG("call updateFrameCache");
1105 m_check_domtree_version = true;
1107 sendNotifyProgressFinished();
1110 void WebViewCore::doMaxScroll(CacheBuilder::Direction dir)
1115 case CacheBuilder::LEFT:
1118 case CacheBuilder::UP:
1121 case CacheBuilder::RIGHT:
1124 case CacheBuilder::DOWN:
1127 case CacheBuilder::UNINITIALIZED:
1129 LOG_ASSERT(0, "unexpected focus selector");
1131 this->scrollBy(dx, dy, true);
1134 void WebViewCore::setScrollOffset(int moveGeneration, int dx, int dy)
1136 DBG_NAV_LOGD("{%d,%d} m_scrollOffset=(%d,%d)", dx, dy,
1137 m_scrollOffsetX, m_scrollOffsetY);
1138 if (m_scrollOffsetX != dx || m_scrollOffsetY != dy) {
1139 m_scrollOffsetX = dx;
1140 m_scrollOffsetY = dy;
1141 // The visible rect is located within our coordinate space so it
1142 // contains the actual scroll position. Setting the location makes hit
1143 // testing work correctly.
1144 m_mainFrame->view()->platformWidget()->setLocation(m_scrollOffsetX,
1146 m_mainFrame->eventHandler()->sendScrollEvent();
1148 // update the currently visible screen
1149 sendPluginVisibleScreen();
1151 gCursorBoundsMutex.lock();
1152 bool hasCursorBounds = m_hasCursorBounds;
1153 Frame* frame = (Frame*) m_cursorFrame;
1154 IntPoint location = m_cursorLocation;
1155 gCursorBoundsMutex.unlock();
1156 if (!hasCursorBounds)
1158 moveMouseIfLatest(moveGeneration, frame, location.x(), location.y());
1161 void WebViewCore::setGlobalBounds(int x, int y, int h, int v)
1163 DBG_NAV_LOGD("{%d,%d}", x, y);
1164 m_mainFrame->view()->platformWidget()->setWindowBounds(x, y, h, v);
1167 void WebViewCore::setSizeScreenWidthAndScale(int width, int height,
1168 int textWrapWidth, float scale, int screenWidth, int screenHeight,
1169 int anchorX, int anchorY, bool ignoreHeight)
1171 WebCoreViewBridge* window = m_mainFrame->view()->platformWidget();
1172 int ow = window->width();
1173 int oh = window->height();
1174 window->setSize(width, height);
1175 window->setVisibleSize(screenWidth, screenHeight);
1176 if (width != screenWidth) {
1177 m_mainFrame->view()->setUseFixedLayout(true);
1178 m_mainFrame->view()->setFixedLayoutSize(IntSize(width, height));
1180 m_mainFrame->view()->setUseFixedLayout(false);
1182 int osw = m_screenWidth;
1183 int osh = m_screenHeight;
1184 int otw = m_textWrapWidth;
1185 DBG_NAV_LOGD("old:(w=%d,h=%d,sw=%d,scale=%g) new:(w=%d,h=%d,sw=%d,scale=%g)",
1186 ow, oh, osw, m_scale, width, height, screenWidth, scale);
1187 m_screenWidth = screenWidth;
1188 m_screenHeight = screenHeight;
1189 m_textWrapWidth = textWrapWidth;
1190 if (scale >= 0) // negative means keep the current scale
1192 m_maxXScroll = screenWidth >> 2;
1193 m_maxYScroll = m_maxXScroll * height / width;
1194 if (ow != width || (!ignoreHeight && oh != height) || otw != textWrapWidth) {
1195 WebCore::RenderObject *r = m_mainFrame->contentRenderer();
1196 DBG_NAV_LOGD("renderer=%p view=(w=%d,h=%d)", r,
1197 screenWidth, screenHeight);
1199 WebCore::IntPoint anchorPoint = WebCore::IntPoint(anchorX, anchorY);
1200 DBG_NAV_LOGD("anchorX=%d anchorY=%d", anchorX, anchorY);
1201 RefPtr<WebCore::Node> node;
1202 WebCore::IntRect bounds;
1203 WebCore::IntPoint offset;
1204 // If the text wrap changed, it is probably zoom change or
1205 // orientation change. Try to keep the anchor at the same place.
1206 if (otw && textWrapWidth && otw != textWrapWidth) {
1207 WebCore::HitTestResult hitTestResult =
1208 m_mainFrame->eventHandler()-> hitTestResultAtPoint(
1209 anchorPoint, false);
1210 node = hitTestResult.innerNode();
1213 bounds = node->getRect();
1214 DBG_NAV_LOGD("ob:(x=%d,y=%d,w=%d,h=%d)",
1215 bounds.x(), bounds.y(), bounds.width(), bounds.height());
1216 // sites like nytimes.com insert a non-standard tag <nyt_text>
1217 // in the html. If it is the HitTestResult, it may have zero
1218 // width and height. In this case, use its parent node.
1219 if (bounds.width() == 0) {
1220 node = node->parent();
1222 bounds = node->getRect();
1223 DBG_NAV_LOGD("found a zero width node and use its parent, whose ob:(x=%d,y=%d,w=%d,h=%d)",
1224 bounds.x(), bounds.y(), bounds.width(), bounds.height());
1228 r->setNeedsLayoutAndPrefWidthsRecalc();
1229 m_mainFrame->view()->forceLayout();
1230 // scroll to restore current screen center
1232 const WebCore::IntRect& newBounds = node->getRect();
1233 DBG_NAV_LOGD("nb:(x=%d,y=%d,w=%d,"
1234 "h=%d)", newBounds.x(), newBounds.y(),
1235 newBounds.width(), newBounds.height());
1236 if ((osw && osh && bounds.width() && bounds.height())
1237 && (bounds != newBounds)) {
1238 WebCore::FrameView* view = m_mainFrame->view();
1239 // force left align if width is not changed while height changed.
1240 // the anchorPoint is probably at some white space in the node
1241 // which is affected by text wrap around the screen width.
1242 const bool leftAlign = (otw != textWrapWidth)
1243 && (bounds.width() == newBounds.width())
1244 && (bounds.height() != newBounds.height());
1245 const float xPercentInDoc =
1246 leftAlign ? 0.0 : (float) (anchorX - bounds.x()) / bounds.width();
1247 const float xPercentInView =
1248 leftAlign ? 0.0 : (float) (anchorX - m_scrollOffsetX) / osw;
1249 const float yPercentInDoc = (float) (anchorY - bounds.y()) / bounds.height();
1250 const float yPercentInView = (float) (anchorY - m_scrollOffsetY) / osh;
1251 showRect(newBounds.x(), newBounds.y(), newBounds.width(),
1252 newBounds.height(), view->contentsWidth(),
1253 view->contentsHeight(),
1254 xPercentInDoc, xPercentInView,
1255 yPercentInDoc, yPercentInView);
1261 // update the currently visible screen as perceived by the plugin
1262 sendPluginVisibleScreen();
1265 void WebViewCore::dumpDomTree(bool useFile)
1267 #ifdef ANDROID_DOM_LOGGING
1269 gDomTreeFile = fopen(DOM_TREE_LOG_FILE, "w");
1270 m_mainFrame->document()->showTreeForThis();
1272 fclose(gDomTreeFile);
1278 void WebViewCore::dumpRenderTree(bool useFile)
1280 #ifdef ANDROID_DOM_LOGGING
1281 WTF::CString renderDump = WebCore::externalRepresentation(m_mainFrame).utf8();
1282 const char* data = renderDump.data();
1284 gRenderTreeFile = fopen(RENDER_TREE_LOG_FILE, "w");
1285 DUMP_RENDER_LOGD("%s", data);
1286 fclose(gRenderTreeFile);
1287 gRenderTreeFile = 0;
1289 // adb log can only output 1024 characters, so write out line by line.
1290 // exclude '\n' as adb log adds it for each output.
1291 int length = renderDump.length();
1292 for (int i = 0, last = 0; i < length; i++) {
1293 if (data[i] == '\n') {
1295 DUMP_RENDER_LOGD("%.*s", (i - last), &(data[last]));
1303 void WebViewCore::dumpNavTree()
1306 cacheBuilder().mDebug.print();
1310 WebCore::HTMLAnchorElement* WebViewCore::retrieveAnchorElement(WebCore::Frame* frame, WebCore::Node* node)
1312 if (!CacheBuilder::validNode(m_mainFrame, frame, node))
1314 if (!node->hasTagName(WebCore::HTMLNames::aTag))
1316 return static_cast<WebCore::HTMLAnchorElement*>(node);
1319 WebCore::String WebViewCore::retrieveHref(WebCore::Frame* frame, WebCore::Node* node)
1321 WebCore::HTMLAnchorElement* anchor = retrieveAnchorElement(frame, node);
1322 return anchor ? anchor->href() : WebCore::String();
1325 WebCore::String WebViewCore::retrieveAnchorText(WebCore::Frame* frame, WebCore::Node* node)
1327 WebCore::HTMLAnchorElement* anchor = retrieveAnchorElement(frame, node);
1328 return anchor ? anchor->text() : WebCore::String();
1331 WebCore::String WebViewCore::requestLabel(WebCore::Frame* frame,
1332 WebCore::Node* node)
1334 if (node && CacheBuilder::validNode(m_mainFrame, frame, node)) {
1335 RefPtr<WebCore::NodeList> list = node->document()->getElementsByTagName("label");
1336 unsigned length = list->length();
1337 for (unsigned i = 0; i < length; i++) {
1338 WebCore::HTMLLabelElement* label = static_cast<WebCore::HTMLLabelElement*>(
1340 if (label->control() == node) {
1343 while ((node = node->traverseNextNode(label))) {
1344 if (node->isTextNode()) {
1345 Text* textNode = static_cast<Text*>(node);
1346 result += textNode->dataImpl();
1353 return WebCore::String();
1356 void WebViewCore::updateCacheOnNodeChange()
1358 gCursorBoundsMutex.lock();
1359 bool hasCursorBounds = m_hasCursorBounds;
1360 Frame* frame = (Frame*) m_cursorFrame;
1361 Node* node = (Node*) m_cursorNode;
1362 IntRect bounds = m_cursorHitBounds;
1363 gCursorBoundsMutex.unlock();
1364 if (!hasCursorBounds || !node)
1366 if (CacheBuilder::validNode(m_mainFrame, frame, node)) {
1367 RenderObject* renderer = node->renderer();
1368 if (renderer && renderer->style()->visibility() != HIDDEN) {
1369 IntRect absBox = renderer->absoluteBoundingBoxRect();
1370 int globalX, globalY;
1371 CacheBuilder::GetGlobalOffset(frame, &globalX, &globalY);
1372 absBox.move(globalX, globalY);
1373 if (absBox == bounds)
1375 DBG_NAV_LOGD("absBox=(%d,%d,%d,%d) bounds=(%d,%d,%d,%d)",
1376 absBox.x(), absBox.y(), absBox.width(), absBox.height(),
1377 bounds.x(), bounds.y(), bounds.width(), bounds.height());
1380 DBG_NAV_LOGD("updateFrameCache node=%p", node);
1384 void WebViewCore::updateFrameCache()
1386 if (!m_frameCacheOutOfDate) {
1387 DBG_NAV_LOG("!m_frameCacheOutOfDate");
1390 #ifdef ANDROID_INSTRUMENT
1391 TimeCounterAuto counter(TimeCounter::WebViewCoreBuildNavTimeCounter);
1393 m_frameCacheOutOfDate = false;
1395 m_now = SkTime::GetMSecs();
1397 m_temp = new CachedRoot();
1398 m_temp->init(m_mainFrame, &m_history);
1399 #if USE(ACCELERATED_COMPOSITING)
1400 GraphicsLayerAndroid* graphicsLayer = graphicsRootLayer();
1402 m_temp->setRootLayer(graphicsLayer->contentLayer());
1404 CacheBuilder& builder = cacheBuilder();
1405 WebCore::Settings* settings = m_mainFrame->page()->settings();
1406 builder.allowAllTextDetection();
1407 #ifdef ANDROID_META_SUPPORT
1409 if (!settings->formatDetectionAddress())
1410 builder.disallowAddressDetection();
1411 if (!settings->formatDetectionEmail())
1412 builder.disallowEmailDetection();
1413 if (!settings->formatDetectionTelephone())
1414 builder.disallowPhoneDetection();
1417 builder.buildCache(m_temp);
1418 m_tempPict = new SkPicture();
1419 recordPicture(m_tempPict);
1420 m_temp->setPicture(m_tempPict);
1421 m_temp->setTextGeneration(m_textGeneration);
1422 WebCoreViewBridge* window = m_mainFrame->view()->platformWidget();
1423 m_temp->setVisibleRect(WebCore::IntRect(m_scrollOffsetX,
1424 m_scrollOffsetY, window->width(), window->height()));
1425 gFrameCacheMutex.lock();
1426 delete m_frameCacheKit;
1427 delete m_navPictureKit;
1428 m_frameCacheKit = m_temp;
1429 m_navPictureKit = m_tempPict;
1430 m_updatedFrameCache = true;
1432 const CachedNode* cachedFocusNode = m_frameCacheKit->currentFocus();
1433 DBG_NAV_LOGD("cachedFocusNode=%d (nodePointer=%p)",
1434 cachedFocusNode ? cachedFocusNode->index() : 0,
1435 cachedFocusNode ? cachedFocusNode->nodePointer() : 0);
1437 gFrameCacheMutex.unlock();
1440 void WebViewCore::updateFrameCacheIfLoading()
1442 if (!m_check_domtree_version)
1446 struct TouchNodeData {
1451 // get the bounding box of the Node
1452 static IntRect getAbsoluteBoundingBox(Node* node) {
1454 RenderObject* render = node->renderer();
1455 if (render->isRenderInline())
1456 rect = toRenderInline(render)->linesVisibleOverflowBoundingBox();
1457 else if (render->isBox())
1458 rect = toRenderBox(render)->visualOverflowRect();
1459 else if (render->isText())
1460 rect = toRenderText(render)->linesBoundingBox();
1462 LOGE("getAbsoluteBoundingBox failed for node %p, name %s", node, render->renderName());
1463 FloatPoint absPos = render->localToAbsolute();
1464 rect.move(absPos.x(), absPos.y());
1468 // get the highlight rectangles for the touch point (x, y) with the slop
1469 Vector<IntRect> WebViewCore::getTouchHighlightRects(int x, int y, int slop)
1471 Vector<IntRect> rects;
1472 m_mousePos = IntPoint(x - m_scrollOffsetX, y - m_scrollOffsetY);
1473 #ifdef ANDROID_HITTEST_WITHSIZE
1474 HitTestResult hitTestResult = m_mainFrame->eventHandler()->hitTestResultAtPoint(IntPoint(x, y),
1475 false, false, DontHitTestScrollbars, IntSize(slop, slop));
1476 if (!hitTestResult.innerNode() || !hitTestResult.innerNode()->inDocument()) {
1477 LOGE("Should not happen: no in document Node found");
1480 const Vector<RefPtr<Node> >& list = hitTestResult.rawNodeList();
1481 if (list.isEmpty()) {
1482 LOGE("Should not happen: no raw node found");
1485 Frame* frame = hitTestResult.innerNode()->document()->frame();
1486 Vector<TouchNodeData> nodeDataList;
1487 Vector<RefPtr<Node> >::const_iterator last = list.end();
1488 for (Vector<RefPtr<Node> >::const_iterator it = list.begin(); it != last; ++it) {
1489 // TODO: it seems reasonable to not search across the frame. Isn't it?
1490 // if the node is not in the same frame as the innerNode, skip it
1491 if (it->get()->document()->frame() != frame)
1493 // traverse up the tree to find the first node that needs highlight
1495 Node* eventNode = it->get();
1497 RenderObject* render = eventNode->renderer();
1498 if (render->isBody() || render->isRenderView())
1500 if (eventNode->supportsFocus()
1501 || eventNode->hasEventListeners(eventNames().clickEvent)
1502 || eventNode->hasEventListeners(eventNames().mousedownEvent)
1503 || eventNode->hasEventListeners(eventNames().mouseupEvent)) {
1507 // the nodes in the rawNodeList() are ordered based on z-index during hit testing.
1508 // so do not search for the eventNode across explicit z-index border.
1509 // TODO: this is a hard one to call. z-index is quite complicated as its value only
1510 // matters when you compare two RenderLayer in the same hierarchy level. e.g. in
1511 // the following example, "b" is on the top as its z level is the highest. even "c"
1512 // has 100 as z-index, it is still below "d" as its parent has the same z-index as
1513 // "d" and logically before "d". Of course "a" is the lowest in the z level.
1521 // If the fat point touches everyone, the order in the list should be "b", "d", "c"
1522 // and "a". When we search for the event node for "b", we really don't want "a" as
1523 // in the z-order it is behind everything else.
1524 if (!render->style()->hasAutoZIndex())
1526 eventNode = eventNode->parentNode();
1528 // didn't find any eventNode, skip it
1531 // first quick check whether it is a duplicated node before computing bounding box
1532 Vector<TouchNodeData>::const_iterator nlast = nodeDataList.end();
1533 for (Vector<TouchNodeData>::const_iterator n = nodeDataList.begin(); n != nlast; ++n) {
1534 // found the same node, skip it
1535 if (eventNode == n->mNode) {
1542 // next check whether the node is fully covered by or fully covering another node.
1544 IntRect rect = getAbsoluteBoundingBox(eventNode);
1545 if (rect.isEmpty()) {
1546 // if the node's bounds is empty and it is not a ContainerNode, skip it.
1547 if (!eventNode->isContainerNode())
1549 // if the node's children are all positioned objects, its bounds can be empty.
1550 // Walk through the children to find the bounding box.
1551 Node* child = static_cast<const ContainerNode*>(eventNode)->firstChild();
1554 if (child->renderer())
1555 childrect = getAbsoluteBoundingBox(child);
1556 if (!childrect.isEmpty()) {
1557 rect.unite(childrect);
1558 child = child->traverseNextSibling(eventNode);
1560 child = child->traverseNextNode(eventNode);
1563 for (int i = nodeDataList.size() - 1; i >= 0; i--) {
1564 TouchNodeData n = nodeDataList.at(i);
1565 // the new node is enclosing an existing node, skip it
1566 if (rect.contains(n.mBounds)) {
1570 // the new node is fully inside an existing node, remove the existing node
1571 if (n.mBounds.contains(rect))
1572 nodeDataList.remove(i);
1575 TouchNodeData newNode;
1576 newNode.mNode = eventNode;
1577 newNode.mBounds = rect;
1578 nodeDataList.append(newNode);
1581 if (!nodeDataList.size())
1583 // finally select the node with the largest overlap with the fat point
1584 TouchNodeData final;
1586 IntPoint docPos = frame->view()->windowToContents(m_mousePos);
1587 IntRect testRect(docPos.x() - slop, docPos.y() - slop, 2 * slop + 1, 2 * slop + 1);
1589 Vector<TouchNodeData>::const_iterator nlast = nodeDataList.end();
1590 for (Vector<TouchNodeData>::const_iterator n = nodeDataList.begin(); n != nlast; ++n) {
1591 IntRect rect = n->mBounds;
1592 rect.intersect(testRect);
1593 int a = rect.width() * rect.height();
1599 // now get the node's highlight rectangles in the page coordinate system
1601 IntPoint frameAdjust;
1602 if (frame != m_mainFrame) {
1603 frameAdjust = frame->view()->contentsToWindow(IntPoint());
1604 frameAdjust.move(m_scrollOffsetX, m_scrollOffsetY);
1606 if (final.mNode->isLink()) {
1607 // most of the links are inline instead of box style. So the bounding box is not
1608 // a good representation for the highlights. Get the list of rectangles instead.
1609 RenderObject* render = final.mNode->renderer();
1610 IntPoint offset = roundedIntPoint(render->localToAbsolute());
1611 render->absoluteRects(rects, offset.x() + frameAdjust.x(), offset.y() + frameAdjust.y());
1612 bool inside = false;
1613 int distance = INT_MAX;
1614 int newx = x, newy = y;
1615 int i = rects.size();
1617 if (rects[i].isEmpty()) {
1621 // check whether the point (x, y) is inside one of the rectangles.
1624 if (rects[i].contains(x, y)) {
1628 if (x >= rects[i].x() && x < rects[i].right()) {
1629 if (y < rects[i].y()) {
1630 if (rects[i].y() - y < distance) {
1632 newy = rects[i].y();
1633 distance = rects[i].y() - y;
1635 } else if (y >= rects[i].bottom()) {
1636 if (y - rects[i].bottom() + 1 < distance) {
1638 newy = rects[i].bottom() - 1;
1639 distance = y - rects[i].bottom() + 1;
1642 } else if (y >= rects[i].y() && y < rects[i].bottom()) {
1643 if (x < rects[i].x()) {
1644 if (rects[i].x() - x < distance) {
1645 newx = rects[i].x();
1647 distance = rects[i].x() - x;
1649 } else if (x >= rects[i].right()) {
1650 if (x - rects[i].right() + 1 < distance) {
1651 newx = rects[i].right() - 1;
1653 distance = x - rects[i].right() + 1;
1658 if (!rects.isEmpty()) {
1660 // if neither x nor y has overlap, just pick the top/left of the first rectangle
1661 if (newx == x && newy == y) {
1662 newx = rects[0].x();
1663 newy = rects[0].y();
1665 m_mousePos.setX(newx - m_scrollOffsetX);
1666 m_mousePos.setY(newy - m_scrollOffsetY);
1667 DBG_NAV_LOGD("Move x/y from (%d, %d) to (%d, %d) scrollOffset is (%d, %d)",
1668 x, y, m_mousePos.x() + m_scrollOffsetX, m_mousePos.y() + m_scrollOffsetY,
1669 m_scrollOffsetX, m_scrollOffsetY);
1674 IntRect rect = final.mBounds;
1675 rect.move(frameAdjust.x(), frameAdjust.y());
1677 // adjust m_mousePos if it is not inside the returned highlight rectangle
1678 testRect.move(frameAdjust.x(), frameAdjust.y());
1679 testRect.intersect(rect);
1680 if (!testRect.contains(x, y)) {
1681 m_mousePos = testRect.center();
1682 m_mousePos.move(-m_scrollOffsetX, -m_scrollOffsetY);
1683 DBG_NAV_LOGD("Move x/y from (%d, %d) to (%d, %d) scrollOffset is (%d, %d)",
1684 x, y, m_mousePos.x() + m_scrollOffsetX, m_mousePos.y() + m_scrollOffsetY,
1685 m_scrollOffsetX, m_scrollOffsetY);
1692 ///////////////////////////////////////////////////////////////////////////////
1694 void WebViewCore::addPlugin(PluginWidgetAndroid* w)
1696 // SkDebugf("----------- addPlugin %p", w);
1697 /* The plugin must be appended to the end of the array. This ensures that if
1698 the plugin is added while iterating through the array (e.g. sendEvent(...))
1699 that the iteration process is not corrupted.
1701 *m_plugins.append() = w;
1704 void WebViewCore::removePlugin(PluginWidgetAndroid* w)
1706 // SkDebugf("----------- removePlugin %p", w);
1707 int index = m_plugins.find(w);
1709 SkDebugf("--------------- pluginwindow not found! %p\n", w);
1711 m_plugins.removeShuffle(index);
1715 bool WebViewCore::isPlugin(PluginWidgetAndroid* w) const
1717 return m_plugins.find(w) >= 0;
1720 void WebViewCore::invalPlugin(PluginWidgetAndroid* w)
1722 const double PLUGIN_INVAL_DELAY = 1.0 / 60;
1724 if (!m_pluginInvalTimer.isActive()) {
1725 m_pluginInvalTimer.startOneShot(PLUGIN_INVAL_DELAY);
1729 void WebViewCore::drawPlugins()
1731 SkRegion inval; // accumualte what needs to be redrawn
1732 PluginWidgetAndroid** iter = m_plugins.begin();
1733 PluginWidgetAndroid** stop = m_plugins.end();
1735 for (; iter < stop; ++iter) {
1736 PluginWidgetAndroid* w = *iter;
1738 if (w->isDirty(&dirty)) {
1740 inval.op(dirty, SkRegion::kUnion_Op);
1744 if (!inval.isEmpty()) {
1745 // inval.getBounds() is our rectangle
1746 const SkIRect& bounds = inval.getBounds();
1747 WebCore::IntRect r(bounds.fLeft, bounds.fTop,
1748 bounds.width(), bounds.height());
1749 this->viewInvalidate(r);
1753 void WebViewCore::notifyPluginsOnFrameLoad(const Frame* frame) {
1754 // if frame is the parent then notify all plugins
1755 if (!frame->tree()->parent()) {
1756 // trigger an event notifying the plugins that the page has loaded
1758 SkANP::InitEvent(&event, kLifecycle_ANPEventType);
1759 event.data.lifecycle.action = kOnLoad_ANPLifecycleAction;
1760 sendPluginEvent(event);
1762 // else if frame's parent has completed
1763 else if (!frame->tree()->parent()->loader()->isLoading()) {
1764 // send to all plugins who have this frame in their heirarchy
1765 PluginWidgetAndroid** iter = m_plugins.begin();
1766 PluginWidgetAndroid** stop = m_plugins.end();
1767 for (; iter < stop; ++iter) {
1768 Frame* currentFrame = (*iter)->pluginView()->parentFrame();
1769 while (currentFrame) {
1770 if (frame == currentFrame) {
1772 SkANP::InitEvent(&event, kLifecycle_ANPEventType);
1773 event.data.lifecycle.action = kOnLoad_ANPLifecycleAction;
1774 (*iter)->sendEvent(event);
1777 currentFrame = currentFrame->tree()->parent();
1783 void WebViewCore::sendPluginVisibleScreen()
1785 /* We may want to cache the previous values and only send the notification
1786 to the plugin in the event that one of the values has changed.
1789 ANPRectI visibleRect;
1790 visibleRect.left = m_scrollOffsetX;
1791 visibleRect.top = m_scrollOffsetY;
1792 visibleRect.right = m_scrollOffsetX + m_screenWidth;
1793 visibleRect.bottom = m_scrollOffsetY + m_screenHeight;
1795 PluginWidgetAndroid** iter = m_plugins.begin();
1796 PluginWidgetAndroid** stop = m_plugins.end();
1797 for (; iter < stop; ++iter) {
1798 (*iter)->setVisibleScreen(visibleRect, m_scale);
1802 void WebViewCore::sendPluginEvent(const ANPEvent& evt)
1804 /* The list of plugins may be manipulated as we iterate through the list.
1805 This implementation allows for the addition of new plugins during an
1806 iteration, but may fail if a plugin is removed. Currently, there are not
1807 any use cases where a plugin is deleted while processing this loop, but
1808 if it does occur we will have to use an alternate data structure and/or
1809 iteration mechanism.
1811 for (int x = 0; x < m_plugins.count(); x++) {
1812 m_plugins[x]->sendEvent(evt);
1816 PluginWidgetAndroid* WebViewCore::getPluginWidget(NPP npp)
1818 PluginWidgetAndroid** iter = m_plugins.begin();
1819 PluginWidgetAndroid** stop = m_plugins.end();
1820 for (; iter < stop; ++iter) {
1821 if ((*iter)->pluginView()->instance() == npp) {
1828 static PluginView* nodeIsPlugin(Node* node) {
1829 RenderObject* renderer = node->renderer();
1830 if (renderer && renderer->isWidget()) {
1831 Widget* widget = static_cast<RenderWidget*>(renderer)->widget();
1832 if (widget && widget->isPluginView())
1833 return static_cast<PluginView*>(widget);
1838 Node* WebViewCore::cursorNodeIsPlugin() {
1839 gCursorBoundsMutex.lock();
1840 bool hasCursorBounds = m_hasCursorBounds;
1841 Frame* frame = (Frame*) m_cursorFrame;
1842 Node* node = (Node*) m_cursorNode;
1843 gCursorBoundsMutex.unlock();
1844 if (hasCursorBounds && CacheBuilder::validNode(m_mainFrame, frame, node)
1845 && nodeIsPlugin(node)) {
1851 ///////////////////////////////////////////////////////////////////////////////
1852 void WebViewCore::moveMouseIfLatest(int moveGeneration,
1853 WebCore::Frame* frame, int x, int y)
1855 DBG_NAV_LOGD("m_moveGeneration=%d moveGeneration=%d"
1856 " frame=%p x=%d y=%d",
1857 m_moveGeneration, moveGeneration, frame, x, y);
1858 if (m_moveGeneration > moveGeneration) {
1859 DBG_NAV_LOGD("m_moveGeneration=%d > moveGeneration=%d",
1860 m_moveGeneration, moveGeneration);
1861 return; // short-circuit if a newer move has already been generated
1863 m_lastGeneration = moveGeneration;
1864 moveMouse(frame, x, y);
1867 void WebViewCore::moveFocus(WebCore::Frame* frame, WebCore::Node* node)
1869 DBG_NAV_LOGD("frame=%p node=%p", frame, node);
1870 if (!node || !CacheBuilder::validNode(m_mainFrame, frame, node)
1871 || !node->isElementNode())
1873 // Code borrowed from FocusController::advanceFocus
1874 WebCore::FocusController* focusController
1875 = m_mainFrame->page()->focusController();
1876 WebCore::Document* oldDoc
1877 = focusController->focusedOrMainFrame()->document();
1878 if (oldDoc->focusedNode() == node)
1880 if (node->document() != oldDoc)
1881 oldDoc->setFocusedNode(0);
1882 focusController->setFocusedFrame(frame);
1883 static_cast<WebCore::Element*>(node)->focus(false);
1886 // Update mouse position
1887 void WebViewCore::moveMouse(WebCore::Frame* frame, int x, int y)
1889 DBG_NAV_LOGD("frame=%p x=%d y=%d scrollOffset=(%d,%d)", frame,
1890 x, y, m_scrollOffsetX, m_scrollOffsetY);
1891 if (!frame || CacheBuilder::validNode(m_mainFrame, frame, NULL) == false)
1892 frame = m_mainFrame;
1893 // mouse event expects the position in the window coordinate
1894 m_mousePos = WebCore::IntPoint(x - m_scrollOffsetX, y - m_scrollOffsetY);
1895 // validNode will still return true if the node is null, as long as we have
1896 // a valid frame. Do not want to make a call on frame unless it is valid.
1897 WebCore::PlatformMouseEvent mouseEvent(m_mousePos, m_mousePos,
1898 WebCore::NoButton, WebCore::MouseEventMoved, 1, false, false, false,
1899 false, WTF::currentTime());
1900 frame->eventHandler()->handleMouseMoveEvent(mouseEvent);
1901 updateCacheOnNodeChange();
1904 void WebViewCore::setSelection(int start, int end)
1906 WebCore::Node* focus = currentFocus();
1909 WebCore::RenderObject* renderer = focus->renderer();
1910 if (!renderer || (!renderer->isTextField() && !renderer->isTextArea()))
1912 WebCore::RenderTextControl* rtc = static_cast<WebCore::RenderTextControl*>(renderer);
1918 // Tell our EditorClient that this change was generated from the UI, so it
1919 // does not need to echo it to the UI.
1920 EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
1921 m_mainFrame->editor()->client());
1922 client->setUiGeneratedSelectionChange(true);
1923 rtc->setSelectionRange(start, end);
1924 client->setUiGeneratedSelectionChange(false);
1925 WebCore::Frame* focusedFrame = focus->document()->frame();
1926 focusedFrame->revealSelection();
1927 setFocusControllerActive(focusedFrame, true);
1930 String WebViewCore::modifySelection(const String& alter, const String& direction, const String& granularity)
1932 DOMSelection* selection = m_mainFrame->domWindow()->getSelection();
1934 if (selection->rangeCount() == 0) {
1935 Document* document = m_mainFrame->document();
1936 HTMLElement* body = document->body();
1939 PassRefPtr<Range> rangeRef = document->createRange();
1940 rangeRef->setStart(PassRefPtr<Node>(body), 0, ec);
1942 LOGE("Error setting range start. Error code: %d", ec);
1946 rangeRef->setEnd(PassRefPtr<Node>(body), 0, ec);
1948 LOGE("Error setting range end. Error code: %d", ec);
1952 selection->addRange(rangeRef.get());
1955 if (equalIgnoringCase(direction, "forward")) {
1956 selection->collapseToEnd();
1957 } else if (equalIgnoringCase(direction, "backward")) {
1958 selection->collapseToStart();
1960 LOGE("Invalid direction: %s", direction.utf8().data());
1964 // NOTE: The selection of WebKit misbehaves and I need to add some
1965 // voodoo here to force it behave well. Rachel did something similar
1966 // in JS and I want to make sure it is optimal before adding it here.
1968 selection->modify(alter, direction, granularity);
1969 String selection_string = selection->toString();
1970 LOGD("Selection string: %s", selection_string.utf8().data());
1972 return selection_string;
1975 void WebViewCore::deleteSelection(int start, int end, int textGeneration)
1977 setSelection(start, end);
1980 WebCore::Node* focus = currentFocus();
1983 // Prevent our editor client from passing a message to change the
1985 EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
1986 m_mainFrame->editor()->client());
1987 client->setUiGeneratedSelectionChange(true);
1988 PlatformKeyboardEvent down(kKeyCodeDel, 0, 0, true, false, false, false);
1989 PlatformKeyboardEvent up(kKeyCodeDel, 0, 0, false, false, false, false);
1992 client->setUiGeneratedSelectionChange(false);
1993 m_textGeneration = textGeneration;
1996 void WebViewCore::replaceTextfieldText(int oldStart,
1997 int oldEnd, const WebCore::String& replace, int start, int end,
2000 WebCore::Node* focus = currentFocus();
2003 setSelection(oldStart, oldEnd);
2004 // Prevent our editor client from passing a message to change the
2006 EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
2007 m_mainFrame->editor()->client());
2008 client->setUiGeneratedSelectionChange(true);
2009 WebCore::TypingCommand::insertText(focus->document(), replace,
2011 client->setUiGeneratedSelectionChange(false);
2012 setSelection(start, end);
2013 m_textGeneration = textGeneration;
2016 void WebViewCore::passToJs(int generation, const WebCore::String& current,
2017 const PlatformKeyboardEvent& event)
2019 WebCore::Node* focus = currentFocus();
2021 DBG_NAV_LOG("!focus");
2025 WebCore::RenderObject* renderer = focus->renderer();
2026 if (!renderer || (!renderer->isTextField() && !renderer->isTextArea())) {
2027 DBG_NAV_LOGD("renderer==%p || not text", renderer);
2031 // Block text field updates during a key press.
2032 m_blockTextfieldUpdates = true;
2033 // Also prevent our editor client from passing a message to change the
2035 EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
2036 m_mainFrame->editor()->client());
2037 client->setUiGeneratedSelectionChange(true);
2039 client->setUiGeneratedSelectionChange(false);
2040 m_blockTextfieldUpdates = false;
2041 m_textGeneration = generation;
2042 setFocusControllerActive(focus->document()->frame(), true);
2043 WebCore::RenderTextControl* renderText =
2044 static_cast<WebCore::RenderTextControl*>(renderer);
2045 WebCore::String test = renderText->text();
2046 if (test == current) {
2047 DBG_NAV_LOG("test == current");
2050 // If the text changed during the key event, update the UI text field.
2051 updateTextfield(focus, false, test);
2054 void WebViewCore::scrollFocusedTextInput(float xPercent, int y)
2056 WebCore::Node* focus = currentFocus();
2058 DBG_NAV_LOG("!focus");
2062 WebCore::RenderObject* renderer = focus->renderer();
2063 if (!renderer || (!renderer->isTextField() && !renderer->isTextArea())) {
2064 DBG_NAV_LOGD("renderer==%p || not text", renderer);
2068 WebCore::RenderTextControl* renderText =
2069 static_cast<WebCore::RenderTextControl*>(renderer);
2070 int x = (int) (xPercent * (renderText->scrollWidth() -
2071 renderText->clientWidth()));
2072 DBG_NAV_LOGD("x=%d y=%d xPercent=%g scrollW=%d clientW=%d", x, y,
2073 xPercent, renderText->scrollWidth(), renderText->clientWidth());
2074 renderText->setScrollLeft(x);
2075 renderText->setScrollTop(y);
2078 void WebViewCore::setFocusControllerActive(WebCore::Frame* frame, bool active)
2081 WebCore::Node* focus = currentFocus();
2083 frame = focus->document()->frame();
2085 frame = m_mainFrame;
2087 WebCore::FocusController* controller = frame->page()->focusController();
2088 controller->setActive(active);
2089 controller->setFocused(active);
2092 void WebViewCore::saveDocumentState(WebCore::Frame* frame)
2094 if (!CacheBuilder::validNode(m_mainFrame, frame, 0))
2095 frame = m_mainFrame;
2096 WebCore::HistoryItem *item = frame->loader()->history()->currentItem();
2098 // item can be null when there is no offical URL for the current page. This happens
2099 // when the content is loaded using with WebCoreFrameBridge::LoadData() and there
2100 // is no failing URL (common case is when content is loaded using data: scheme)
2102 item->setDocumentState(frame->document()->formElementsState());
2106 // Convert a WebCore::String into an array of characters where the first
2107 // character represents the length, for easy conversion to java.
2108 static uint16_t* stringConverter(const WebCore::String& text)
2110 size_t length = text.length();
2111 uint16_t* itemName = new uint16_t[length+1];
2112 itemName[0] = (uint16_t)length;
2113 uint16_t* firstChar = &(itemName[1]);
2114 memcpy((void*)firstChar, text.characters(), sizeof(UChar)*length);
2118 // Response to dropdown created for a listbox.
2119 class ListBoxReply : public WebCoreReply {
2121 ListBoxReply(WebCore::HTMLSelectElement* select, WebCore::Frame* frame, WebViewCore* view)
2127 // Response used if the listbox only allows single selection.
2128 // index is listIndex of the selected item, or -1 if nothing is selected.
2129 virtual void replyInt(int index)
2132 // Special value for cancel. Do nothing.
2135 // If the select element no longer exists, due to a page change, etc,
2137 if (!m_select || !CacheBuilder::validNode(m_viewImpl->m_mainFrame,
2140 // Use a pointer to HTMLSelectElement's superclass, where
2141 // listToOptionIndex is public.
2142 SelectElement* selectElement = m_select;
2143 int optionIndex = selectElement->listToOptionIndex(index);
2144 m_select->setSelectedIndex(optionIndex, true);
2145 m_select->dispatchFormControlChangeEvent();
2146 m_viewImpl->contentInvalidate(m_select->getRect());
2149 // Response if the listbox allows multiple selection. array stores the listIndices
2150 // of selected positions.
2151 virtual void replyIntArray(const int* array, int count)
2153 // If the select element no longer exists, due to a page change, etc,
2155 if (!m_select || !CacheBuilder::validNode(m_viewImpl->m_mainFrame,
2159 // If count is 1 or 0, use replyInt.
2160 SkASSERT(count > 1);
2162 const WTF::Vector<Element*>& items = m_select->listItems();
2163 int totalItems = static_cast<int>(items.size());
2164 // Keep track of the position of the value we are comparing against.
2166 // The value we are comparing against.
2167 int selection = array[arrayIndex];
2168 WebCore::HTMLOptionElement* option;
2169 for (int listIndex = 0; listIndex < totalItems; listIndex++) {
2170 if (items[listIndex]->hasLocalName(WebCore::HTMLNames::optionTag)) {
2171 option = static_cast<WebCore::HTMLOptionElement*>(
2173 if (listIndex == selection) {
2174 option->setSelectedState(true);
2176 if (arrayIndex == count)
2179 selection = array[arrayIndex];
2181 option->setSelectedState(false);
2184 m_select->dispatchFormControlChangeEvent();
2185 m_viewImpl->contentInvalidate(m_select->getRect());
2188 // The select element associated with this listbox.
2189 WebCore::HTMLSelectElement* m_select;
2190 // The frame of this select element, to verify that it is valid.
2191 WebCore::Frame* m_frame;
2192 // For calling invalidate and checking the select element's validity
2193 WebViewCore* m_viewImpl;
2196 // Create an array of java Strings.
2197 static jobjectArray makeLabelArray(JNIEnv* env, const uint16_t** labels, size_t count)
2199 jclass stringClass = env->FindClass("java/lang/String");
2200 LOG_ASSERT(stringClass, "Could not find java/lang/String");
2201 jobjectArray array = env->NewObjectArray(count, stringClass, 0);
2202 LOG_ASSERT(array, "Could not create new string array");
2204 for (size_t i = 0; i < count; i++) {
2205 jobject newString = env->NewString(&labels[i][1], labels[i][0]);
2206 env->SetObjectArrayElement(array, i, newString);
2207 env->DeleteLocalRef(newString);
2208 checkException(env);
2210 env->DeleteLocalRef(stringClass);
2214 void WebViewCore::openFileChooser(PassRefPtr<WebCore::FileChooser> chooser) {
2217 JNIEnv* env = JSC::Bindings::getJNIEnv();
2219 WebCore::String acceptType = chooser->acceptTypes();
2220 jstring jAcceptType = env->NewString(const_cast<unsigned short*>(acceptType.characters()), acceptType.length());
2221 jstring jName = (jstring) env->CallObjectMethod(
2222 m_javaGlue->object(env).get(), m_javaGlue->m_openFileChooser, jAcceptType);
2223 checkException(env);
2224 env->DeleteLocalRef(jAcceptType);
2226 const UChar* string = static_cast<const UChar*>(env->GetStringChars(jName, NULL));
2231 WebCore::String webcoreString = to_string(env, jName);
2232 env->ReleaseStringChars(jName, string);
2234 if (webcoreString.length())
2235 chooser->chooseFile(webcoreString);
2238 void WebViewCore::listBoxRequest(WebCoreReply* reply, const uint16_t** labels, size_t count, const int enabled[], size_t enabledCount,
2239 bool multiple, const int selected[], size_t selectedCountOrSelection)
2241 // If m_popupReply is not null, then we already have a list showing.
2242 if (m_popupReply != 0)
2245 LOG_ASSERT(m_javaGlue->m_obj, "No java widget associated with this view!");
2247 // Create an array of java Strings for the drop down.
2248 JNIEnv* env = JSC::Bindings::getJNIEnv();
2249 jobjectArray labelArray = makeLabelArray(env, labels, count);
2251 // Create an array determining whether each item is enabled.
2252 jintArray enabledArray = env->NewIntArray(enabledCount);
2253 checkException(env);
2254 jint* ptrArray = env->GetIntArrayElements(enabledArray, 0);
2255 checkException(env);
2256 for (size_t i = 0; i < enabledCount; i++) {
2257 ptrArray[i] = enabled[i];
2259 env->ReleaseIntArrayElements(enabledArray, ptrArray, 0);
2260 checkException(env);
2263 // Pass up an array representing which items are selected.
2264 jintArray selectedArray = env->NewIntArray(selectedCountOrSelection);
2265 checkException(env);
2266 jint* selArray = env->GetIntArrayElements(selectedArray, 0);
2267 checkException(env);
2268 for (size_t i = 0; i < selectedCountOrSelection; i++) {
2269 selArray[i] = selected[i];
2271 env->ReleaseIntArrayElements(selectedArray, selArray, 0);
2273 env->CallVoidMethod(m_javaGlue->object(env).get(),
2274 m_javaGlue->m_requestListBox, labelArray, enabledArray,
2276 env->DeleteLocalRef(selectedArray);
2278 // Pass up the single selection.
2279 env->CallVoidMethod(m_javaGlue->object(env).get(),
2280 m_javaGlue->m_requestSingleListBox, labelArray, enabledArray,
2281 selectedCountOrSelection);
2284 env->DeleteLocalRef(labelArray);
2285 env->DeleteLocalRef(enabledArray);
2286 checkException(env);
2289 m_popupReply = reply;
2292 bool WebViewCore::key(const PlatformKeyboardEvent& event)
2294 WebCore::EventHandler* eventHandler;
2295 WebCore::Node* focusNode = currentFocus();
2296 DBG_NAV_LOGD("keyCode=%s unichar=%d focusNode=%p",
2297 event.keyIdentifier().utf8().data(), event.unichar(), focusNode);
2299 WebCore::Frame* frame = focusNode->document()->frame();
2300 eventHandler = frame->eventHandler();
2301 if (focusNode->isContentEditable()) {
2302 // keyEvent will return true even if the contentEditable did not
2303 // change its selection. In the case that it does not, we want to
2304 // return false so that the key will be sent back to our navigation
2306 VisibleSelection old = frame->selection()->selection();
2307 eventHandler->keyEvent(event);
2308 return frame->selection()->selection() != old;
2311 eventHandler = m_mainFrame->eventHandler();
2313 return eventHandler->keyEvent(event);
2316 // For when the user clicks the trackball
2317 void WebViewCore::click(WebCore::Frame* frame, WebCore::Node* node) {
2319 WebCore::IntPoint pt = m_mousePos;
2320 pt.move(m_scrollOffsetX, m_scrollOffsetY);
2321 WebCore::HitTestResult hitTestResult = m_mainFrame->eventHandler()->
2322 hitTestResultAtPoint(pt, false);
2323 node = hitTestResult.innerNode();
2324 frame = node->document()->frame();
2325 DBG_NAV_LOGD("m_mousePos=(%d,%d) m_scrollOffset=(%d,%d) pt=(%d,%d)"
2326 " node=%p", m_mousePos.x(), m_mousePos.y(),
2327 m_scrollOffsetX, m_scrollOffsetY, pt.x(), pt.y(), node);
2330 EditorClientAndroid* client
2331 = static_cast<EditorClientAndroid*>(
2332 m_mainFrame->editor()->client());
2333 client->setShouldChangeSelectedRange(false);
2334 handleMouseClick(frame, node);
2335 client->setShouldChangeSelectedRange(true);
2339 #if USE(ACCELERATED_COMPOSITING)
2340 GraphicsLayerAndroid* WebViewCore::graphicsRootLayer() const
2342 RenderView* contentRenderer = m_mainFrame->contentRenderer();
2343 if (!contentRenderer)
2345 return static_cast<GraphicsLayerAndroid*>(
2346 contentRenderer->compositor()->rootPlatformLayer());
2350 bool WebViewCore::handleTouchEvent(int action, int x, int y, int metaState)
2352 bool preventDefault = false;
2354 #if USE(ACCELERATED_COMPOSITING)
2355 GraphicsLayerAndroid* rootLayer = graphicsRootLayer();
2357 rootLayer->pauseDisplay(true);
2360 #if ENABLE(TOUCH_EVENTS) // Android
2361 WebCore::TouchEventType type = WebCore::TouchStart;
2362 WebCore::PlatformTouchPoint::State touchState = WebCore::PlatformTouchPoint::TouchPressed;
2364 case 0: // MotionEvent.ACTION_DOWN
2365 type = WebCore::TouchStart;
2367 case 1: // MotionEvent.ACTION_UP
2368 type = WebCore::TouchEnd;
2369 touchState = WebCore::PlatformTouchPoint::TouchReleased;
2371 case 2: // MotionEvent.ACTION_MOVE
2372 type = WebCore::TouchMove;
2373 touchState = WebCore::PlatformTouchPoint::TouchMoved;
2375 case 3: // MotionEvent.ACTION_CANCEL
2376 type = WebCore::TouchCancel;
2377 touchState = WebCore::PlatformTouchPoint::TouchCancelled;
2379 case 0x100: // WebViewCore.ACTION_LONGPRESS
2380 type = WebCore::TouchLongPress;
2381 touchState = WebCore::PlatformTouchPoint::TouchPressed;
2383 case 0x200: // WebViewCore.ACTION_DOUBLETAP
2384 type = WebCore::TouchDoubleTap;
2385 touchState = WebCore::PlatformTouchPoint::TouchPressed;
2388 // We do not support other kinds of touch event inside WebCore
2390 LOGW("Java passed a touch event type that we do not support in WebCore: %d", action);
2394 // Track previous touch and if stationary set the state.
2395 WebCore::IntPoint pt(x - m_scrollOffsetX, y - m_scrollOffsetY);
2397 WebCore::PlatformTouchEvent te(pt, type, touchState, metaState);
2398 preventDefault = m_mainFrame->eventHandler()->handleTouchEvent(te);
2401 #if USE(ACCELERATED_COMPOSITING)
2403 rootLayer->pauseDisplay(false);
2405 return preventDefault;
2408 void WebViewCore::touchUp(int touchGeneration,
2409 WebCore::Frame* frame, WebCore::Node* node, int x, int y)
2411 if (touchGeneration == 0) {
2412 // m_mousePos should be set in getTouchHighlightRects()
2413 WebCore::HitTestResult hitTestResult = m_mainFrame->eventHandler()->hitTestResultAtPoint(m_mousePos, false);
2414 node = hitTestResult.innerNode();
2416 frame = node->document()->frame();
2419 DBG_NAV_LOGD("touch up on (%d, %d), scrollOffset is (%d, %d), node:%p, frame:%p", m_mousePos.x() + m_scrollOffsetX, m_mousePos.y() + m_scrollOffsetY, m_scrollOffsetX, m_scrollOffsetY, node, frame);
2421 if (m_touchGeneration > touchGeneration) {
2422 DBG_NAV_LOGD("m_touchGeneration=%d > touchGeneration=%d"
2423 " x=%d y=%d", m_touchGeneration, touchGeneration, x, y);
2424 return; // short circuit if a newer touch has been generated
2426 // This moves m_mousePos to the correct place, and handleMouseClick uses
2427 // m_mousePos to determine where the click happens.
2428 moveMouse(frame, x, y);
2429 m_lastGeneration = touchGeneration;
2431 if (frame && CacheBuilder::validNode(m_mainFrame, frame, 0)) {
2432 frame->loader()->resetMultipleFormSubmissionProtection();
2434 DBG_NAV_LOGD("touchGeneration=%d handleMouseClick frame=%p node=%p"
2435 " x=%d y=%d", touchGeneration, frame, node, x, y);
2436 handleMouseClick(frame, node);
2439 // Common code for both clicking with the trackball and touchUp
2440 bool WebViewCore::handleMouseClick(WebCore::Frame* framePtr, WebCore::Node* nodePtr)
2442 bool valid = framePtr == NULL
2443 || CacheBuilder::validNode(m_mainFrame, framePtr, nodePtr);
2444 WebFrame* webFrame = WebFrame::getWebFrame(m_mainFrame);
2445 if (valid && nodePtr) {
2446 // Need to special case area tags because an image map could have an area element in the middle
2447 // so when attempting to get the default, the point chosen would be follow the wrong link.
2448 if (nodePtr->hasTagName(WebCore::HTMLNames::areaTag)) {
2449 webFrame->setUserInitiatedClick(true);
2450 nodePtr->dispatchSimulatedClick(0, true, true);
2451 webFrame->setUserInitiatedClick(false);
2452 DBG_NAV_LOG("area");
2455 WebCore::RenderObject* renderer = nodePtr->renderer();
2456 if (renderer && (renderer->isMenuList() || renderer->isListBox())) {
2457 WebCore::HTMLSelectElement* select = static_cast<WebCore::HTMLSelectElement*>(nodePtr);
2458 const WTF::Vector<WebCore::Element*>& listItems = select->listItems();
2459 SkTDArray<const uint16_t*> names;
2460 // Possible values for enabledArray. Keep in Sync with values in
2461 // InvokeListBox.Container in WebView.java
2464 OPTION_DISABLED = 0,
2467 SkTDArray<int> enabledArray;
2468 SkTDArray<int> selectedArray;
2469 int size = listItems.size();
2470 bool multiple = select->multiple();
2471 for (int i = 0; i < size; i++) {
2472 if (listItems[i]->hasTagName(WebCore::HTMLNames::optionTag)) {
2473 WebCore::HTMLOptionElement* option = static_cast<WebCore::HTMLOptionElement*>(listItems[i]);
2474 *names.append() = stringConverter(option->textIndentedToRespectGroupLabel());
2475 *enabledArray.append() = option->disabled() ? OPTION_DISABLED : OPTION_ENABLED;
2476 if (multiple && option->selected())
2477 *selectedArray.append() = i;
2478 } else if (listItems[i]->hasTagName(WebCore::HTMLNames::optgroupTag)) {
2479 WebCore::HTMLOptGroupElement* optGroup = static_cast<WebCore::HTMLOptGroupElement*>(listItems[i]);
2480 *names.append() = stringConverter(optGroup->groupLabelText());
2481 *enabledArray.append() = OPTGROUP;
2484 WebCoreReply* reply = new ListBoxReply(select, select->document()->frame(), this);
2485 // Use a pointer to HTMLSelectElement's superclass, where
2486 // optionToListIndex is public.
2487 SelectElement* selectElement = select;
2488 listBoxRequest(reply, names.begin(), size, enabledArray.begin(), enabledArray.count(),
2489 multiple, selectedArray.begin(), multiple ? selectedArray.count() :
2490 selectElement->optionToListIndex(select->selectedIndex()));
2491 DBG_NAV_LOG("menu list");
2495 if (!valid || !framePtr)
2496 framePtr = m_mainFrame;
2497 webFrame->setUserInitiatedClick(true);
2498 WebCore::PlatformMouseEvent mouseDown(m_mousePos, m_mousePos, WebCore::LeftButton,
2499 WebCore::MouseEventPressed, 1, false, false, false, false,
2500 WTF::currentTime());
2501 // ignore the return from as it will return true if the hit point can trigger selection change
2502 framePtr->eventHandler()->handleMousePressEvent(mouseDown);
2503 WebCore::PlatformMouseEvent mouseUp(m_mousePos, m_mousePos, WebCore::LeftButton,
2504 WebCore::MouseEventReleased, 1, false, false, false, false,
2505 WTF::currentTime());
2506 bool handled = framePtr->eventHandler()->handleMouseReleaseEvent(mouseUp);
2507 webFrame->setUserInitiatedClick(false);
2509 // If the user clicked on a textfield, make the focusController active
2510 // so we show the blinking cursor.
2511 WebCore::Node* focusNode = currentFocus();
2512 DBG_NAV_LOGD("m_mousePos={%d,%d} focusNode=%p handled=%s", m_mousePos.x(),
2513 m_mousePos.y(), focusNode, handled ? "true" : "false");
2515 WebCore::RenderObject* renderer = focusNode->renderer();
2516 if (renderer && (renderer->isTextField() || renderer->isTextArea())) {
2517 bool ime = !(static_cast<WebCore::HTMLInputElement*>(focusNode))
2519 setFocusControllerActive(framePtr, ime);
2521 RenderTextControl* rtc
2522 = static_cast<RenderTextControl*> (renderer);
2523 requestKeyboardWithSelection(focusNode, rtc->selectionStart(),
2524 rtc->selectionEnd());
2526 requestKeyboard(false);
2528 } else if (focusNode->isContentEditable()) {
2529 setFocusControllerActive(framePtr, true);
2530 requestKeyboard(true);
2536 void WebViewCore::popupReply(int index)
2539 m_popupReply->replyInt(index);
2540 Release(m_popupReply);
2545 void WebViewCore::popupReply(const int* array, int count)
2548 m_popupReply->replyIntArray(array, count);
2549 Release(m_popupReply);
2550 m_popupReply = NULL;
2554 void WebViewCore::addMessageToConsole(const WebCore::String& message, unsigned int lineNumber, const WebCore::String& sourceID, int msgLevel) {
2555 JNIEnv* env = JSC::Bindings::getJNIEnv();
2556 jstring jMessageStr = env->NewString((unsigned short *)message.characters(), message.length());
2557 jstring jSourceIDStr = env->NewString((unsigned short *)sourceID.characters(), sourceID.length());
2558 env->CallVoidMethod(m_javaGlue->object(env).get(),
2559 m_javaGlue->m_addMessageToConsole, jMessageStr, lineNumber,
2560 jSourceIDStr, msgLevel);
2561 env->DeleteLocalRef(jMessageStr);
2562 env->DeleteLocalRef(jSourceIDStr);
2563 checkException(env);
2566 void WebViewCore::jsAlert(const WebCore::String& url, const WebCore::String& text)
2568 JNIEnv* env = JSC::Bindings::getJNIEnv();
2569 jstring jInputStr = env->NewString((unsigned short *)text.characters(), text.length());
2570 jstring jUrlStr = env->NewString((unsigned short *)url.characters(), url.length());
2571 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsAlert, jUrlStr, jInputStr);
2572 env->DeleteLocalRef(jInputStr);
2573 env->DeleteLocalRef(jUrlStr);
2574 checkException(env);
2577 void WebViewCore::exceededDatabaseQuota(const WebCore::String& url, const WebCore::String& databaseIdentifier, const unsigned long long currentQuota, unsigned long long estimatedSize)
2579 #if ENABLE(DATABASE)
2580 JNIEnv* env = JSC::Bindings::getJNIEnv();
2581 jstring jDatabaseIdentifierStr = env->NewString((unsigned short *)databaseIdentifier.characters(), databaseIdentifier.length());
2582 jstring jUrlStr = env->NewString((unsigned short *)url.characters(), url.length());
2583 env->CallVoidMethod(m_javaGlue->object(env).get(),
2584 m_javaGlue->m_exceededDatabaseQuota, jUrlStr,
2585 jDatabaseIdentifierStr, currentQuota, estimatedSize);
2586 env->DeleteLocalRef(jDatabaseIdentifierStr);
2587 env->DeleteLocalRef(jUrlStr);
2588 checkException(env);
2592 void WebViewCore::reachedMaxAppCacheSize(const unsigned long long spaceNeeded)
2594 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
2595 JNIEnv* env = JSC::Bindings::getJNIEnv();
2596 env->CallVoidMethod(m_javaGlue->object(env).get(),
2597 m_javaGlue->m_reachedMaxAppCacheSize, spaceNeeded);
2598 checkException(env);
2602 void WebViewCore::populateVisitedLinks(WebCore::PageGroup* group)
2604 m_groupForVisitedLinks = group;
2605 JNIEnv* env = JSC::Bindings::getJNIEnv();
2606 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_populateVisitedLinks);
2607 checkException(env);
2610 void WebViewCore::geolocationPermissionsShowPrompt(const WebCore::String& origin)
2612 JNIEnv* env = JSC::Bindings::getJNIEnv();
2613 jstring originString = env->NewString((unsigned short *)origin.characters(), origin.length());
2614 env->CallVoidMethod(m_javaGlue->object(env).get(),
2615 m_javaGlue->m_geolocationPermissionsShowPrompt,
2617 env->DeleteLocalRef(originString);
2618 checkException(env);
2621 void WebViewCore::geolocationPermissionsHidePrompt()
2623 JNIEnv* env = JSC::Bindings::getJNIEnv();
2624 env->CallVoidMethod(m_javaGlue->object(env).get(),
2625 m_javaGlue->m_geolocationPermissionsHidePrompt);
2626 checkException(env);
2629 bool WebViewCore::jsConfirm(const WebCore::String& url, const WebCore::String& text)
2631 JNIEnv* env = JSC::Bindings::getJNIEnv();
2632 jstring jInputStr = env->NewString((unsigned short *)text.characters(), text.length());
2633 jstring jUrlStr = env->NewString((unsigned short *)url.characters(), url.length());
2634 jboolean result = env->CallBooleanMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsConfirm, jUrlStr, jInputStr);
2635 env->DeleteLocalRef(jInputStr);
2636 env->DeleteLocalRef(jUrlStr);
2637 checkException(env);
2641 bool WebViewCore::jsPrompt(const WebCore::String& url, const WebCore::String& text, const WebCore::String& defaultValue, WebCore::String& result)
2643 JNIEnv* env = JSC::Bindings::getJNIEnv();
2644 jstring jInputStr = env->NewString((unsigned short *)text.characters(), text.length());
2645 jstring jDefaultStr = env->NewString((unsigned short *)defaultValue.characters(), defaultValue.length());
2646 jstring jUrlStr = env->NewString((unsigned short *)url.characters(), url.length());
2647 jstring returnVal = (jstring) env->CallObjectMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsPrompt, jUrlStr, jInputStr, jDefaultStr);
2648 // If returnVal is null, it means that the user cancelled the dialog.
2652 result = to_string(env, returnVal);
2653 env->DeleteLocalRef(jInputStr);
2654 env->DeleteLocalRef(jDefaultStr);
2655 env->DeleteLocalRef(jUrlStr);
2656 checkException(env);
2660 bool WebViewCore::jsUnload(const WebCore::String& url, const WebCore::String& message)
2662 JNIEnv* env = JSC::Bindings::getJNIEnv();
2663 jstring jInputStr = env->NewString((unsigned short *)message.characters(), message.length());
2664 jstring jUrlStr = env->NewString((unsigned short *)url.characters(), url.length());
2665 jboolean result = env->CallBooleanMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsUnload, jUrlStr, jInputStr);
2666 env->DeleteLocalRef(jInputStr);
2667 env->DeleteLocalRef(jUrlStr);
2668 checkException(env);
2672 bool WebViewCore::jsInterrupt()
2674 JNIEnv* env = JSC::Bindings::getJNIEnv();
2675 jboolean result = env->CallBooleanMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsInterrupt);
2676 checkException(env);
2681 WebViewCore::getJavaObject()
2683 return getRealObject(JSC::Bindings::getJNIEnv(), m_javaGlue->m_obj);
2687 WebViewCore::getWebViewJavaObject()
2689 JNIEnv* env = JSC::Bindings::getJNIEnv();
2690 return env->GetObjectField(m_javaGlue->object(env).get(), gWebViewCoreFields.m_webView);
2693 void WebViewCore::updateTextSelection() {
2694 WebCore::Node* focusNode = currentFocus();
2697 RenderObject* renderer = focusNode->renderer();
2698 if (!renderer || (!renderer->isTextArea() && !renderer->isTextField()))
2700 RenderTextControl* rtc = static_cast<RenderTextControl*>(renderer);
2701 JNIEnv* env = JSC::Bindings::getJNIEnv();
2702 env->CallVoidMethod(m_javaGlue->object(env).get(),
2703 m_javaGlue->m_updateTextSelection, reinterpret_cast<int>(focusNode),
2704 rtc->selectionStart(), rtc->selectionEnd(), m_textGeneration);
2705 checkException(env);
2708 void WebViewCore::updateTextfield(WebCore::Node* ptr, bool changeToPassword,
2709 const WebCore::String& text)
2711 if (m_blockTextfieldUpdates)
2713 JNIEnv* env = JSC::Bindings::getJNIEnv();
2714 if (changeToPassword) {
2715 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_updateTextfield,
2716 (int) ptr, true, 0, m_textGeneration);
2717 checkException(env);
2720 int length = text.length();
2721 jstring string = env->NewString((unsigned short *) text.characters(), length);
2722 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_updateTextfield,
2723 (int) ptr, false, string, m_textGeneration);
2724 env->DeleteLocalRef(string);
2725 checkException(env);
2728 void WebViewCore::clearTextEntry()
2730 JNIEnv* env = JSC::Bindings::getJNIEnv();
2731 env->CallVoidMethod(m_javaGlue->object(env).get(),
2732 m_javaGlue->m_clearTextEntry);
2735 void WebViewCore::setBackgroundColor(SkColor c)
2737 WebCore::FrameView* view = m_mainFrame->view();
2741 // need (int) cast to find the right constructor
2742 WebCore::Color bcolor((int)SkColorGetR(c), (int)SkColorGetG(c),
2743 (int)SkColorGetB(c), (int)SkColorGetA(c));
2744 view->setBaseBackgroundColor(bcolor);
2746 // Background color of 0 indicates we want a transparent background
2748 view->setTransparent(true);
2751 jclass WebViewCore::getPluginClass(const WebCore::String& libName, const char* className)
2753 JNIEnv* env = JSC::Bindings::getJNIEnv();
2755 jstring libString = env->NewString(libName.characters(), libName.length());
2756 jstring classString = env->NewStringUTF(className);
2757 jobject pluginClass = env->CallObjectMethod(m_javaGlue->object(env).get(),
2758 m_javaGlue->m_getPluginClass,
2759 libString, classString);
2760 checkException(env);
2762 // cleanup unneeded local JNI references
2763 env->DeleteLocalRef(libString);
2764 env->DeleteLocalRef(classString);
2766 if (pluginClass != NULL) {
2767 return static_cast<jclass>(pluginClass);
2773 void WebViewCore::showFullScreenPlugin(jobject childView, NPP npp)
2775 JNIEnv* env = JSC::Bindings::getJNIEnv();
2776 AutoJObject obj = m_javaGlue->object(env);
2778 env->CallVoidMethod(obj.get(),
2779 m_javaGlue->m_showFullScreenPlugin, childView, (int)npp);
2780 checkException(env);
2783 void WebViewCore::hideFullScreenPlugin()
2785 JNIEnv* env = JSC::Bindings::getJNIEnv();
2786 env->CallVoidMethod(m_javaGlue->object(env).get(),
2787 m_javaGlue->m_hideFullScreenPlugin);
2788 checkException(env);
2791 jobject WebViewCore::addSurface(jobject view, int x, int y, int width, int height)
2793 JNIEnv* env = JSC::Bindings::getJNIEnv();
2794 jobject result = env->CallObjectMethod(m_javaGlue->object(env).get(),
2795 m_javaGlue->m_addSurface,
2796 view, x, y, width, height);
2797 checkException(env);
2801 void WebViewCore::updateSurface(jobject childView, int x, int y, int width, int height)
2803 JNIEnv* env = JSC::Bindings::getJNIEnv();
2804 env->CallVoidMethod(m_javaGlue->object(env).get(),
2805 m_javaGlue->m_updateSurface, childView,
2806 x, y, width, height);
2807 checkException(env);
2810 void WebViewCore::destroySurface(jobject childView)
2812 JNIEnv* env = JSC::Bindings::getJNIEnv();
2813 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_destroySurface, childView);
2814 checkException(env);
2817 jobject WebViewCore::getContext()
2819 JNIEnv* env = JSC::Bindings::getJNIEnv();
2820 AutoJObject obj = m_javaGlue->object(env);
2822 jobject result = env->CallObjectMethod(obj.get(), m_javaGlue->m_getContext);
2823 checkException(env);
2827 bool WebViewCore::validNodeAndBounds(Frame* frame, Node* node,
2828 const IntRect& originalAbsoluteBounds)
2830 bool valid = CacheBuilder::validNode(m_mainFrame, frame, node);
2833 RenderObject* renderer = node->renderer();
2836 IntRect absBounds = node->hasTagName(HTMLNames::areaTag)
2837 ? CacheBuilder::getAreaRect(static_cast<HTMLAreaElement*>(node))
2838 : renderer->absoluteBoundingBoxRect();
2839 return absBounds == originalAbsoluteBounds;
2842 void WebViewCore::showRect(int left, int top, int width, int height,
2843 int contentWidth, int contentHeight, float xPercentInDoc,
2844 float xPercentInView, float yPercentInDoc, float yPercentInView)
2846 JNIEnv* env = JSC::Bindings::getJNIEnv();
2847 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_showRect,
2848 left, top, width, height, contentWidth, contentHeight,
2849 xPercentInDoc, xPercentInView, yPercentInDoc, yPercentInView);
2850 checkException(env);
2853 void WebViewCore::centerFitRect(int x, int y, int width, int height)
2855 JNIEnv* env = JSC::Bindings::getJNIEnv();
2856 env->CallVoidMethod(m_javaGlue->object(env).get(),
2857 m_javaGlue->m_centerFitRect, x, y, width, height);
2858 checkException(env);
2862 void WebViewCore::setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode verticalMode)
2864 JNIEnv* env = JSC::Bindings::getJNIEnv();
2865 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_setScrollbarModes,
2866 horizontalMode, verticalMode);
2867 checkException(env);
2870 void WebViewCore::notifyWebAppCanBeInstalled()
2872 JNIEnv* env = JSC::Bindings::getJNIEnv();
2873 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_setInstallableWebApp);
2874 checkException(env);
2877 //----------------------------------------------------------------------
2878 // Native JNI methods
2879 //----------------------------------------------------------------------
2880 static jstring WebCoreStringToJString(JNIEnv *env, WebCore::String string)
2882 int length = string.length();
2885 jstring ret = env->NewString((jchar *)string.characters(), length);
2886 env->DeleteLocalRef(ret);
2890 static jstring RequestLabel(JNIEnv *env, jobject obj, int framePointer,
2893 return WebCoreStringToJString(env, GET_NATIVE_VIEW(env, obj)->requestLabel(
2894 (WebCore::Frame*) framePointer, (WebCore::Node*) nodePointer));
2897 static void UpdateFrameCacheIfLoading(JNIEnv *env, jobject obj)
2899 GET_NATIVE_VIEW(env, obj)->updateFrameCacheIfLoading();
2902 static void SetSize(JNIEnv *env, jobject obj, jint width, jint height,
2903 jint textWrapWidth, jfloat scale, jint screenWidth, jint screenHeight,
2904 jint anchorX, jint anchorY, jboolean ignoreHeight)
2906 #ifdef ANDROID_INSTRUMENT
2907 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2909 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2910 LOGV("webviewcore::nativeSetSize(%u %u)\n viewImpl: %p", (unsigned)width, (unsigned)height, viewImpl);
2911 LOG_ASSERT(viewImpl, "viewImpl not set in nativeSetSize");
2912 viewImpl->setSizeScreenWidthAndScale(width, height, textWrapWidth, scale,
2913 screenWidth, screenHeight, anchorX, anchorY, ignoreHeight);
2916 static void SetScrollOffset(JNIEnv *env, jobject obj, jint gen, jint x, jint y)
2918 #ifdef ANDROID_INSTRUMENT
2919 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2921 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2922 LOG_ASSERT(viewImpl, "need viewImpl");
2924 viewImpl->setScrollOffset(gen, x, y);
2927 static void SetGlobalBounds(JNIEnv *env, jobject obj, jint x, jint y, jint h,
2930 #ifdef ANDROID_INSTRUMENT
2931 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2933 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2934 LOG_ASSERT(viewImpl, "need viewImpl");
2936 viewImpl->setGlobalBounds(x, y, h, v);
2939 static jboolean Key(JNIEnv *env, jobject obj, jint keyCode, jint unichar,
2940 jint repeatCount, jboolean isShift, jboolean isAlt, jboolean isSym,
2943 #ifdef ANDROID_INSTRUMENT
2944 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2946 return GET_NATIVE_VIEW(env, obj)->key(PlatformKeyboardEvent(keyCode,
2947 unichar, repeatCount, isDown, isShift, isAlt, isSym));
2950 static void Click(JNIEnv *env, jobject obj, int framePtr, int nodePtr)
2952 #ifdef ANDROID_INSTRUMENT
2953 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2955 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2956 LOG_ASSERT(viewImpl, "viewImpl not set in Click");
2958 viewImpl->click(reinterpret_cast<WebCore::Frame*>(framePtr),
2959 reinterpret_cast<WebCore::Node*>(nodePtr));
2962 static void DeleteSelection(JNIEnv *env, jobject obj, jint start, jint end,
2963 jint textGeneration)
2965 #ifdef ANDROID_INSTRUMENT
2966 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2968 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2969 viewImpl->deleteSelection(start, end, textGeneration);
2972 static void SetSelection(JNIEnv *env, jobject obj, jint start, jint end)
2974 #ifdef ANDROID_INSTRUMENT
2975 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2977 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2978 viewImpl->setSelection(start, end);
2981 static jstring ModifySelection(JNIEnv *env, jobject obj, jstring alter, jstring direction, jstring granularity)
2983 #ifdef ANDROID_INSTRUMENT
2984 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2986 String alterString = to_string(env, alter);
2987 String directionString = to_string(env, direction);
2988 String granularityString = to_string(env, granularity);
2990 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2991 String selection_string = viewImpl->modifySelection(alterString,
2995 return WebCoreStringToJString(env, selection_string);
2998 static void ReplaceTextfieldText(JNIEnv *env, jobject obj,
2999 jint oldStart, jint oldEnd, jstring replace, jint start, jint end,
3000 jint textGeneration)
3002 #ifdef ANDROID_INSTRUMENT
3003 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3005 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3006 WebCore::String webcoreString = to_string(env, replace);
3007 viewImpl->replaceTextfieldText(oldStart,
3008 oldEnd, webcoreString, start, end, textGeneration);
3011 static void PassToJs(JNIEnv *env, jobject obj,
3012 jint generation, jstring currentText, jint keyCode,
3013 jint keyValue, jboolean down, jboolean cap, jboolean fn, jboolean sym)
3015 #ifdef ANDROID_INSTRUMENT
3016 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3018 WebCore::String current = to_string(env, currentText);
3019 GET_NATIVE_VIEW(env, obj)->passToJs(generation, current,
3020 PlatformKeyboardEvent(keyCode, keyValue, 0, down, cap, fn, sym));
3023 static void ScrollFocusedTextInput(JNIEnv *env, jobject obj, jfloat xPercent,
3026 #ifdef ANDROID_INSTRUMENT
3027 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3029 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3030 viewImpl->scrollFocusedTextInput(xPercent, y);
3033 static void SetFocusControllerActive(JNIEnv *env, jobject obj, jboolean active)
3035 #ifdef ANDROID_INSTRUMENT
3036 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3038 LOGV("webviewcore::nativeSetFocusControllerActive()\n");
3039 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3040 LOG_ASSERT(viewImpl, "viewImpl not set in nativeSetFocusControllerActive");
3041 viewImpl->setFocusControllerActive(0, active);
3044 static void SaveDocumentState(JNIEnv *env, jobject obj, jint frame)
3046 #ifdef ANDROID_INSTRUMENT
3047 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3049 LOGV("webviewcore::nativeSaveDocumentState()\n");
3050 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3051 LOG_ASSERT(viewImpl, "viewImpl not set in nativeSaveDocumentState");
3052 viewImpl->saveDocumentState((WebCore::Frame*) frame);
3055 void WebViewCore::addVisitedLink(const UChar* string, int length)
3057 if (m_groupForVisitedLinks)
3058 m_groupForVisitedLinks->addVisitedLink(string, length);
3061 static bool RecordContent(JNIEnv *env, jobject obj, jobject region, jobject pt)
3063 #ifdef ANDROID_INSTRUMENT
3064 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3066 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3067 SkRegion* nativeRegion = GraphicsJNI::getNativeRegion(env, region);
3069 bool result = viewImpl->recordContent(nativeRegion, &nativePt);
3070 GraphicsJNI::ipoint_to_jpoint(nativePt, env, pt);
3074 static void SplitContent(JNIEnv *env, jobject obj)
3076 #ifdef ANDROID_INSTRUMENT
3077 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3079 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3080 viewImpl->splitContent();
3083 static void SendListBoxChoice(JNIEnv* env, jobject obj, jint choice)
3085 #ifdef ANDROID_INSTRUMENT
3086 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3088 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3089 LOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoice");
3090 viewImpl->popupReply(choice);
3093 // Set aside a predetermined amount of space in which to place the listbox
3094 // choices, to avoid unnecessary allocations.
3095 // The size here is arbitrary. We want the size to be at least as great as the
3096 // number of items in the average multiple-select listbox.
3097 #define PREPARED_LISTBOX_STORAGE 10
3099 static void SendListBoxChoices(JNIEnv* env, jobject obj, jbooleanArray jArray,
3102 #ifdef ANDROID_INSTRUMENT
3103 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3105 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3106 LOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoices");
3107 jboolean* ptrArray = env->GetBooleanArrayElements(jArray, 0);
3108 SkAutoSTMalloc<PREPARED_LISTBOX_STORAGE, int> storage(size);
3109 int* array = storage.get();
3111 for (int i = 0; i < size; i++) {
3116 env->ReleaseBooleanArrayElements(jArray, ptrArray, JNI_ABORT);
3117 viewImpl->popupReply(array, count);
3120 static jstring FindAddress(JNIEnv *env, jobject obj, jstring addr,
3121 jboolean caseInsensitive)
3123 #ifdef ANDROID_INSTRUMENT
3124 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3128 int length = env->GetStringLength(addr);
3131 const jchar* addrChars = env->GetStringChars(addr, 0);
3133 bool success = CacheBuilder::FindAddress(addrChars, length,
3134 &start, &end, caseInsensitive) == CacheBuilder::FOUND_COMPLETE;
3137 ret = env->NewString((jchar*) addrChars + start, end - start);
3138 env->DeleteLocalRef(ret);
3140 env->ReleaseStringChars(addr, addrChars);
3144 static jboolean HandleTouchEvent(JNIEnv *env, jobject obj, jint action, jint x, jint y, jint metaState)
3146 #ifdef ANDROID_INSTRUMENT
3147 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3149 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3150 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
3151 return viewImpl->handleTouchEvent(action, x, y, metaState);
3154 static void TouchUp(JNIEnv *env, jobject obj, jint touchGeneration,
3155 jint frame, jint node, jint x, jint y)
3157 #ifdef ANDROID_INSTRUMENT
3158 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3160 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3161 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
3162 viewImpl->touchUp(touchGeneration,
3163 (WebCore::Frame*) frame, (WebCore::Node*) node, x, y);
3166 static jstring RetrieveHref(JNIEnv *env, jobject obj, jint frame,
3169 #ifdef ANDROID_INSTRUMENT
3170 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3172 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3173 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
3174 WebCore::String result = viewImpl->retrieveHref((WebCore::Frame*) frame,
3175 (WebCore::Node*) node);
3176 if (!result.isEmpty())
3177 return WebCoreStringToJString(env, result);
3181 static jstring RetrieveAnchorText(JNIEnv *env, jobject obj, jint frame,
3184 #ifdef ANDROID_INSTRUMENT
3185 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3187 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3188 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
3189 WebCore::String result = viewImpl->retrieveAnchorText((WebCore::Frame*) frame,
3190 (WebCore::Node*) node);
3191 if (!result.isEmpty())
3192 return WebCoreStringToJString(env, result);
3197 static void MoveFocus(JNIEnv *env, jobject obj, jint framePtr, jint nodePtr)
3199 #ifdef ANDROID_INSTRUMENT
3200 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3202 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3203 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
3204 viewImpl->moveFocus((WebCore::Frame*) framePtr, (WebCore::Node*) nodePtr);
3207 static void MoveMouse(JNIEnv *env, jobject obj, jint frame,
3210 #ifdef ANDROID_INSTRUMENT
3211 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3213 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3214 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
3215 viewImpl->moveMouse((WebCore::Frame*) frame, x, y);
3218 static void MoveMouseIfLatest(JNIEnv *env, jobject obj, jint moveGeneration,
3219 jint frame, jint x, jint y)
3221 #ifdef ANDROID_INSTRUMENT
3222 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3224 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3225 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
3226 viewImpl->moveMouseIfLatest(moveGeneration,
3227 (WebCore::Frame*) frame, x, y);
3230 static void UpdateFrameCache(JNIEnv *env, jobject obj)
3232 #ifdef ANDROID_INSTRUMENT
3233 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3235 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3236 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
3237 viewImpl->updateFrameCache();
3240 static jint GetContentMinPrefWidth(JNIEnv *env, jobject obj)
3242 #ifdef ANDROID_INSTRUMENT
3243 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3245 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3246 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
3248 WebCore::Frame* frame = viewImpl->mainFrame();
3250 WebCore::Document* document = frame->document();
3252 WebCore::RenderObject* renderer = document->renderer();
3253 if (renderer && renderer->isRenderView()) {
3254 return renderer->minPrefWidth();
3261 static void SetViewportSettingsFromNative(JNIEnv *env, jobject obj)
3263 #ifdef ANDROID_INSTRUMENT
3264 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3266 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3267 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
3269 WebCore::Settings* s = viewImpl->mainFrame()->page()->settings();
3273 #ifdef ANDROID_META_SUPPORT
3274 env->SetIntField(obj, gWebViewCoreFields.m_viewportWidth, s->viewportWidth());
3275 env->SetIntField(obj, gWebViewCoreFields.m_viewportHeight, s->viewportHeight());
3276 env->SetIntField(obj, gWebViewCoreFields.m_viewportInitialScale, s->viewportInitialScale());
3277 env->SetIntField(obj, gWebViewCoreFields.m_viewportMinimumScale, s->viewportMinimumScale());
3278 env->SetIntField(obj, gWebViewCoreFields.m_viewportMaximumScale, s->viewportMaximumScale());
3279 env->SetBooleanField(obj, gWebViewCoreFields.m_viewportUserScalable, s->viewportUserScalable());
3280 env->SetIntField(obj, gWebViewCoreFields.m_viewportDensityDpi, s->viewportTargetDensityDpi());
3284 static void SetBackgroundColor(JNIEnv *env, jobject obj, jint color)
3286 #ifdef ANDROID_INSTRUMENT
3287 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3289 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3290 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
3292 viewImpl->setBackgroundColor((SkColor) color);
3295 static void DumpDomTree(JNIEnv *env, jobject obj, jboolean useFile)
3297 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3298 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
3300 viewImpl->dumpDomTree(useFile);
3303 static void DumpRenderTree(JNIEnv *env, jobject obj, jboolean useFile)
3305 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3306 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
3308 viewImpl->dumpRenderTree(useFile);
3311 static void DumpNavTree(JNIEnv *env, jobject obj)
3313 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3314 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
3316 viewImpl->dumpNavTree();
3319 static void DumpV8Counters(JNIEnv*, jobject)
3322 #ifdef ANDROID_INSTRUMENT
3323 V8Counters::dumpCounters();
3328 static void SetJsFlags(JNIEnv *env, jobject obj, jstring flags)
3331 WebCore::String flagsString = to_string(env, flags);
3332 WTF::CString utf8String = flagsString.utf8();
3333 WebCore::ScriptController::setFlags(utf8String.data(), utf8String.length());
3338 // Called from the Java side to set a new quota for the origin or new appcache
3339 // max size in response to a notification that the original quota was exceeded or
3340 // that the appcache has reached its maximum size.
3341 static void SetNewStorageLimit(JNIEnv* env, jobject obj, jlong quota) {
3342 #if ENABLE(DATABASE) || ENABLE(OFFLINE_WEB_APPLICATIONS)
3343 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3344 Frame* frame = viewImpl->mainFrame();
3346 // The main thread is blocked awaiting this response, so now we can wake it
3348 ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client());
3349 chromeC->wakeUpMainThreadWithNewQuota(quota);
3353 // Called from Java to provide a Geolocation permission state for the specified origin.
3354 static void GeolocationPermissionsProvide(JNIEnv* env, jobject obj, jstring origin, jboolean allow, jboolean remember) {
3355 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3356 Frame* frame = viewImpl->mainFrame();
3358 ChromeClientAndroid* chromeClient = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client());
3359 chromeClient->provideGeolocationPermissions(to_string(env, origin), allow, remember);
3362 static void RegisterURLSchemeAsLocal(JNIEnv* env, jobject obj, jstring scheme) {
3363 #ifdef ANDROID_INSTRUMENT
3364 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3366 WebCore::SecurityOrigin::registerURLSchemeAsLocal(to_string(env, scheme));
3369 static void ClearContent(JNIEnv *env, jobject obj)
3371 #ifdef ANDROID_INSTRUMENT
3372 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3374 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3375 viewImpl->clearContent();
3378 static void CopyContentToPicture(JNIEnv *env, jobject obj, jobject pict)
3380 #ifdef ANDROID_INSTRUMENT
3381 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3383 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3386 SkPicture* picture = GraphicsJNI::getNativePicture(env, pict);
3387 viewImpl->copyContentToPicture(picture);
3390 static bool DrawContent(JNIEnv *env, jobject obj, jobject canv, jint color)
3392 // Note: this is called from UI thread, don't count it for WebViewCoreTimeCounter
3393 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3394 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv);
3395 return viewImpl->drawContent(canvas, color);
3398 static bool FocusBoundsChanged(JNIEnv* env, jobject obj)
3400 return GET_NATIVE_VIEW(env, obj)->focusBoundsChanged();
3403 static bool PictureReady(JNIEnv* env, jobject obj)
3405 return GET_NATIVE_VIEW(env, obj)->pictureReady();
3408 static void Pause(JNIEnv* env, jobject obj)
3410 // This is called for the foreground tab when the browser is put to the
3411 // background (and also for any tab when it is put to the background of the
3412 // browser). The browser can only be killed by the system when it is in the
3413 // background, so saving the Geolocation permission state now ensures that
3414 // is maintained when the browser is killed.
3415 ChromeClient* chromeClient = GET_NATIVE_VIEW(env, obj)->mainFrame()->page()->chrome()->client();
3416 ChromeClientAndroid* chromeClientAndroid = static_cast<ChromeClientAndroid*>(chromeClient);
3417 chromeClientAndroid->storeGeolocationPermissions();
3419 Frame* mainFrame = GET_NATIVE_VIEW(env, obj)->mainFrame();
3420 for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) {
3421 Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation();
3423 geolocation->suspend();
3427 SkANP::InitEvent(&event, kLifecycle_ANPEventType);
3428 event.data.lifecycle.action = kPause_ANPLifecycleAction;
3429 GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event);
3431 GET_NATIVE_VIEW(env, obj)->setIsPaused(true);
3434 static void Resume(JNIEnv* env, jobject obj)
3436 Frame* mainFrame = GET_NATIVE_VIEW(env, obj)->mainFrame();
3437 for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) {
3438 Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation();
3440 geolocation->resume();
3444 SkANP::InitEvent(&event, kLifecycle_ANPEventType);
3445 event.data.lifecycle.action = kResume_ANPLifecycleAction;
3446 GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event);
3448 GET_NATIVE_VIEW(env, obj)->setIsPaused(false);
3451 static void FreeMemory(JNIEnv* env, jobject obj)
3454 SkANP::InitEvent(&event, kLifecycle_ANPEventType);
3455 event.data.lifecycle.action = kFreeMemory_ANPLifecycleAction;
3456 GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event);
3459 static void ProvideVisitedHistory(JNIEnv *env, jobject obj, jobject hist)
3461 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3462 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
3464 jobjectArray array = static_cast<jobjectArray>(hist);
3466 jsize len = env->GetArrayLength(array);
3467 for (jsize i = 0; i < len; i++) {
3468 jstring item = static_cast<jstring>(env->GetObjectArrayElement(array, i));
3469 const UChar* str = static_cast<const UChar*>(env->GetStringChars(item, NULL));
3470 jsize len = env->GetStringLength(item);
3471 viewImpl->addVisitedLink(str, len);
3472 env->ReleaseStringChars(item, str);
3473 env->DeleteLocalRef(item);
3477 // Notification from the UI thread that the plugin's full-screen surface has been discarded
3478 static void FullScreenPluginHidden(JNIEnv* env, jobject obj, jint npp)
3480 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3481 PluginWidgetAndroid* plugin = viewImpl->getPluginWidget((NPP)npp);
3483 plugin->exitFullScreen(false);
3486 static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj)
3489 GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B);
3490 return WebCore::IntRect(L, T, R - L, B - T);
3493 static bool ValidNodeAndBounds(JNIEnv *env, jobject obj, int frame, int node,
3496 IntRect nativeRect = jrect_to_webrect(env, rect);
3497 return GET_NATIVE_VIEW(env, obj)->validNodeAndBounds(
3498 reinterpret_cast<Frame*>(frame),
3499 reinterpret_cast<Node*>(node), nativeRect);
3502 static jobject GetTouchHighlightRects(JNIEnv* env, jobject obj, jint x, jint y, jint slop)
3504 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3507 Vector<IntRect> rects = viewImpl->getTouchHighlightRects(x, y, slop);
3508 if (rects.isEmpty())
3511 jclass arrayClass = env->FindClass("java/util/ArrayList");
3512 LOG_ASSERT(arrayClass, "Could not find java/util/ArrayList");
3513 jmethodID init = env->GetMethodID(arrayClass, "<init>", "(I)V");
3514 LOG_ASSERT(init, "Could not find constructor for ArrayList");
3515 jobject array = env->NewObject(arrayClass, init, rects.size());
3516 LOG_ASSERT(vector, "Could not create a new ArrayList");
3517 jmethodID add = env->GetMethodID(arrayClass, "add", "(Ljava/lang/Object;)Z");
3518 LOG_ASSERT(add, "Could not find add method on ArrayList");
3519 jclass rectClass = env->FindClass("android/graphics/Rect");
3520 LOG_ASSERT(rectClass, "Could not find android/graphics/Rect");
3521 jmethodID rectinit = env->GetMethodID(rectClass, "<init>", "(IIII)V");
3522 LOG_ASSERT(rectinit, "Could not find init method on Rect");
3524 for (size_t i = 0; i < rects.size(); i++) {
3525 jobject rect = env->NewObject(rectClass, rectinit, rects[i].x(),
3526 rects[i].y(), rects[i].right(), rects[i].bottom());
3528 env->CallBooleanMethod(array, add, rect);
3529 env->DeleteLocalRef(rect);
3533 env->DeleteLocalRef(rectClass);
3534 env->DeleteLocalRef(arrayClass);
3538 // ----------------------------------------------------------------------------
3543 static JNINativeMethod gJavaWebViewCoreMethods[] = {
3544 { "nativeClearContent", "()V",
3545 (void*) ClearContent },
3546 { "nativeCopyContentToPicture", "(Landroid/graphics/Picture;)V",
3547 (void*) CopyContentToPicture },
3548 { "nativeDrawContent", "(Landroid/graphics/Canvas;I)Z",
3549 (void*) DrawContent } ,
3550 { "nativeFocusBoundsChanged", "()Z",
3551 (void*) FocusBoundsChanged } ,
3552 { "nativeKey", "(IIIZZZZ)Z",
3554 { "nativeClick", "(II)V",
3556 { "nativePictureReady", "()Z",
3557 (void*) PictureReady } ,
3558 { "nativeSendListBoxChoices", "([ZI)V",
3559 (void*) SendListBoxChoices },
3560 { "nativeSendListBoxChoice", "(I)V",
3561 (void*) SendListBoxChoice },
3562 { "nativeSetSize", "(IIIFIIIIZ)V",
3564 { "nativeSetScrollOffset", "(III)V",
3565 (void*) SetScrollOffset },
3566 { "nativeSetGlobalBounds", "(IIII)V",
3567 (void*) SetGlobalBounds },
3568 { "nativeSetSelection", "(II)V",
3569 (void*) SetSelection } ,
3570 { "nativeModifySelection", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
3571 (void*) ModifySelection },
3572 { "nativeDeleteSelection", "(III)V",
3573 (void*) DeleteSelection } ,
3574 { "nativeReplaceTextfieldText", "(IILjava/lang/String;III)V",
3575 (void*) ReplaceTextfieldText } ,
3576 { "nativeMoveFocus", "(II)V",
3577 (void*) MoveFocus },
3578 { "nativeMoveMouse", "(III)V",
3579 (void*) MoveMouse },
3580 { "nativeMoveMouseIfLatest", "(IIII)V",
3581 (void*) MoveMouseIfLatest },
3582 { "passToJs", "(ILjava/lang/String;IIZZZZ)V",
3584 { "nativeScrollFocusedTextInput", "(FI)V",
3585 (void*) ScrollFocusedTextInput },
3586 { "nativeSetFocusControllerActive", "(Z)V",
3587 (void*) SetFocusControllerActive },
3588 { "nativeSaveDocumentState", "(I)V",
3589 (void*) SaveDocumentState },
3590 { "nativeFindAddress", "(Ljava/lang/String;Z)Ljava/lang/String;",
3591 (void*) FindAddress },
3592 { "nativeHandleTouchEvent", "(IIII)Z",
3593 (void*) HandleTouchEvent },
3594 { "nativeTouchUp", "(IIIII)V",
3596 { "nativeRetrieveHref", "(II)Ljava/lang/String;",
3597 (void*) RetrieveHref },
3598 { "nativeRetrieveAnchorText", "(II)Ljava/lang/String;",
3599 (void*) RetrieveAnchorText },
3600 { "nativeUpdateFrameCache", "()V",
3601 (void*) UpdateFrameCache },
3602 { "nativeGetContentMinPrefWidth", "()I",
3603 (void*) GetContentMinPrefWidth },
3604 { "nativeRecordContent", "(Landroid/graphics/Region;Landroid/graphics/Point;)Z",
3605 (void*) RecordContent },
3606 { "setViewportSettingsFromNative", "()V",
3607 (void*) SetViewportSettingsFromNative },
3608 { "nativeSplitContent", "()V",
3609 (void*) SplitContent },
3610 { "nativeSetBackgroundColor", "(I)V",
3611 (void*) SetBackgroundColor },
3612 { "nativeRegisterURLSchemeAsLocal", "(Ljava/lang/String;)V",
3613 (void*) RegisterURLSchemeAsLocal },
3614 { "nativeDumpDomTree", "(Z)V",
3615 (void*) DumpDomTree },
3616 { "nativeDumpRenderTree", "(Z)V",
3617 (void*) DumpRenderTree },
3618 { "nativeDumpNavTree", "()V",
3619 (void*) DumpNavTree },
3620 { "nativeDumpV8Counters", "()V",
3621 (void*) DumpV8Counters },
3622 { "nativeSetNewStorageLimit", "(J)V",
3623 (void*) SetNewStorageLimit },
3624 { "nativeGeolocationPermissionsProvide", "(Ljava/lang/String;ZZ)V",
3625 (void*) GeolocationPermissionsProvide },
3626 { "nativePause", "()V", (void*) Pause },
3627 { "nativeResume", "()V", (void*) Resume },
3628 { "nativeFreeMemory", "()V", (void*) FreeMemory },
3629 { "nativeSetJsFlags", "(Ljava/lang/String;)V", (void*) SetJsFlags },
3630 { "nativeRequestLabel", "(II)Ljava/lang/String;",
3631 (void*) RequestLabel },
3632 { "nativeUpdateFrameCacheIfLoading", "()V",
3633 (void*) UpdateFrameCacheIfLoading },
3634 { "nativeProvideVisitedHistory", "([Ljava/lang/String;)V",
3635 (void*) ProvideVisitedHistory },
3636 { "nativeFullScreenPluginHidden", "(I)V",
3637 (void*) FullScreenPluginHidden },
3638 { "nativeValidNodeAndBounds", "(IILandroid/graphics/Rect;)Z",
3639 (void*) ValidNodeAndBounds },
3640 { "nativeGetTouchHighlightRects", "(III)Ljava/util/ArrayList;",
3641 (void*) GetTouchHighlightRects },
3644 int register_webviewcore(JNIEnv* env)
3646 jclass widget = env->FindClass("android/webkit/WebViewCore");
3648 "Unable to find class android/webkit/WebViewCore");
3649 gWebViewCoreFields.m_nativeClass = env->GetFieldID(widget, "mNativeClass",
3651 LOG_ASSERT(gWebViewCoreFields.m_nativeClass,
3652 "Unable to find android/webkit/WebViewCore.mNativeClass");
3653 gWebViewCoreFields.m_viewportWidth = env->GetFieldID(widget,
3654 "mViewportWidth", "I");
3655 LOG_ASSERT(gWebViewCoreFields.m_viewportWidth,
3656 "Unable to find android/webkit/WebViewCore.mViewportWidth");
3657 gWebViewCoreFields.m_viewportHeight = env->GetFieldID(widget,
3658 "mViewportHeight", "I");
3659 LOG_ASSERT(gWebViewCoreFields.m_viewportHeight,
3660 "Unable to find android/webkit/WebViewCore.mViewportHeight");
3661 gWebViewCoreFields.m_viewportInitialScale = env->GetFieldID(widget,
3662 "mViewportInitialScale", "I");
3663 LOG_ASSERT(gWebViewCoreFields.m_viewportInitialScale,
3664 "Unable to find android/webkit/WebViewCore.mViewportInitialScale");
3665 gWebViewCoreFields.m_viewportMinimumScale = env->GetFieldID(widget,
3666 "mViewportMinimumScale", "I");
3667 LOG_ASSERT(gWebViewCoreFields.m_viewportMinimumScale,
3668 "Unable to find android/webkit/WebViewCore.mViewportMinimumScale");
3669 gWebViewCoreFields.m_viewportMaximumScale = env->GetFieldID(widget,
3670 "mViewportMaximumScale", "I");
3671 LOG_ASSERT(gWebViewCoreFields.m_viewportMaximumScale,
3672 "Unable to find android/webkit/WebViewCore.mViewportMaximumScale");
3673 gWebViewCoreFields.m_viewportUserScalable = env->GetFieldID(widget,
3674 "mViewportUserScalable", "Z");
3675 LOG_ASSERT(gWebViewCoreFields.m_viewportUserScalable,
3676 "Unable to find android/webkit/WebViewCore.mViewportUserScalable");
3677 gWebViewCoreFields.m_viewportDensityDpi = env->GetFieldID(widget,
3678 "mViewportDensityDpi", "I");
3679 LOG_ASSERT(gWebViewCoreFields.m_viewportDensityDpi,
3680 "Unable to find android/webkit/WebViewCore.mViewportDensityDpi");
3681 gWebViewCoreFields.m_webView = env->GetFieldID(widget,
3682 "mWebView", "Landroid/webkit/WebView;");
3683 LOG_ASSERT(gWebViewCoreFields.m_webView,
3684 "Unable to find android/webkit/WebViewCore.mWebView");
3686 return jniRegisterNativeMethods(env, "android/webkit/WebViewCore",
3687 gJavaWebViewCoreMethods, NELEM(gJavaWebViewCoreMethods));
3690 } /* namespace android */