• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2006, The Android Open Source Project
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
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.
12  *
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 APPLE COMPUTER, INC. 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.
24  */
25 
26 #define LOG_TAG "webcoreglue"
27 
28 #include <config.h>
29 #include "WebViewCore.h"
30 
31 #include "AtomicString.h"
32 #include "CachedNode.h"
33 #include "CachedRoot.h"
34 #include "ChromeClientAndroid.h"
35 #include "Color.h"
36 #include "DatabaseTracker.h"
37 #include "Document.h"
38 #include "DOMWindow.h"
39 #include "Element.h"
40 #include "Editor.h"
41 #include "EditorClientAndroid.h"
42 #include "EventHandler.h"
43 #include "EventNames.h"
44 #include "FocusController.h"
45 #include "Font.h"
46 #include "Frame.h"
47 #include "FrameLoader.h"
48 #include "FrameLoaderClientAndroid.h"
49 #include "FrameTree.h"
50 #include "FrameView.h"
51 #include "Geolocation.h"
52 #include "GraphicsContext.h"
53 #include "GraphicsJNI.h"
54 #include "HitTestResult.h"
55 #include "HTMLAnchorElement.h"
56 #include "HTMLAreaElement.h"
57 #include "HTMLElement.h"
58 #include "HTMLImageElement.h"
59 #include "HTMLInputElement.h"
60 #include "HTMLMapElement.h"
61 #include "HTMLNames.h"
62 #include "HTMLOptGroupElement.h"
63 #include "HTMLOptionElement.h"
64 #include "HTMLSelectElement.h"
65 #include "HTMLTextAreaElement.h"
66 #include "InlineTextBox.h"
67 #include <JNIHelp.h>
68 #include "KeyboardCodes.h"
69 #include "Navigator.h"
70 #include "Node.h"
71 #include "Page.h"
72 #include "PageGroup.h"
73 #include "PlatformKeyboardEvent.h"
74 #include "PlatformString.h"
75 #include "PluginWidgetAndroid.h"
76 #include "PluginView.h"
77 #include "Position.h"
78 #include "ProgressTracker.h"
79 #include "RenderBox.h"
80 #include "RenderLayer.h"
81 #include "RenderPart.h"
82 #include "RenderText.h"
83 #include "RenderTextControl.h"
84 #include "RenderThemeAndroid.h"
85 #include "RenderView.h"
86 #include "ResourceRequest.h"
87 #include "SelectionController.h"
88 #include "Settings.h"
89 #include "SkANP.h"
90 #include "SkTemplates.h"
91 #include "SkTypes.h"
92 #include "SkCanvas.h"
93 #include "SkPicture.h"
94 #include "SkUtils.h"
95 #include "StringImpl.h"
96 #include "Text.h"
97 #include "TypingCommand.h"
98 #include "WebCoreFrameBridge.h"
99 #include "WebFrameView.h"
100 #include "HistoryItem.h"
101 #include "android_graphics.h"
102 #include <ui/KeycodeLabels.h>
103 #include "jni_utility.h"
104 #include <wtf/CurrentTime.h>
105 
106 #if USE(V8)
107 #include "CString.h"
108 #include "ScriptController.h"
109 #endif
110 
111 #if DEBUG_NAV_UI
112 #include "SkTime.h"
113 #endif
114 
115 #if ENABLE(TOUCH_EVENTS) // Android
116 #include "PlatformTouchEvent.h"
117 #endif
118 
119 #ifdef ANDROID_DOM_LOGGING
120 #include "AndroidLog.h"
121 #include "RenderTreeAsText.h"
122 #include "CString.h"
123 
124 FILE* gDomTreeFile = 0;
125 FILE* gRenderTreeFile = 0;
126 #endif
127 
128 #ifdef ANDROID_INSTRUMENT
129 #include "TimeCounter.h"
130 #endif
131 
132 /*  We pass this flag when recording the actual content, so that we don't spend
133     time actually regionizing complex path clips, when all we really want to do
134     is record them.
135  */
136 #define PICT_RECORD_FLAGS   SkPicture::kUsePathBoundsForClip_RecordingFlag
137 
138 ////////////////////////////////////////////////////////////////////////////////////////////////
139 
140 namespace android {
141 
142 // ----------------------------------------------------------------------------
143 
144 #define GET_NATIVE_VIEW(env, obj) ((WebViewCore*)env->GetIntField(obj, gWebViewCoreFields.m_nativeClass))
145 
146 // Field ids for WebViewCore
147 struct WebViewCoreFields {
148     jfieldID    m_nativeClass;
149     jfieldID    m_viewportWidth;
150     jfieldID    m_viewportHeight;
151     jfieldID    m_viewportInitialScale;
152     jfieldID    m_viewportMinimumScale;
153     jfieldID    m_viewportMaximumScale;
154     jfieldID    m_viewportUserScalable;
155     jfieldID    m_viewportDensityDpi;
156     jfieldID    m_webView;
157 } gWebViewCoreFields;
158 
159 // ----------------------------------------------------------------------------
160 
161 struct WebViewCore::JavaGlue {
162     jobject     m_obj;
163     jmethodID   m_spawnScrollTo;
164     jmethodID   m_scrollTo;
165     jmethodID   m_scrollBy;
166     jmethodID   m_contentDraw;
167     jmethodID   m_requestListBox;
168     jmethodID   m_requestSingleListBox;
169     jmethodID   m_jsAlert;
170     jmethodID   m_jsConfirm;
171     jmethodID   m_jsPrompt;
172     jmethodID   m_jsUnload;
173     jmethodID   m_jsInterrupt;
174     jmethodID   m_didFirstLayout;
175     jmethodID   m_updateViewport;
176     jmethodID   m_sendNotifyProgressFinished;
177     jmethodID   m_sendViewInvalidate;
178     jmethodID   m_updateTextfield;
179     jmethodID   m_updateTextSelection;
180     jmethodID   m_clearTextEntry;
181     jmethodID   m_restoreScale;
182     jmethodID   m_restoreScreenWidthScale;
183     jmethodID   m_needTouchEvents;
184     jmethodID   m_requestKeyboard;
185     jmethodID   m_exceededDatabaseQuota;
186     jmethodID   m_reachedMaxAppCacheSize;
187     jmethodID   m_populateVisitedLinks;
188     jmethodID   m_geolocationPermissionsShowPrompt;
189     jmethodID   m_geolocationPermissionsHidePrompt;
190     jmethodID   m_addMessageToConsole;
191     jmethodID   m_startFullScreenPluginActivity;
192     jmethodID   m_createSurface;
193     jmethodID   m_destroySurface;
objectandroid::WebViewCore::JavaGlue194     AutoJObject object(JNIEnv* env) {
195         return getRealObject(env, m_obj);
196     }
197 };
198 
199 /*
200  * WebViewCore Implementation
201  */
202 
GetJMethod(JNIEnv * env,jclass clazz,const char name[],const char signature[])203 static jmethodID GetJMethod(JNIEnv* env, jclass clazz, const char name[], const char signature[])
204 {
205     jmethodID m = env->GetMethodID(clazz, name, signature);
206     LOG_ASSERT(m, "Could not find method %s", name);
207     return m;
208 }
209 
210 Mutex WebViewCore::gFrameCacheMutex;
211 Mutex WebViewCore::gButtonMutex;
212 Mutex WebViewCore::gCursorBoundsMutex;
213 Mutex WebViewCore::m_contentMutex;
214 
WebViewCore(JNIEnv * env,jobject javaWebViewCore,WebCore::Frame * mainframe)215 WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* mainframe)
216         : m_pluginInvalTimer(this, &WebViewCore::pluginInvalTimerFired)
217 {
218     m_mainFrame = mainframe;
219 
220     m_popupReply = 0;
221     m_moveGeneration = 0;
222     m_generation = 0;
223     m_lastGeneration = 0;
224     m_touchGeneration = 0;
225     m_blockTextfieldUpdates = false;
226     // just initial values. These should be set by client
227     m_maxXScroll = 320/4;
228     m_maxYScroll = 240/4;
229     m_textGeneration = 0;
230     m_screenWidth = 320;
231     m_scale = 1;
232     m_screenWidthScale = 1;
233 
234     LOG_ASSERT(m_mainFrame, "Uh oh, somehow a frameview was made without an initial frame!");
235 
236     jclass clazz = env->GetObjectClass(javaWebViewCore);
237     m_javaGlue = new JavaGlue;
238     m_javaGlue->m_obj = adoptGlobalRef(env, javaWebViewCore);
239     m_javaGlue->m_spawnScrollTo = GetJMethod(env, clazz, "contentSpawnScrollTo", "(II)V");
240     m_javaGlue->m_scrollTo = GetJMethod(env, clazz, "contentScrollTo", "(II)V");
241     m_javaGlue->m_scrollBy = GetJMethod(env, clazz, "contentScrollBy", "(IIZ)V");
242     m_javaGlue->m_contentDraw = GetJMethod(env, clazz, "contentDraw", "()V");
243     m_javaGlue->m_requestListBox = GetJMethod(env, clazz, "requestListBox", "([Ljava/lang/String;[Z[I)V");
244     m_javaGlue->m_requestSingleListBox = GetJMethod(env, clazz, "requestListBox", "([Ljava/lang/String;[ZI)V");
245     m_javaGlue->m_jsAlert = GetJMethod(env, clazz, "jsAlert", "(Ljava/lang/String;Ljava/lang/String;)V");
246     m_javaGlue->m_jsConfirm = GetJMethod(env, clazz, "jsConfirm", "(Ljava/lang/String;Ljava/lang/String;)Z");
247     m_javaGlue->m_jsPrompt = GetJMethod(env, clazz, "jsPrompt", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
248     m_javaGlue->m_jsUnload = GetJMethod(env, clazz, "jsUnload", "(Ljava/lang/String;Ljava/lang/String;)Z");
249     m_javaGlue->m_jsInterrupt = GetJMethod(env, clazz, "jsInterrupt", "()Z");
250     m_javaGlue->m_didFirstLayout = GetJMethod(env, clazz, "didFirstLayout", "(Z)V");
251     m_javaGlue->m_updateViewport = GetJMethod(env, clazz, "updateViewport", "()V");
252     m_javaGlue->m_sendNotifyProgressFinished = GetJMethod(env, clazz, "sendNotifyProgressFinished", "()V");
253     m_javaGlue->m_sendViewInvalidate = GetJMethod(env, clazz, "sendViewInvalidate", "(IIII)V");
254     m_javaGlue->m_updateTextfield = GetJMethod(env, clazz, "updateTextfield", "(IZLjava/lang/String;I)V");
255     m_javaGlue->m_updateTextSelection = GetJMethod(env, clazz, "updateTextSelection", "(IIII)V");
256     m_javaGlue->m_clearTextEntry = GetJMethod(env, clazz, "clearTextEntry", "()V");
257     m_javaGlue->m_restoreScale = GetJMethod(env, clazz, "restoreScale", "(I)V");
258     m_javaGlue->m_restoreScreenWidthScale = GetJMethod(env, clazz, "restoreScreenWidthScale", "(I)V");
259     m_javaGlue->m_needTouchEvents = GetJMethod(env, clazz, "needTouchEvents", "(Z)V");
260     m_javaGlue->m_requestKeyboard = GetJMethod(env, clazz, "requestKeyboard", "(Z)V");
261     m_javaGlue->m_exceededDatabaseQuota = GetJMethod(env, clazz, "exceededDatabaseQuota", "(Ljava/lang/String;Ljava/lang/String;JJ)V");
262     m_javaGlue->m_reachedMaxAppCacheSize = GetJMethod(env, clazz, "reachedMaxAppCacheSize", "(J)V");
263     m_javaGlue->m_populateVisitedLinks = GetJMethod(env, clazz, "populateVisitedLinks", "()V");
264     m_javaGlue->m_geolocationPermissionsShowPrompt = GetJMethod(env, clazz, "geolocationPermissionsShowPrompt", "(Ljava/lang/String;)V");
265     m_javaGlue->m_geolocationPermissionsHidePrompt = GetJMethod(env, clazz, "geolocationPermissionsHidePrompt", "()V");
266     m_javaGlue->m_addMessageToConsole = GetJMethod(env, clazz, "addMessageToConsole", "(Ljava/lang/String;ILjava/lang/String;)V");
267     m_javaGlue->m_startFullScreenPluginActivity = GetJMethod(env, clazz, "startFullScreenPluginActivity", "(Ljava/lang/String;Ljava/lang/String;I)V");
268     m_javaGlue->m_createSurface = GetJMethod(env, clazz, "createSurface", "(Ljava/lang/String;Ljava/lang/String;IIIII)Landroid/webkit/ViewManager$ChildView;");
269     m_javaGlue->m_destroySurface = GetJMethod(env, clazz, "destroySurface", "(Landroid/webkit/ViewManager$ChildView;)V");
270 
271     env->SetIntField(javaWebViewCore, gWebViewCoreFields.m_nativeClass, (jint)this);
272 
273     m_scrollOffsetX = m_scrollOffsetY = 0;
274 
275     PageGroup::setShouldTrackVisitedLinks(true);
276 
277     reset(true);
278 }
279 
~WebViewCore()280 WebViewCore::~WebViewCore()
281 {
282     // Release the focused view
283     Release(m_popupReply);
284 
285     if (m_javaGlue->m_obj) {
286         JNIEnv* env = JSC::Bindings::getJNIEnv();
287         env->DeleteGlobalRef(m_javaGlue->m_obj);
288         m_javaGlue->m_obj = 0;
289     }
290     delete m_javaGlue;
291     delete m_frameCacheKit;
292     delete m_navPictureKit;
293 }
294 
getWebViewCore(const WebCore::FrameView * view)295 WebViewCore* WebViewCore::getWebViewCore(const WebCore::FrameView* view)
296 {
297     return getWebViewCore(static_cast<const WebCore::ScrollView*>(view));
298 }
299 
getWebViewCore(const WebCore::ScrollView * view)300 WebViewCore* WebViewCore::getWebViewCore(const WebCore::ScrollView* view)
301 {
302     WebFrameView* webFrameView = static_cast<WebFrameView*>(view->platformWidget());
303     if (!webFrameView)
304         return 0;
305     return webFrameView->webViewCore();
306 }
307 
reset(bool fromConstructor)308 void WebViewCore::reset(bool fromConstructor)
309 {
310     DBG_SET_LOG("");
311     if (fromConstructor) {
312         m_frameCacheKit = 0;
313         m_navPictureKit = 0;
314     } else {
315         gFrameCacheMutex.lock();
316         delete m_frameCacheKit;
317         delete m_navPictureKit;
318         m_frameCacheKit = 0;
319         m_navPictureKit = 0;
320         gFrameCacheMutex.unlock();
321     }
322 
323     m_lastFocused = 0;
324     m_lastFocusedBounds = WebCore::IntRect(0,0,0,0);
325     m_lastFocusedSelStart = 0;
326     m_lastFocusedSelEnd = 0;
327     m_lastMoveGeneration = 0;
328     clearContent();
329     m_updatedFrameCache = true;
330     m_frameCacheOutOfDate = true;
331     m_skipContentDraw = false;
332     m_findIsUp = false;
333     m_domtree_version = 0;
334     m_check_domtree_version = true;
335     m_progressDone = false;
336     m_hasCursorBounds = false;
337 
338     m_scrollOffsetX = 0;
339     m_scrollOffsetY = 0;
340     m_screenWidth = 0;
341     m_screenHeight = 0;
342     m_groupForVisitedLinks = NULL;
343 }
344 
layoutIfNeededRecursive(WebCore::Frame * f)345 static bool layoutIfNeededRecursive(WebCore::Frame* f)
346 {
347     if (!f)
348         return true;
349 
350     WebCore::FrameView* v = f->view();
351     if (!v)
352         return true;
353 
354     if (v->needsLayout())
355         v->layout(f->tree()->parent());
356 
357     WebCore::Frame* child = f->tree()->firstChild();
358     bool success = true;
359     while (child) {
360         success &= layoutIfNeededRecursive(child);
361         child = child->tree()->nextSibling();
362     }
363 
364     return success && !v->needsLayout();
365 }
366 
cacheBuilder()367 CacheBuilder& WebViewCore::cacheBuilder()
368 {
369     return FrameLoaderClientAndroid::get(m_mainFrame)->getCacheBuilder();
370 }
371 
currentFocus()372 WebCore::Node* WebViewCore::currentFocus()
373 {
374     return cacheBuilder().currentFocus();
375 }
376 
recordPicture(SkPicture * picture)377 void WebViewCore::recordPicture(SkPicture* picture)
378 {
379     // if there is no document yet, just return
380     if (!m_mainFrame->document()) {
381         DBG_NAV_LOG("no document");
382         return;
383     }
384     // Call layout to ensure that the contentWidth and contentHeight are correct
385     if (!layoutIfNeededRecursive(m_mainFrame)) {
386         DBG_NAV_LOG("layout failed");
387         return;
388     }
389     // draw into the picture's recording canvas
390     WebCore::FrameView* view = m_mainFrame->view();
391     DBG_NAV_LOGD("view=(w=%d,h=%d)", view->contentsWidth(),
392         view->contentsHeight());
393     SkAutoPictureRecord arp(picture, view->contentsWidth(),
394                             view->contentsHeight(), PICT_RECORD_FLAGS);
395     SkAutoMemoryUsageProbe mup(__FUNCTION__);
396 
397     // Copy m_buttons so we can pass it to our graphics context.
398     gButtonMutex.lock();
399     WTF::Vector<Container> buttons(m_buttons);
400     gButtonMutex.unlock();
401 
402     WebCore::PlatformGraphicsContext pgc(arp.getRecordingCanvas(), &buttons);
403     WebCore::GraphicsContext gc(&pgc);
404     view->platformWidget()->draw(&gc, WebCore::IntRect(0, 0, INT_MAX, INT_MAX));
405 
406     gButtonMutex.lock();
407     updateButtonList(&buttons);
408     gButtonMutex.unlock();
409 }
410 
recordPictureSet(PictureSet * content)411 void WebViewCore::recordPictureSet(PictureSet* content)
412 {
413     // if there is no document yet, just return
414     if (!m_mainFrame->document()) {
415         DBG_SET_LOG("!m_mainFrame->document()");
416         return;
417     }
418     if (m_addInval.isEmpty()) {
419         DBG_SET_LOG("m_addInval.isEmpty()");
420         return;
421     }
422     // Call layout to ensure that the contentWidth and contentHeight are correct
423     // it's fine for layout to gather invalidates, but defeat sending a message
424     // back to java to call webkitDraw, since we're already in the middle of
425     // doing that
426     m_skipContentDraw = true;
427     bool success = layoutIfNeededRecursive(m_mainFrame);
428     m_skipContentDraw = false;
429 
430     // We may be mid-layout and thus cannot draw.
431     if (!success)
432         return;
433 
434     {   // collect WebViewCoreRecordTimeCounter after layoutIfNeededRecursive
435 #ifdef ANDROID_INSTRUMENT
436     TimeCounterAuto counter(TimeCounter::WebViewCoreRecordTimeCounter);
437 #endif
438 
439     // if the webkit page dimensions changed, discard the pictureset and redraw.
440     WebCore::FrameView* view = m_mainFrame->view();
441     int width = view->contentsWidth();
442     int height = view->contentsHeight();
443 
444     // Use the contents width and height as a starting point.
445     SkIRect contentRect;
446     contentRect.set(0, 0, width, height);
447     SkIRect total(contentRect);
448 
449     // Traverse all the frames and add their sizes if they are in the visible
450     // rectangle.
451     for (WebCore::Frame* frame = m_mainFrame->tree()->traverseNext(); frame;
452             frame = frame->tree()->traverseNext()) {
453         // If the frame doesn't have an owner then it is the top frame and the
454         // view size is the frame size.
455         WebCore::RenderPart* owner = frame->ownerRenderer();
456         if (owner && owner->style()->visibility() == VISIBLE) {
457             int x = owner->x();
458             int y = owner->y();
459 
460             // Traverse the tree up to the parent to find the absolute position
461             // of this frame.
462             WebCore::Frame* parent = frame->tree()->parent();
463             while (parent) {
464                 WebCore::RenderPart* parentOwner = parent->ownerRenderer();
465                 if (parentOwner) {
466                     x += parentOwner->x();
467                     y += parentOwner->y();
468                 }
469                 parent = parent->tree()->parent();
470             }
471             // Use the owner dimensions so that padding and border are
472             // included.
473             int right = x + owner->width();
474             int bottom = y + owner->height();
475             SkIRect frameRect = {x, y, right, bottom};
476             // Ignore a width or height that is smaller than 1. Some iframes
477             // have small dimensions in order to be hidden. The iframe
478             // expansion code does not expand in that case so we should ignore
479             // them here.
480             if (frameRect.width() > 1 && frameRect.height() > 1
481                     && SkIRect::Intersects(total, frameRect))
482                 total.join(x, y, right, bottom);
483         }
484     }
485 
486     // If the new total is larger than the content, resize the view to include
487     // all the content.
488     if (!contentRect.contains(total)) {
489         // Resize the view to change the overflow clip.
490         view->resize(total.fRight, total.fBottom);
491 
492         // We have to force a layout in order for the clip to change.
493         m_mainFrame->contentRenderer()->setNeedsLayoutAndPrefWidthsRecalc();
494         view->forceLayout();
495 
496         // Relayout similar to above
497         m_skipContentDraw = true;
498         bool success = layoutIfNeededRecursive(m_mainFrame);
499         m_skipContentDraw = false;
500         if (!success)
501             return;
502 
503         // Set the computed content width
504         width = view->contentsWidth();
505         height = view->contentsHeight();
506     }
507 
508     content->checkDimensions(width, height, &m_addInval);
509 
510     // The inval region may replace existing pictures. The existing pictures
511     // may have already been split into pieces. If reuseSubdivided() returns
512     // true, the split pieces are the last entries in the picture already. They
513     // are marked as invalid, and are rebuilt by rebuildPictureSet().
514 
515     // If the new region doesn't match a set of split pieces, add it to the end.
516     if (!content->reuseSubdivided(m_addInval)) {
517         const SkIRect& inval = m_addInval.getBounds();
518         SkPicture* picture = rebuildPicture(inval);
519         DBG_SET_LOGD("{%d,%d,w=%d,h=%d}", inval.fLeft,
520             inval.fTop, inval.width(), inval.height());
521         content->add(m_addInval, picture, 0, false);
522         picture->safeUnref();
523     }
524     // Remove any pictures already in the set that are obscured by the new one,
525     // and check to see if any already split pieces need to be redrawn.
526     if (content->build())
527         rebuildPictureSet(content);
528     } // WebViewCoreRecordTimeCounter
529     WebCore::Node* oldFocusNode = currentFocus();
530     m_frameCacheOutOfDate = true;
531     WebCore::IntRect oldBounds;
532     int oldSelStart = 0;
533     int oldSelEnd = 0;
534     if (oldFocusNode) {
535         oldBounds = oldFocusNode->getRect();
536         RenderObject* renderer = oldFocusNode->renderer();
537         if (renderer && (renderer->isTextArea() || renderer->isTextField())) {
538             WebCore::RenderTextControl* rtc =
539                 static_cast<WebCore::RenderTextControl*>(renderer);
540             oldSelStart = rtc->selectionStart();
541             oldSelEnd = rtc->selectionEnd();
542         }
543     } else
544         oldBounds = WebCore::IntRect(0,0,0,0);
545     unsigned latestVersion = 0;
546     if (m_check_domtree_version) {
547         // as domTreeVersion only increment, we can just check the sum to see
548         // whether we need to update the frame cache
549         for (Frame* frame = m_mainFrame; frame; frame = frame->tree()->traverseNext()) {
550             latestVersion += frame->document()->domTreeVersion();
551         }
552     }
553     DBG_NAV_LOGD("m_lastFocused=%p oldFocusNode=%p"
554         " m_lastFocusedBounds={%d,%d,%d,%d} oldBounds={%d,%d,%d,%d}"
555         " m_lastFocusedSelection={%d,%d} oldSelection={%d,%d}"
556         " m_check_domtree_version=%s latestVersion=%d m_domtree_version=%d",
557         m_lastFocused, oldFocusNode,
558         m_lastFocusedBounds.x(), m_lastFocusedBounds.y(),
559         m_lastFocusedBounds.width(), m_lastFocusedBounds.height(),
560         oldBounds.x(), oldBounds.y(), oldBounds.width(), oldBounds.height(),
561         m_lastFocusedSelStart, m_lastFocusedSelEnd, oldSelStart, oldSelEnd,
562         m_check_domtree_version ? "true" : "false",
563         latestVersion, m_domtree_version);
564     if (m_lastFocused == oldFocusNode && m_lastFocusedBounds == oldBounds
565             && m_lastFocusedSelStart == oldSelStart
566             && m_lastFocusedSelEnd == oldSelEnd
567             && !m_findIsUp
568             && (!m_check_domtree_version || latestVersion == m_domtree_version))
569     {
570         return;
571     }
572     m_lastFocused = oldFocusNode;
573     m_lastFocusedBounds = oldBounds;
574     m_lastFocusedSelStart = oldSelStart;
575     m_lastFocusedSelEnd = oldSelEnd;
576     m_domtree_version = latestVersion;
577     DBG_NAV_LOG("call updateFrameCache");
578     updateFrameCache();
579 }
580 
updateButtonList(WTF::Vector<Container> * buttons)581 void WebViewCore::updateButtonList(WTF::Vector<Container>* buttons)
582 {
583     // All the entries in buttons are either updates of previous entries in
584     // m_buttons or they need to be added to it.
585     Container* end = buttons->end();
586     for (Container* updatedContainer = buttons->begin();
587             updatedContainer != end; updatedContainer++) {
588         bool updated = false;
589         // Search for a previous entry that references the same node as our new
590         // data
591         Container* lastPossibleMatch = m_buttons.end();
592         for (Container* possibleMatch = m_buttons.begin();
593                 possibleMatch != lastPossibleMatch; possibleMatch++) {
594             if (updatedContainer->matches(possibleMatch->node())) {
595                 // Update our record, and skip to the next one.
596                 possibleMatch->setRect(updatedContainer->rect());
597                 updated = true;
598                 break;
599             }
600         }
601         if (!updated) {
602             // This is a brand new button, so append it to m_buttons
603             m_buttons.append(*updatedContainer);
604         }
605     }
606     size_t i = 0;
607     // count will decrease each time one is removed, so check count each time.
608     while (i < m_buttons.size()) {
609         if (m_buttons[i].canBeRemoved()) {
610             m_buttons[i] = m_buttons.last();
611             m_buttons.removeLast();
612         } else {
613             i++;
614         }
615     }
616 }
617 
clearContent()618 void WebViewCore::clearContent()
619 {
620     DBG_SET_LOG("");
621     m_contentMutex.lock();
622     m_content.clear();
623     m_contentMutex.unlock();
624     m_addInval.setEmpty();
625     m_rebuildInval.setEmpty();
626 }
627 
copyContentToPicture(SkPicture * picture)628 void WebViewCore::copyContentToPicture(SkPicture* picture)
629 {
630     DBG_SET_LOG("start");
631     m_contentMutex.lock();
632     PictureSet copyContent = PictureSet(m_content);
633     m_contentMutex.unlock();
634 
635     int w = copyContent.width();
636     int h = copyContent.height();
637     copyContent.draw(picture->beginRecording(w, h, PICT_RECORD_FLAGS));
638     picture->endRecording();
639     DBG_SET_LOG("end");
640 }
641 
drawContent(SkCanvas * canvas,SkColor color)642 bool WebViewCore::drawContent(SkCanvas* canvas, SkColor color)
643 {
644 #ifdef ANDROID_INSTRUMENT
645     TimeCounterAuto counter(TimeCounter::WebViewUIDrawTimeCounter);
646 #endif
647     DBG_SET_LOG("start");
648     m_contentMutex.lock();
649     PictureSet copyContent = PictureSet(m_content);
650     m_contentMutex.unlock();
651     int sc = canvas->save(SkCanvas::kClip_SaveFlag);
652     SkRect clip;
653     clip.set(0, 0, copyContent.width(), copyContent.height());
654     canvas->clipRect(clip, SkRegion::kDifference_Op);
655     canvas->drawColor(color);
656     canvas->restoreToCount(sc);
657     bool tookTooLong = copyContent.draw(canvas);
658     m_contentMutex.lock();
659     m_content.setDrawTimes(copyContent);
660     m_contentMutex.unlock();
661     DBG_SET_LOG("end");
662     return tookTooLong;
663 }
664 
pictureReady()665 bool WebViewCore::pictureReady()
666 {
667     bool done;
668     m_contentMutex.lock();
669     PictureSet copyContent = PictureSet(m_content);
670     done = m_progressDone;
671     m_contentMutex.unlock();
672     DBG_NAV_LOGD("done=%s empty=%s", done ? "true" : "false",
673         copyContent.isEmpty() ? "true" : "false");
674     return done || !copyContent.isEmpty();
675 }
676 
rebuildPicture(const SkIRect & inval)677 SkPicture* WebViewCore::rebuildPicture(const SkIRect& inval)
678 {
679     WebCore::FrameView* view = m_mainFrame->view();
680     int width = view->contentsWidth();
681     int height = view->contentsHeight();
682     SkPicture* picture = new SkPicture();
683     SkAutoPictureRecord arp(picture, width, height);
684     SkAutoMemoryUsageProbe mup(__FUNCTION__);
685     SkCanvas* recordingCanvas = arp.getRecordingCanvas();
686 
687     gButtonMutex.lock();
688     WTF::Vector<Container> buttons(m_buttons);
689     gButtonMutex.unlock();
690 
691     WebCore::PlatformGraphicsContext pgc(recordingCanvas, &buttons);
692     WebCore::GraphicsContext gc(&pgc);
693     recordingCanvas->translate(-inval.fLeft, -inval.fTop);
694     recordingCanvas->save();
695     view->platformWidget()->draw(&gc, WebCore::IntRect(inval.fLeft,
696         inval.fTop, inval.width(), inval.height()));
697     m_rebuildInval.op(inval, SkRegion::kUnion_Op);
698     DBG_SET_LOGD("m_rebuildInval={%d,%d,r=%d,b=%d}",
699         m_rebuildInval.getBounds().fLeft, m_rebuildInval.getBounds().fTop,
700         m_rebuildInval.getBounds().fRight, m_rebuildInval.getBounds().fBottom);
701 
702     gButtonMutex.lock();
703     updateButtonList(&buttons);
704     gButtonMutex.unlock();
705 
706     return picture;
707 }
708 
rebuildPictureSet(PictureSet * pictureSet)709 void WebViewCore::rebuildPictureSet(PictureSet* pictureSet)
710 {
711     WebCore::FrameView* view = m_mainFrame->view();
712     size_t size = pictureSet->size();
713     for (size_t index = 0; index < size; index++) {
714         if (pictureSet->upToDate(index))
715             continue;
716         const SkIRect& inval = pictureSet->bounds(index);
717         DBG_SET_LOGD("pictSet=%p [%d] {%d,%d,w=%d,h=%d}", pictureSet, index,
718             inval.fLeft, inval.fTop, inval.width(), inval.height());
719         pictureSet->setPicture(index, rebuildPicture(inval));
720     }
721     pictureSet->validate(__FUNCTION__);
722 }
723 
recordContent(SkRegion * region,SkIPoint * point)724 bool WebViewCore::recordContent(SkRegion* region, SkIPoint* point)
725 {
726     DBG_SET_LOG("start");
727     float progress = (float) m_mainFrame->page()->progress()->estimatedProgress();
728     m_contentMutex.lock();
729     PictureSet contentCopy(m_content);
730     m_progressDone = progress <= 0.0f || progress >= 1.0f;
731     m_contentMutex.unlock();
732     recordPictureSet(&contentCopy);
733     if (!m_progressDone && contentCopy.isEmpty()) {
734         DBG_SET_LOGD("empty (progress=%g)", progress);
735         return false;
736     }
737     region->set(m_addInval);
738     m_addInval.setEmpty();
739     region->op(m_rebuildInval, SkRegion::kUnion_Op);
740     m_rebuildInval.setEmpty();
741     m_contentMutex.lock();
742     contentCopy.setDrawTimes(m_content);
743     m_content.set(contentCopy);
744     point->fX = m_content.width();
745     point->fY = m_content.height();
746     m_contentMutex.unlock();
747     DBG_SET_LOGD("region={%d,%d,r=%d,b=%d}", region->getBounds().fLeft,
748         region->getBounds().fTop, region->getBounds().fRight,
749         region->getBounds().fBottom);
750     DBG_SET_LOG("end");
751     return true;
752 }
753 
splitContent()754 void WebViewCore::splitContent()
755 {
756     bool layoutSuceeded = layoutIfNeededRecursive(m_mainFrame);
757     LOG_ASSERT(layoutSuceeded, "Can never be called recursively");
758     PictureSet tempPictureSet;
759     m_contentMutex.lock();
760     m_content.split(&tempPictureSet);
761     m_contentMutex.unlock();
762     rebuildPictureSet(&tempPictureSet);
763     m_contentMutex.lock();
764     m_content.set(tempPictureSet);
765     m_contentMutex.unlock();
766 }
767 
scrollTo(int x,int y,bool animate)768 void WebViewCore::scrollTo(int x, int y, bool animate)
769 {
770     LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
771 
772 //    LOGD("WebViewCore::scrollTo(%d %d)\n", x, y);
773 
774     JNIEnv* env = JSC::Bindings::getJNIEnv();
775     env->CallVoidMethod(m_javaGlue->object(env).get(), animate ? m_javaGlue->m_spawnScrollTo : m_javaGlue->m_scrollTo, x, y);
776     checkException(env);
777 }
778 
sendNotifyProgressFinished()779 void WebViewCore::sendNotifyProgressFinished()
780 {
781     LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
782     JNIEnv* env = JSC::Bindings::getJNIEnv();
783     env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_sendNotifyProgressFinished);
784     checkException(env);
785 }
786 
viewInvalidate(const WebCore::IntRect & rect)787 void WebViewCore::viewInvalidate(const WebCore::IntRect& rect)
788 {
789     LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
790     JNIEnv* env = JSC::Bindings::getJNIEnv();
791     env->CallVoidMethod(m_javaGlue->object(env).get(),
792                         m_javaGlue->m_sendViewInvalidate,
793                         rect.x(), rect.y(), rect.right(), rect.bottom());
794     checkException(env);
795 }
796 
scrollBy(int dx,int dy,bool animate)797 void WebViewCore::scrollBy(int dx, int dy, bool animate)
798 {
799     if (!(dx | dy))
800         return;
801     JNIEnv* env = JSC::Bindings::getJNIEnv();
802     env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_scrollBy,
803         dx, dy, animate);
804     checkException(env);
805 }
806 
contentDraw()807 void WebViewCore::contentDraw()
808 {
809     JNIEnv* env = JSC::Bindings::getJNIEnv();
810     env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_contentDraw);
811     checkException(env);
812 }
813 
contentInvalidate(const WebCore::IntRect & r)814 void WebViewCore::contentInvalidate(const WebCore::IntRect &r)
815 {
816     DBG_SET_LOGD("rect={%d,%d,w=%d,h=%d}", r.x(), r.y(), r.width(), r.height());
817     SkIRect rect(r);
818     if (!rect.intersect(0, 0, INT_MAX, INT_MAX))
819         return;
820     m_addInval.op(rect, SkRegion::kUnion_Op);
821     DBG_SET_LOGD("m_addInval={%d,%d,r=%d,b=%d}",
822         m_addInval.getBounds().fLeft, m_addInval.getBounds().fTop,
823         m_addInval.getBounds().fRight, m_addInval.getBounds().fBottom);
824     if (!m_skipContentDraw)
825         contentDraw();
826 }
827 
offInvalidate(const WebCore::IntRect & r)828 void WebViewCore::offInvalidate(const WebCore::IntRect &r)
829 {
830     // FIXME: these invalidates are offscreen, and can be throttled or
831     // deferred until the area is visible. For now, treat them as
832     // regular invals so that drawing happens (inefficiently) for now.
833     contentInvalidate(r);
834 }
835 
pin_pos(int x,int width,int targetWidth)836 static int pin_pos(int x, int width, int targetWidth)
837 {
838     if (x + width > targetWidth)
839         x = targetWidth - width;
840     if (x < 0)
841         x = 0;
842     return x;
843 }
844 
didFirstLayout()845 void WebViewCore::didFirstLayout()
846 {
847     DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
848     LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
849 
850     WebCore::FrameLoader* loader = m_mainFrame->loader();
851     const WebCore::KURL& url = loader->url();
852     if (url.isEmpty())
853         return;
854     LOGV("::WebCore:: didFirstLayout %s", url.string().ascii().data());
855 
856     WebCore::FrameLoadType loadType = loader->loadType();
857 
858     JNIEnv* env = JSC::Bindings::getJNIEnv();
859     env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_didFirstLayout,
860             loadType == WebCore::FrameLoadTypeStandard
861             // When redirect with locked history, we would like to reset the
862             // scale factor. This is important for www.yahoo.com as it is
863             // redirected to www.yahoo.com/?rs=1 on load.
864             || loadType == WebCore::FrameLoadTypeRedirectWithLockedBackForwardList);
865     checkException(env);
866 
867     DBG_NAV_LOG("call updateFrameCache");
868     m_check_domtree_version = false;
869     updateFrameCache();
870     m_history.setDidFirstLayout(true);
871 }
872 
updateViewport()873 void WebViewCore::updateViewport()
874 {
875     DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
876     LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
877 
878     JNIEnv* env = JSC::Bindings::getJNIEnv();
879     env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_updateViewport);
880     checkException(env);
881 }
882 
restoreScale(int scale)883 void WebViewCore::restoreScale(int scale)
884 {
885     DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
886     LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
887 
888     JNIEnv* env = JSC::Bindings::getJNIEnv();
889     env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_restoreScale, scale);
890     checkException(env);
891 }
892 
restoreScreenWidthScale(int scale)893 void WebViewCore::restoreScreenWidthScale(int scale)
894 {
895     DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
896     LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
897 
898     JNIEnv* env = JSC::Bindings::getJNIEnv();
899     env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_restoreScreenWidthScale, scale);
900     checkException(env);
901 }
902 
needTouchEvents(bool need)903 void WebViewCore::needTouchEvents(bool need)
904 {
905     DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
906     LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
907 
908 #if ENABLE(TOUCH_EVENTS) // Android
909     JNIEnv* env = JSC::Bindings::getJNIEnv();
910     AutoJObject obj = m_javaGlue->object(env);
911     // if it is called during DESTROY is handled, the real object of WebViewCore
912     // can be gone. Check before using it.
913     if (env && obj.get()) {
914         env->CallVoidMethod(obj.get(), m_javaGlue->m_needTouchEvents, need);
915         checkException(env);
916     }
917 #endif
918 }
919 
requestKeyboard(bool showKeyboard)920 void WebViewCore::requestKeyboard(bool showKeyboard)
921 {
922     DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
923     LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
924 
925     JNIEnv* env = JSC::Bindings::getJNIEnv();
926     env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_requestKeyboard, showKeyboard);
927     checkException(env);
928 }
929 
notifyProgressFinished()930 void WebViewCore::notifyProgressFinished()
931 {
932     DBG_NAV_LOG("call updateFrameCache");
933     m_check_domtree_version = true;
934     updateFrameCache();
935     sendNotifyProgressFinished();
936 }
937 
doMaxScroll(CacheBuilder::Direction dir)938 void WebViewCore::doMaxScroll(CacheBuilder::Direction dir)
939 {
940     int dx = 0, dy = 0;
941 
942     switch (dir) {
943     case CacheBuilder::LEFT:
944         dx = -m_maxXScroll;
945         break;
946     case CacheBuilder::UP:
947         dy = -m_maxYScroll;
948         break;
949     case CacheBuilder::RIGHT:
950         dx = m_maxXScroll;
951         break;
952     case CacheBuilder::DOWN:
953         dy = m_maxYScroll;
954         break;
955     case CacheBuilder::UNINITIALIZED:
956     default:
957         LOG_ASSERT(0, "unexpected focus selector");
958     }
959     this->scrollBy(dx, dy, true);
960 }
961 
setScrollOffset(int moveGeneration,int dx,int dy)962 void WebViewCore::setScrollOffset(int moveGeneration, int dx, int dy)
963 {
964     DBG_NAV_LOGD("{%d,%d} m_scrollOffset=(%d,%d)", dx, dy,
965         m_scrollOffsetX, m_scrollOffsetY);
966     if (m_scrollOffsetX != dx || m_scrollOffsetY != dy) {
967         m_scrollOffsetX = dx;
968         m_scrollOffsetY = dy;
969         // The visible rect is located within our coordinate space so it
970         // contains the actual scroll position. Setting the location makes hit
971         // testing work correctly.
972         m_mainFrame->view()->platformWidget()->setLocation(m_scrollOffsetX,
973                 m_scrollOffsetY);
974         m_mainFrame->eventHandler()->sendScrollEvent();
975 
976         // update the currently visible screen
977         sendPluginVisibleScreen();
978     }
979     gCursorBoundsMutex.lock();
980     bool hasCursorBounds = m_hasCursorBounds;
981     Frame* frame = (Frame*) m_cursorFrame;
982     IntPoint location = m_cursorLocation;
983     gCursorBoundsMutex.unlock();
984     if (!hasCursorBounds)
985         return;
986     moveMouseIfLatest(moveGeneration, frame, location.x(), location.y());
987 }
988 
setGlobalBounds(int x,int y,int h,int v)989 void WebViewCore::setGlobalBounds(int x, int y, int h, int v)
990 {
991     DBG_NAV_LOGD("{%d,%d}", x, y);
992     m_mainFrame->view()->platformWidget()->setWindowBounds(x, y, h, v);
993 }
994 
setSizeScreenWidthAndScale(int width,int height,int screenWidth,float scale,int realScreenWidth,int screenHeight,bool ignoreHeight)995 void WebViewCore::setSizeScreenWidthAndScale(int width, int height,
996     int screenWidth, float scale, int realScreenWidth, int screenHeight,
997     bool ignoreHeight)
998 {
999     WebCoreViewBridge* window = m_mainFrame->view()->platformWidget();
1000     int ow = window->width();
1001     int oh = window->height();
1002     window->setSize(width, height);
1003     int osw = m_screenWidth;
1004     DBG_NAV_LOGD("old:(w=%d,h=%d,sw=%d,scale=%g) new:(w=%d,h=%d,sw=%d,scale=%g)",
1005         ow, oh, osw, m_scale, width, height, screenWidth, scale);
1006     m_screenWidth = screenWidth;
1007     m_screenHeight = screenHeight;
1008     if (scale >= 0) { // negative means ignore
1009         m_scale = scale;
1010         if (screenWidth != realScreenWidth)
1011             m_screenWidthScale = realScreenWidth * scale / screenWidth;
1012         else
1013             m_screenWidthScale = m_scale;
1014     }
1015     m_maxXScroll = screenWidth >> 2;
1016     m_maxYScroll = (screenWidth * height / width) >> 2;
1017     if (ow != width || (!ignoreHeight && oh != height) || osw != screenWidth) {
1018         WebCore::RenderObject *r = m_mainFrame->contentRenderer();
1019         DBG_NAV_LOGD("renderer=%p view=(w=%d,h=%d)", r,
1020             realScreenWidth, screenHeight);
1021         if (r) {
1022             // get current screen center position
1023             WebCore::IntPoint screenCenter = WebCore::IntPoint(
1024                 m_scrollOffsetX + (realScreenWidth >> 1),
1025                 m_scrollOffsetY + (screenHeight >> 1));
1026             WebCore::HitTestResult hitTestResult = m_mainFrame->eventHandler()->
1027                 hitTestResultAtPoint(screenCenter, false);
1028             WebCore::Node* node = hitTestResult.innerNode();
1029             WebCore::IntRect bounds;
1030             WebCore::IntPoint offset;
1031             if (node) {
1032                 bounds = node->getRect();
1033                 DBG_NAV_LOGD("ob:(x=%d,y=%d,w=%d,h=%d)",
1034                     bounds.x(), bounds.y(), bounds.width(), bounds.height());
1035                 offset = WebCore::IntPoint(screenCenter.x() - bounds.x(),
1036                     screenCenter.y() - bounds.y());
1037                 if (offset.x() < 0 || offset.x() > realScreenWidth ||
1038                     offset.y() < 0 || offset.y() > screenHeight)
1039                 {
1040                     DBG_NAV_LOGD("offset out of bounds:(x=%d,y=%d)",
1041                         offset.x(), offset.y());
1042                     node = 0;
1043                 }
1044             }
1045             r->setNeedsLayoutAndPrefWidthsRecalc();
1046             m_mainFrame->view()->forceLayout();
1047             // scroll to restore current screen center
1048             if (!node)
1049                 return;
1050             const WebCore::IntRect& newBounds = node->getRect();
1051             DBG_NAV_LOGD("nb:(x=%d,y=%d,w=%d,"
1052                 "h=%d,ns=%d)", newBounds.x(), newBounds.y(),
1053                 newBounds.width(), newBounds.height());
1054             scrollBy(newBounds.x() - bounds.x(), newBounds.y() - bounds.y(),
1055                 false);
1056         }
1057     }
1058 
1059     // update the currently visible screen
1060     sendPluginVisibleScreen();
1061 }
1062 
dumpDomTree(bool useFile)1063 void WebViewCore::dumpDomTree(bool useFile)
1064 {
1065 #ifdef ANDROID_DOM_LOGGING
1066     if (useFile)
1067         gDomTreeFile = fopen(DOM_TREE_LOG_FILE, "w");
1068     m_mainFrame->document()->showTreeForThis();
1069     if (gDomTreeFile) {
1070         fclose(gDomTreeFile);
1071         gDomTreeFile = 0;
1072     }
1073 #endif
1074 }
1075 
dumpRenderTree(bool useFile)1076 void WebViewCore::dumpRenderTree(bool useFile)
1077 {
1078 #ifdef ANDROID_DOM_LOGGING
1079     if (useFile)
1080         gRenderTreeFile = fopen(RENDER_TREE_LOG_FILE, "w");
1081     WebCore::CString renderDump = WebCore::externalRepresentation(m_mainFrame->contentRenderer()).utf8();
1082     const char* data = renderDump.data();
1083     int length = renderDump.length();
1084     int last = 0;
1085     for (int i = 0; i < length; i++) {
1086         if (data[i] == '\n') {
1087             if (i != last) {
1088                 char* chunk = new char[i - last + 1];
1089                 strncpy(chunk, (data + last), i - last);
1090                 chunk[i - last] = '\0';
1091                 DUMP_RENDER_LOGD("%s", chunk);
1092             }
1093             last = i + 1;
1094         }
1095     }
1096     if (gRenderTreeFile) {
1097         fclose(gRenderTreeFile);
1098         gRenderTreeFile = 0;
1099     }
1100 #endif
1101 }
1102 
dumpNavTree()1103 void WebViewCore::dumpNavTree()
1104 {
1105 #if DUMP_NAV_CACHE
1106     cacheBuilder().mDebug.print();
1107 #endif
1108 }
1109 
retrieveHref(WebCore::Frame * frame,WebCore::Node * node)1110 WebCore::String WebViewCore::retrieveHref(WebCore::Frame* frame, WebCore::Node* node)
1111 {
1112     if (!CacheBuilder::validNode(m_mainFrame, frame, node))
1113         return WebCore::String();
1114     if (!node->hasTagName(WebCore::HTMLNames::aTag))
1115         return WebCore::String();
1116     WebCore::HTMLAnchorElement* anchor = static_cast<WebCore::HTMLAnchorElement*>(node);
1117     return anchor->href();
1118 }
1119 
updateCacheOnNodeChange()1120 void WebViewCore::updateCacheOnNodeChange()
1121 {
1122     gCursorBoundsMutex.lock();
1123     bool hasCursorBounds = m_hasCursorBounds;
1124     Frame* frame = (Frame*) m_cursorFrame;
1125     Node* node = (Node*) m_cursorNode;
1126     IntRect bounds = m_cursorHitBounds;
1127     gCursorBoundsMutex.unlock();
1128     if (!hasCursorBounds || !node)
1129         return;
1130     if (CacheBuilder::validNode(m_mainFrame, frame, node)) {
1131         RenderObject* renderer = node->renderer();
1132         if (renderer && renderer->style()->visibility() != HIDDEN) {
1133             IntRect absBox = renderer->absoluteBoundingBoxRect();
1134             int globalX, globalY;
1135             CacheBuilder::GetGlobalOffset(frame, &globalX, &globalY);
1136             absBox.move(globalX, globalY);
1137             if (absBox == bounds)
1138                 return;
1139             DBG_NAV_LOGD("absBox=(%d,%d,%d,%d) bounds=(%d,%d,%d,%d)",
1140                 absBox.x(), absBox.y(), absBox.width(), absBox.height(),
1141                 bounds.x(), bounds.y(), bounds.width(), bounds.height());
1142         }
1143     }
1144     DBG_NAV_LOGD("updateFrameCache node=%p", node);
1145     updateFrameCache();
1146 }
1147 
updateFrameCache()1148 void WebViewCore::updateFrameCache()
1149 {
1150     if (!m_frameCacheOutOfDate) {
1151         DBG_NAV_LOG("!m_frameCacheOutOfDate");
1152         return;
1153     }
1154 #ifdef ANDROID_INSTRUMENT
1155     TimeCounterAuto counter(TimeCounter::WebViewCoreBuildNavTimeCounter);
1156 #endif
1157     m_frameCacheOutOfDate = false;
1158 #if DEBUG_NAV_UI
1159     m_now = SkTime::GetMSecs();
1160 #endif
1161     m_temp = new CachedRoot();
1162     m_temp->init(m_mainFrame, &m_history);
1163     CacheBuilder& builder = cacheBuilder();
1164     WebCore::Settings* settings = m_mainFrame->page()->settings();
1165     builder.allowAllTextDetection();
1166 #ifdef ANDROID_META_SUPPORT
1167     if (settings) {
1168         if (!settings->formatDetectionAddress())
1169             builder.disallowAddressDetection();
1170         if (!settings->formatDetectionEmail())
1171             builder.disallowEmailDetection();
1172         if (!settings->formatDetectionTelephone())
1173             builder.disallowPhoneDetection();
1174     }
1175 #endif
1176     builder.buildCache(m_temp);
1177     m_tempPict = new SkPicture();
1178     recordPicture(m_tempPict);
1179     m_temp->setPicture(m_tempPict);
1180     m_temp->setTextGeneration(m_textGeneration);
1181     WebCoreViewBridge* window = m_mainFrame->view()->platformWidget();
1182     m_temp->setVisibleRect(WebCore::IntRect(m_scrollOffsetX,
1183         m_scrollOffsetY, window->width(), window->height()));
1184     gFrameCacheMutex.lock();
1185     delete m_frameCacheKit;
1186     delete m_navPictureKit;
1187     m_frameCacheKit = m_temp;
1188     m_navPictureKit = m_tempPict;
1189     m_updatedFrameCache = true;
1190 #if DEBUG_NAV_UI
1191     const CachedNode* cachedFocusNode = m_frameCacheKit->currentFocus();
1192     DBG_NAV_LOGD("cachedFocusNode=%d (nodePointer=%p)",
1193         cachedFocusNode ? cachedFocusNode->index() : 0,
1194         cachedFocusNode ? cachedFocusNode->nodePointer() : 0);
1195 #endif
1196     gFrameCacheMutex.unlock();
1197 }
1198 
updateFrameCacheIfLoading()1199 void WebViewCore::updateFrameCacheIfLoading()
1200 {
1201     if (!m_check_domtree_version)
1202         updateFrameCache();
1203 }
1204 
1205 ///////////////////////////////////////////////////////////////////////////////
1206 
addPlugin(PluginWidgetAndroid * w)1207 void WebViewCore::addPlugin(PluginWidgetAndroid* w)
1208 {
1209 //    SkDebugf("----------- addPlugin %p", w);
1210     *m_plugins.append() = w;
1211 }
1212 
removePlugin(PluginWidgetAndroid * w)1213 void WebViewCore::removePlugin(PluginWidgetAndroid* w)
1214 {
1215 //    SkDebugf("----------- removePlugin %p", w);
1216     int index = m_plugins.find(w);
1217     if (index < 0) {
1218         SkDebugf("--------------- pluginwindow not found! %p\n", w);
1219     } else {
1220         m_plugins.removeShuffle(index);
1221     }
1222 }
1223 
invalPlugin(PluginWidgetAndroid * w)1224 void WebViewCore::invalPlugin(PluginWidgetAndroid* w)
1225 {
1226     const double PLUGIN_INVAL_DELAY = 1.0 / 60;
1227 
1228     if (!m_pluginInvalTimer.isActive()) {
1229         m_pluginInvalTimer.startOneShot(PLUGIN_INVAL_DELAY);
1230     }
1231 }
1232 
drawPlugins()1233 void WebViewCore::drawPlugins()
1234 {
1235     SkRegion inval; // accumualte what needs to be redrawn
1236     PluginWidgetAndroid** iter = m_plugins.begin();
1237     PluginWidgetAndroid** stop = m_plugins.end();
1238 
1239     for (; iter < stop; ++iter) {
1240         PluginWidgetAndroid* w = *iter;
1241         SkIRect dirty;
1242         if (w->isDirty(&dirty)) {
1243             w->draw();
1244             w->localToDocumentCoords(&dirty);
1245             inval.op(dirty, SkRegion::kUnion_Op);
1246         }
1247     }
1248 
1249     if (!inval.isEmpty()) {
1250         // inval.getBounds() is our rectangle
1251         const SkIRect& bounds = inval.getBounds();
1252         WebCore::IntRect r(bounds.fLeft, bounds.fTop,
1253                            bounds.width(), bounds.height());
1254         this->viewInvalidate(r);
1255     }
1256 }
1257 
notifyPluginsOnFrameLoad(const Frame * frame)1258 void WebViewCore::notifyPluginsOnFrameLoad(const Frame* frame) {
1259     // if frame is the parent then notify all plugins
1260     if (!frame->tree()->parent()) {
1261         // trigger an event notifying the plugins that the page has loaded
1262         ANPEvent event;
1263         SkANP::InitEvent(&event, kLifecycle_ANPEventType);
1264         event.data.lifecycle.action = kOnLoad_ANPLifecycleAction;
1265         sendPluginEvent(event);
1266     }
1267     // else if frame's parent has completed
1268     else if (!frame->tree()->parent()->loader()->isLoading()) {
1269         // send to all plugins who have this frame in their heirarchy
1270         PluginWidgetAndroid** iter = m_plugins.begin();
1271         PluginWidgetAndroid** stop = m_plugins.end();
1272         for (; iter < stop; ++iter) {
1273             Frame* currentFrame = (*iter)->pluginView()->parentFrame();
1274             while (currentFrame) {
1275                 if (frame == currentFrame) {
1276                     ANPEvent event;
1277                     SkANP::InitEvent(&event, kLifecycle_ANPEventType);
1278                     event.data.lifecycle.action = kOnLoad_ANPLifecycleAction;
1279                     (*iter)->sendEvent(event);
1280                     break;
1281                 }
1282                 currentFrame = currentFrame->tree()->parent();
1283             }
1284         }
1285     }
1286 }
1287 
sendPluginVisibleScreen()1288 void WebViewCore::sendPluginVisibleScreen()
1289 {
1290     ANPRectI visibleRect;
1291     visibleRect.left = m_scrollOffsetX;
1292     visibleRect.top = m_scrollOffsetY;
1293     visibleRect.right = m_scrollOffsetX + m_screenWidth;
1294     visibleRect.bottom = m_scrollOffsetY + m_screenHeight;
1295 
1296     PluginWidgetAndroid** iter = m_plugins.begin();
1297     PluginWidgetAndroid** stop = m_plugins.end();
1298     for (; iter < stop; ++iter) {
1299         (*iter)->setVisibleScreen(visibleRect, m_scale);
1300     }
1301 }
1302 
sendPluginEvent(const ANPEvent & evt,ANPEventFlag flag)1303 void WebViewCore::sendPluginEvent(const ANPEvent& evt, ANPEventFlag flag)
1304 {
1305     PluginWidgetAndroid** iter = m_plugins.begin();
1306     PluginWidgetAndroid** stop = m_plugins.end();
1307     for (; iter < stop; ++iter) {
1308         if((*iter)->isAcceptingEvent(flag))
1309             (*iter)->sendEvent(evt);
1310     }
1311 }
1312 
sendPluginEvent(const ANPEvent & evt)1313 void WebViewCore::sendPluginEvent(const ANPEvent& evt)
1314 {
1315     PluginWidgetAndroid** iter = m_plugins.begin();
1316     PluginWidgetAndroid** stop = m_plugins.end();
1317     for (; iter < stop; ++iter) {
1318         (*iter)->sendEvent(evt);
1319     }
1320 }
1321 
nodeIsPlugin(Node * node)1322 static PluginView* nodeIsPlugin(Node* node) {
1323     RenderObject* renderer = node->renderer();
1324     if (renderer && renderer->isWidget()) {
1325         Widget* widget = static_cast<RenderWidget*>(renderer)->widget();
1326         if (widget && widget->isPluginView())
1327             return static_cast<PluginView*>(widget);
1328     }
1329     return 0;
1330 }
1331 
cursorNodeIsPlugin()1332 Node* WebViewCore::cursorNodeIsPlugin() {
1333     gCursorBoundsMutex.lock();
1334     bool hasCursorBounds = m_hasCursorBounds;
1335     Frame* frame = (Frame*) m_cursorFrame;
1336     Node* node = (Node*) m_cursorNode;
1337     gCursorBoundsMutex.unlock();
1338     if (hasCursorBounds && CacheBuilder::validNode(m_mainFrame, frame, node)
1339             && nodeIsPlugin(node)) {
1340         return node;
1341     }
1342     return 0;
1343 }
1344 
1345 
updatePluginState(Frame * frame,Node * node,PluginState state)1346 void WebViewCore::updatePluginState(Frame* frame, Node* node, PluginState state) {
1347 
1348     // check that the node and frame pointers are (still) valid
1349     if (!frame || !node || !CacheBuilder::validNode(m_mainFrame, frame, node))
1350         return;
1351 
1352     // check that the node is a plugin view
1353     PluginView* pluginView = nodeIsPlugin(node);
1354     if (!pluginView)
1355         return;
1356 
1357     // create the event
1358     ANPEvent event;
1359     SkANP::InitEvent(&event, kLifecycle_ANPEventType);
1360 
1361     if (state == kLoseFocus_PluginState)
1362         event.data.lifecycle.action = kLoseFocus_ANPLifecycleAction;
1363     else if (state == kGainFocus_PluginState)
1364         event.data.lifecycle.action = kGainFocus_ANPLifecycleAction;
1365     else
1366         return;
1367 
1368     // send the event
1369     pluginView->platformPluginWidget()->sendEvent(event);
1370 }
1371 
1372 ///////////////////////////////////////////////////////////////////////////////
moveMouseIfLatest(int moveGeneration,WebCore::Frame * frame,int x,int y)1373 void WebViewCore::moveMouseIfLatest(int moveGeneration,
1374     WebCore::Frame* frame, int x, int y)
1375 {
1376     DBG_NAV_LOGD("m_moveGeneration=%d moveGeneration=%d"
1377         " frame=%p x=%d y=%d",
1378         m_moveGeneration, moveGeneration, frame, x, y);
1379     if (m_moveGeneration > moveGeneration) {
1380         DBG_NAV_LOGD("m_moveGeneration=%d > moveGeneration=%d",
1381             m_moveGeneration, moveGeneration);
1382         return; // short-circuit if a newer move has already been generated
1383     }
1384     m_lastGeneration = moveGeneration;
1385     moveMouse(frame, x, y);
1386 }
1387 
1388 // Update mouse position and may change focused node.
moveMouse(WebCore::Frame * frame,int x,int y)1389 void WebViewCore::moveMouse(WebCore::Frame* frame, int x, int y)
1390 {
1391     DBG_NAV_LOGD("frame=%p x=%d y=%d scrollOffset=(%d,%d)", frame,
1392         x, y, m_scrollOffsetX, m_scrollOffsetY);
1393     if (!frame || CacheBuilder::validNode(m_mainFrame, frame, NULL) == false)
1394         frame = m_mainFrame;
1395     // mouse event expects the position in the window coordinate
1396     m_mousePos = WebCore::IntPoint(x - m_scrollOffsetX, y - m_scrollOffsetY);
1397     // validNode will still return true if the node is null, as long as we have
1398     // a valid frame.  Do not want to make a call on frame unless it is valid.
1399     WebCore::PlatformMouseEvent mouseEvent(m_mousePos, m_mousePos,
1400         WebCore::NoButton, WebCore::MouseEventMoved, 1, false, false, false,
1401         false, WTF::currentTime());
1402     frame->eventHandler()->handleMouseMoveEvent(mouseEvent);
1403     updateCacheOnNodeChange();
1404 }
1405 
findTextBoxIndex(WebCore::Node * node,const WebCore::IntPoint & pt)1406 static int findTextBoxIndex(WebCore::Node* node, const WebCore::IntPoint& pt)
1407 {
1408     if (!node->isTextNode()) {
1409         DBG_NAV_LOGD("node=%p pt=(%d,%d) isText=false", node, pt.x(), pt.y());
1410         return -2; // error
1411     }
1412     WebCore::RenderText* renderText = (WebCore::RenderText*) node->renderer();
1413     if (!renderText) {
1414         DBG_NAV_LOGD("node=%p pt=(%d,%d) renderText=0", node, pt.x(), pt.y());
1415         return -3; // error
1416     }
1417     FloatPoint absPt = renderText->localToAbsolute();
1418     WebCore::InlineTextBox *textBox = renderText->firstTextBox();
1419     int globalX, globalY;
1420     CacheBuilder::GetGlobalOffset(node, &globalX, &globalY);
1421     int x = pt.x() - globalX;
1422     int y = pt.y() - globalY;
1423     do {
1424         int textBoxStart = textBox->start();
1425         int textBoxEnd = textBoxStart + textBox->len();
1426         if (textBoxEnd <= textBoxStart)
1427             continue;
1428         WebCore::IntRect bounds = textBox->selectionRect(absPt.x(), absPt.y(),
1429             textBoxStart, textBoxEnd);
1430         if (!bounds.contains(x, y))
1431             continue;
1432         int offset = textBox->offsetForPosition(x - absPt.x());
1433 #if DEBUG_NAV_UI
1434         int prior = offset > 0 ? textBox->positionForOffset(offset - 1) : -1;
1435         int current = textBox->positionForOffset(offset);
1436         int next = textBox->positionForOffset(offset + 1);
1437         DBG_NAV_LOGD(
1438             "offset=%d pt.x=%d globalX=%d renderX=%d x=%d "
1439             "textBox->x()=%d textBox->start()=%d prior=%d current=%d next=%d",
1440             offset, pt.x(), globalX, absPt.x(), x,
1441             textBox->x(), textBox->start(), prior, current, next
1442             );
1443 #endif
1444         return textBox->start() + offset;
1445     } while ((textBox = textBox->nextTextBox()));
1446     return -1; // couldn't find point, may have walked off end
1447 }
1448 
isPunctuation(UChar c)1449 static inline bool isPunctuation(UChar c)
1450 {
1451     return WTF::Unicode::category(c) & (0
1452         | WTF::Unicode::Punctuation_Dash
1453         | WTF::Unicode::Punctuation_Open
1454         | WTF::Unicode::Punctuation_Close
1455         | WTF::Unicode::Punctuation_Connector
1456         | WTF::Unicode::Punctuation_Other
1457         | WTF::Unicode::Punctuation_InitialQuote
1458         | WTF::Unicode::Punctuation_FinalQuote
1459     );
1460 }
1461 
centerX(const SkIRect & rect)1462 static int centerX(const SkIRect& rect)
1463 {
1464     return (rect.fLeft + rect.fRight) >> 1;
1465 }
1466 
centerY(const SkIRect & rect)1467 static int centerY(const SkIRect& rect)
1468 {
1469     return (rect.fTop + rect.fBottom) >> 1;
1470 }
1471 
getSelection(SkRegion * selRgn)1472 WebCore::String WebViewCore::getSelection(SkRegion* selRgn)
1473 {
1474     SkRegion::Iterator iter(*selRgn);
1475     // FIXME: switch this to use StringBuilder instead
1476     WebCore::String result;
1477     WebCore::Node* lastStartNode = 0;
1478     int lastStartEnd = -1;
1479     UChar lastChar = 0xffff;
1480     for (; !iter.done(); iter.next()) {
1481         const SkIRect& rect = iter.rect();
1482         DBG_NAV_LOGD("rect=(%d, %d, %d, %d)", rect.fLeft, rect.fTop,
1483             rect.fRight, rect.fBottom);
1484         int cy = centerY(rect);
1485         WebCore::IntPoint startPt = WebCore::IntPoint(rect.fLeft + 1, cy);
1486         WebCore::HitTestResult hitTestResult = m_mainFrame->eventHandler()->
1487             hitTestResultAtPoint(startPt, false);
1488         WebCore::Node* node = hitTestResult.innerNode();
1489         if (!node) {
1490             DBG_NAV_LOG("!node");
1491             return result;
1492         }
1493         WebCore::IntPoint endPt = WebCore::IntPoint(rect.fRight - 1, cy);
1494         hitTestResult = m_mainFrame->eventHandler()->hitTestResultAtPoint(endPt, false);
1495         WebCore::Node* endNode = hitTestResult.innerNode();
1496         if (!endNode) {
1497             DBG_NAV_LOG("!endNode (right-1)");
1498             endPt = WebCore::IntPoint(rect.fRight - 2, cy);
1499             hitTestResult = m_mainFrame->eventHandler()->hitTestResultAtPoint(endPt, false);
1500             endNode = hitTestResult.innerNode();
1501         }
1502         if (!endNode) {
1503             DBG_NAV_LOG("!endNode (right-2)");
1504             return result;
1505         }
1506         int start = findTextBoxIndex(node, startPt);
1507         if (start < 0)
1508             continue;
1509         int end = findTextBoxIndex(endNode, endPt);
1510         if (end < -1) // use node if endNode is not valid
1511             endNode = node;
1512         if (end <= 0)
1513             end = static_cast<WebCore::Text*>(endNode)->string()->length();
1514         DBG_NAV_LOGD("node=%p start=%d endNode=%p end=%d", node, start, endNode, end);
1515         WebCore::Node* startNode = node;
1516         do {
1517             if (!node->isTextNode())
1518                 continue;
1519             if (node->getRect().isEmpty())
1520                 continue;
1521             WebCore::Text* textNode = static_cast<WebCore::Text*>(node);
1522             WebCore::StringImpl* string = textNode->string();
1523             if (!string->length())
1524                 continue;
1525             const UChar* chars = string->characters();
1526             int newLength = node == endNode ? end : string->length();
1527             if (node == startNode) {
1528  #if DEBUG_NAV_UI
1529                 if (node == lastStartNode)
1530                     DBG_NAV_LOGD("start=%d last=%d", start, lastStartEnd);
1531  #endif
1532                 if (node == lastStartNode && start < lastStartEnd)
1533                     break; // skip rect if text overlaps already written text
1534                 lastStartNode = node;
1535                 lastStartEnd = newLength - start;
1536             }
1537             if (newLength < start) {
1538                 DBG_NAV_LOGD("newLen=%d < start=%d", newLength, start);
1539                 break;
1540             }
1541             if (!isPunctuation(chars[start]))
1542                 result.append(' ');
1543             result.append(chars + start, newLength - start);
1544             start = 0;
1545         } while (node != endNode && (node = node->traverseNextNode()));
1546     }
1547     result = result.simplifyWhiteSpace().stripWhiteSpace();
1548 #if DUMP_NAV_CACHE
1549     {
1550         char buffer[256];
1551         CacheBuilder::Debug debug;
1552         debug.init(buffer, sizeof(buffer));
1553         debug.print("copy: ");
1554         debug.wideString(result);
1555         DUMP_NAV_LOGD("%s", buffer);
1556     }
1557 #endif
1558     return result;
1559 }
1560 
setSelection(int start,int end)1561 void WebViewCore::setSelection(int start, int end)
1562 {
1563     WebCore::Node* focus = currentFocus();
1564     if (!focus)
1565         return;
1566     WebCore::RenderObject* renderer = focus->renderer();
1567     if (!renderer || (!renderer->isTextField() && !renderer->isTextArea()))
1568         return;
1569     WebCore::RenderTextControl* rtc = static_cast<WebCore::RenderTextControl*>(renderer);
1570     if (start > end) {
1571         int temp = start;
1572         start = end;
1573         end = temp;
1574     }
1575     // Tell our EditorClient that this change was generated from the UI, so it
1576     // does not need to echo it to the UI.
1577     EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
1578             m_mainFrame->editor()->client());
1579     client->setUiGeneratedSelectionChange(true);
1580     rtc->setSelectionRange(start, end);
1581     client->setUiGeneratedSelectionChange(false);
1582     focus->document()->frame()->revealSelection();
1583     setFocusControllerActive(true);
1584 }
1585 
deleteSelection(int start,int end,int textGeneration)1586 void WebViewCore::deleteSelection(int start, int end, int textGeneration)
1587 {
1588     setSelection(start, end);
1589     if (start == end)
1590         return;
1591     WebCore::Node* focus = currentFocus();
1592     if (!focus)
1593         return;
1594     WebCore::TypingCommand::deleteSelection(focus->document());
1595     m_textGeneration = textGeneration;
1596 }
1597 
replaceTextfieldText(int oldStart,int oldEnd,const WebCore::String & replace,int start,int end,int textGeneration)1598 void WebViewCore::replaceTextfieldText(int oldStart,
1599         int oldEnd, const WebCore::String& replace, int start, int end,
1600         int textGeneration)
1601 {
1602     WebCore::Node* focus = currentFocus();
1603     if (!focus)
1604         return;
1605     setSelection(oldStart, oldEnd);
1606     // Prevent our editor client from passing a message to change the
1607     // selection.
1608     EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
1609             m_mainFrame->editor()->client());
1610     client->setUiGeneratedSelectionChange(true);
1611     WebCore::TypingCommand::insertText(focus->document(), replace,
1612         false);
1613     client->setUiGeneratedSelectionChange(false);
1614     setSelection(start, end);
1615     m_textGeneration = textGeneration;
1616 }
1617 
passToJs(int generation,const WebCore::String & current,const PlatformKeyboardEvent & event)1618 void WebViewCore::passToJs(int generation, const WebCore::String& current,
1619     const PlatformKeyboardEvent& event)
1620 {
1621     WebCore::Node* focus = currentFocus();
1622     if (!focus) {
1623         DBG_NAV_LOG("!focus");
1624         clearTextEntry();
1625         return;
1626     }
1627     WebCore::RenderObject* renderer = focus->renderer();
1628     if (!renderer || (!renderer->isTextField() && !renderer->isTextArea())) {
1629         DBG_NAV_LOGD("renderer==%p || not text", renderer);
1630         clearTextEntry();
1631         return;
1632     }
1633     // Block text field updates during a key press.
1634     m_blockTextfieldUpdates = true;
1635     // Also prevent our editor client from passing a message to change the
1636     // selection.
1637     EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
1638             m_mainFrame->editor()->client());
1639     client->setUiGeneratedSelectionChange(true);
1640     key(event);
1641     client->setUiGeneratedSelectionChange(false);
1642     m_blockTextfieldUpdates = false;
1643     m_textGeneration = generation;
1644     setFocusControllerActive(true);
1645     WebCore::RenderTextControl* renderText =
1646         static_cast<WebCore::RenderTextControl*>(renderer);
1647     WebCore::String test = renderText->text();
1648     if (test == current) {
1649         DBG_NAV_LOG("test == current");
1650         return;
1651     }
1652     // If the text changed during the key event, update the UI text field.
1653     updateTextfield(focus, false, test);
1654 }
1655 
scrollFocusedTextInput(float xPercent,int y)1656 void WebViewCore::scrollFocusedTextInput(float xPercent, int y)
1657 {
1658     WebCore::Node* focus = currentFocus();
1659     if (!focus) {
1660         DBG_NAV_LOG("!focus");
1661         clearTextEntry();
1662         return;
1663     }
1664     WebCore::RenderObject* renderer = focus->renderer();
1665     if (!renderer || (!renderer->isTextField() && !renderer->isTextArea())) {
1666         DBG_NAV_LOGD("renderer==%p || not text", renderer);
1667         clearTextEntry();
1668         return;
1669     }
1670     WebCore::RenderTextControl* renderText =
1671         static_cast<WebCore::RenderTextControl*>(renderer);
1672     int x = (int) (xPercent * (renderText->scrollWidth() -
1673         renderText->clientWidth()));
1674     DBG_NAV_LOGD("x=%d y=%d xPercent=%g scrollW=%d clientW=%d", x, y,
1675         xPercent, renderText->scrollWidth(), renderText->clientWidth());
1676     renderText->setScrollLeft(x);
1677     renderText->setScrollTop(y);
1678 }
1679 
setFocusControllerActive(bool active)1680 void WebViewCore::setFocusControllerActive(bool active)
1681 {
1682     m_mainFrame->page()->focusController()->setActive(active);
1683 }
1684 
saveDocumentState(WebCore::Frame * frame)1685 void WebViewCore::saveDocumentState(WebCore::Frame* frame)
1686 {
1687     if (!CacheBuilder::validNode(m_mainFrame, frame, 0))
1688         frame = m_mainFrame;
1689     WebCore::HistoryItem *item = frame->loader()->currentHistoryItem();
1690 
1691     // item can be null when there is no offical URL for the current page. This happens
1692     // when the content is loaded using with WebCoreFrameBridge::LoadData() and there
1693     // is no failing URL (common case is when content is loaded using data: scheme)
1694     if (item) {
1695         item->setDocumentState(frame->document()->formElementsState());
1696     }
1697 }
1698 
1699 // Convert a WebCore::String into an array of characters where the first
1700 // character represents the length, for easy conversion to java.
stringConverter(const WebCore::String & text)1701 static uint16_t* stringConverter(const WebCore::String& text)
1702 {
1703     size_t length = text.length();
1704     uint16_t* itemName = new uint16_t[length+1];
1705     itemName[0] = (uint16_t)length;
1706     uint16_t* firstChar = &(itemName[1]);
1707     memcpy((void*)firstChar, text.characters(), sizeof(UChar)*length);
1708     return itemName;
1709 }
1710 
1711 // Response to dropdown created for a listbox.
1712 class ListBoxReply : public WebCoreReply {
1713 public:
ListBoxReply(WebCore::HTMLSelectElement * select,WebCore::Frame * frame,WebViewCore * view)1714     ListBoxReply(WebCore::HTMLSelectElement* select, WebCore::Frame* frame, WebViewCore* view)
1715         : m_select(select)
1716         , m_frame(frame)
1717         , m_viewImpl(view)
1718     {}
1719 
1720     // Response used if the listbox only allows single selection.
1721     // index is listIndex of the selected item, or -1 if nothing is selected.
replyInt(int index)1722     virtual void replyInt(int index)
1723     {
1724         if (-2 == index) {
1725             // Special value for cancel. Do nothing.
1726             return;
1727         }
1728         // If the select element no longer exists, due to a page change, etc,
1729         // silently return.
1730         if (!m_select || !CacheBuilder::validNode(m_viewImpl->m_mainFrame,
1731                 m_frame, m_select))
1732             return;
1733         // Use a pointer to HTMLSelectElement's superclass, where
1734         // listToOptionIndex is public.
1735         SelectElement* selectElement = m_select;
1736         int optionIndex = selectElement->listToOptionIndex(index);
1737         m_select->setSelectedIndex(optionIndex, true);
1738         m_select->dispatchFormControlChangeEvent();
1739         m_viewImpl->contentInvalidate(m_select->getRect());
1740     }
1741 
1742     // Response if the listbox allows multiple selection.  array stores the listIndices
1743     // of selected positions.
replyIntArray(const int * array,int count)1744     virtual void replyIntArray(const int* array, int count)
1745     {
1746         // If the select element no longer exists, due to a page change, etc,
1747         // silently return.
1748         if (!m_select || !CacheBuilder::validNode(m_viewImpl->m_mainFrame,
1749                 m_frame, m_select))
1750             return;
1751 
1752         // If count is 1 or 0, use replyInt.
1753         SkASSERT(count > 1);
1754 
1755         const WTF::Vector<Element*>& items = m_select->listItems();
1756         int totalItems = static_cast<int>(items.size());
1757         // Keep track of the position of the value we are comparing against.
1758         int arrayIndex = 0;
1759         // The value we are comparing against.
1760         int selection = array[arrayIndex];
1761         WebCore::HTMLOptionElement* option;
1762         for (int listIndex = 0; listIndex < totalItems; listIndex++) {
1763             if (items[listIndex]->hasLocalName(WebCore::HTMLNames::optionTag)) {
1764                 option = static_cast<WebCore::HTMLOptionElement*>(
1765                         items[listIndex]);
1766                 if (listIndex == selection) {
1767                     option->setSelectedState(true);
1768                     arrayIndex++;
1769                     if (arrayIndex == count)
1770                         selection = -1;
1771                     else
1772                         selection = array[arrayIndex];
1773                 } else
1774                     option->setSelectedState(false);
1775             }
1776         }
1777         m_select->dispatchFormControlChangeEvent();
1778         m_viewImpl->contentInvalidate(m_select->getRect());
1779     }
1780 private:
1781     // The select element associated with this listbox.
1782     WebCore::HTMLSelectElement* m_select;
1783     // The frame of this select element, to verify that it is valid.
1784     WebCore::Frame* m_frame;
1785     // For calling invalidate and checking the select element's validity
1786     WebViewCore* m_viewImpl;
1787 };
1788 
1789 // Create an array of java Strings.
makeLabelArray(JNIEnv * env,const uint16_t ** labels,size_t count)1790 static jobjectArray makeLabelArray(JNIEnv* env, const uint16_t** labels, size_t count)
1791 {
1792     jclass stringClass = env->FindClass("java/lang/String");
1793     LOG_ASSERT(stringClass, "Could not find java/lang/String");
1794     jobjectArray array = env->NewObjectArray(count, stringClass, 0);
1795     LOG_ASSERT(array, "Could not create new string array");
1796 
1797     for (size_t i = 0; i < count; i++) {
1798         jobject newString = env->NewString(&labels[i][1], labels[i][0]);
1799         env->SetObjectArrayElement(array, i, newString);
1800         env->DeleteLocalRef(newString);
1801         checkException(env);
1802     }
1803     env->DeleteLocalRef(stringClass);
1804     return array;
1805 }
1806 
listBoxRequest(WebCoreReply * reply,const uint16_t ** labels,size_t count,const int enabled[],size_t enabledCount,bool multiple,const int selected[],size_t selectedCountOrSelection)1807 void WebViewCore::listBoxRequest(WebCoreReply* reply, const uint16_t** labels, size_t count, const int enabled[], size_t enabledCount,
1808         bool multiple, const int selected[], size_t selectedCountOrSelection)
1809 {
1810     // If m_popupReply is not null, then we already have a list showing.
1811     if (m_popupReply != 0)
1812         return;
1813 
1814     LOG_ASSERT(m_javaGlue->m_obj, "No java widget associated with this view!");
1815 
1816     // Create an array of java Strings for the drop down.
1817     JNIEnv* env = JSC::Bindings::getJNIEnv();
1818     jobjectArray labelArray = makeLabelArray(env, labels, count);
1819 
1820     // Create an array determining whether each item is enabled.
1821     jbooleanArray enabledArray = env->NewBooleanArray(enabledCount);
1822     checkException(env);
1823     jboolean* ptrArray = env->GetBooleanArrayElements(enabledArray, 0);
1824     checkException(env);
1825     for (size_t i = 0; i < enabledCount; i++) {
1826         ptrArray[i] = enabled[i];
1827     }
1828     env->ReleaseBooleanArrayElements(enabledArray, ptrArray, 0);
1829     checkException(env);
1830 
1831     if (multiple) {
1832         // Pass up an array representing which items are selected.
1833         jintArray selectedArray = env->NewIntArray(selectedCountOrSelection);
1834         checkException(env);
1835         jint* selArray = env->GetIntArrayElements(selectedArray, 0);
1836         checkException(env);
1837         for (size_t i = 0; i < selectedCountOrSelection; i++) {
1838             selArray[i] = selected[i];
1839         }
1840         env->ReleaseIntArrayElements(selectedArray, selArray, 0);
1841 
1842         env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_requestListBox, labelArray, enabledArray, selectedArray);
1843         env->DeleteLocalRef(selectedArray);
1844     } else {
1845         // Pass up the single selection.
1846         env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_requestSingleListBox, labelArray, enabledArray, selectedCountOrSelection);
1847     }
1848 
1849     env->DeleteLocalRef(labelArray);
1850     env->DeleteLocalRef(enabledArray);
1851     checkException(env);
1852 
1853     Retain(reply);
1854     m_popupReply = reply;
1855 }
1856 
key(const PlatformKeyboardEvent & event)1857 bool WebViewCore::key(const PlatformKeyboardEvent& event)
1858 {
1859     WebCore::EventHandler* eventHandler = m_mainFrame->eventHandler();
1860     WebCore::Node* focusNode = currentFocus();
1861     if (focusNode)
1862         eventHandler = focusNode->document()->frame()->eventHandler();
1863     DBG_NAV_LOGD("keyCode=%s unichar=%d focusNode=%p",
1864         event.keyIdentifier().utf8().data(), event.unichar(), focusNode);
1865     return eventHandler->keyEvent(event);
1866 }
1867 
1868 // For when the user clicks the trackball
click(WebCore::Frame * frame,WebCore::Node * node)1869 void WebViewCore::click(WebCore::Frame* frame, WebCore::Node* node) {
1870     if (!node) {
1871         WebCore::IntPoint pt = m_mousePos;
1872         pt.move(m_scrollOffsetX, m_scrollOffsetY);
1873         WebCore::HitTestResult hitTestResult = m_mainFrame->eventHandler()->
1874                 hitTestResultAtPoint(pt, false);
1875         node = hitTestResult.innerNode();
1876         frame = node->document()->frame();
1877         DBG_NAV_LOGD("m_mousePos=(%d,%d) m_scrollOffset=(%d,%d) pt=(%d,%d)"
1878             " node=%p", m_mousePos.x(), m_mousePos.y(),
1879             m_scrollOffsetX, m_scrollOffsetY, pt.x(), pt.y(), node);
1880     }
1881     if (node) {
1882         EditorClientAndroid* client
1883                 = static_cast<EditorClientAndroid*>(
1884                 m_mainFrame->editor()->client());
1885         client->setShouldChangeSelectedRange(false);
1886         handleMouseClick(frame, node);
1887         client->setShouldChangeSelectedRange(true);
1888     }
1889 }
1890 
handleTouchEvent(int action,int x,int y)1891 bool WebViewCore::handleTouchEvent(int action, int x, int y)
1892 {
1893     bool preventDefault = false;
1894 
1895 #if ENABLE(TOUCH_EVENTS) // Android
1896     WebCore::TouchEventType type = WebCore::TouchEventCancel;
1897     switch (action) {
1898     case 0: // MotionEvent.ACTION_DOWN
1899         type = WebCore::TouchEventStart;
1900         break;
1901     case 1: // MotionEvent.ACTION_UP
1902         type = WebCore::TouchEventEnd;
1903         break;
1904     case 2: // MotionEvent.ACTION_MOVE
1905         type = WebCore::TouchEventMove;
1906         break;
1907     case 3: // MotionEvent.ACTION_CANCEL
1908         type = WebCore::TouchEventCancel;
1909         break;
1910     }
1911     WebCore::IntPoint pt(x - m_scrollOffsetX, y - m_scrollOffsetY);
1912     WebCore::PlatformTouchEvent te(pt, pt, type);
1913     preventDefault = m_mainFrame->eventHandler()->handleTouchEvent(te);
1914 #endif
1915 
1916     return preventDefault;
1917 }
1918 
touchUp(int touchGeneration,WebCore::Frame * frame,WebCore::Node * node,int x,int y)1919 void WebViewCore::touchUp(int touchGeneration,
1920     WebCore::Frame* frame, WebCore::Node* node, int x, int y)
1921 {
1922     if (m_touchGeneration > touchGeneration) {
1923         DBG_NAV_LOGD("m_touchGeneration=%d > touchGeneration=%d"
1924             " x=%d y=%d", m_touchGeneration, touchGeneration, x, y);
1925         return; // short circuit if a newer touch has been generated
1926     }
1927     moveMouse(frame, x, y);
1928     m_lastGeneration = touchGeneration;
1929     if (frame && CacheBuilder::validNode(m_mainFrame, frame, 0)) {
1930         frame->loader()->resetMultipleFormSubmissionProtection();
1931     }
1932     // If the click is on an unselected textfield/area we do not want to allow
1933     // the click to change the selection, because we will set it ourselves
1934     // elsewhere - beginning for textareas, end for textfields
1935     bool needToIgnoreChangesToSelectedRange = true;
1936     WebCore::Node* focusNode = currentFocus();
1937     if (focusNode) {
1938         WebCore::RenderObject* renderer = focusNode->renderer();
1939         if (renderer && (renderer->isTextField() || renderer->isTextArea())) {
1940             // Now check to see if the click is inside the focused textfield
1941             if (focusNode->getRect().contains(x, y))
1942                 needToIgnoreChangesToSelectedRange = false;
1943         }
1944     }
1945     EditorClientAndroid* client = 0;
1946     if (needToIgnoreChangesToSelectedRange) {
1947         client = static_cast<EditorClientAndroid*>(
1948                 m_mainFrame->editor()->client());
1949         client->setShouldChangeSelectedRange(false);
1950     }
1951     DBG_NAV_LOGD("touchGeneration=%d handleMouseClick frame=%p node=%p"
1952         " x=%d y=%d", touchGeneration, frame, node, x, y);
1953     handleMouseClick(frame, node);
1954     if (needToIgnoreChangesToSelectedRange)
1955         client->setShouldChangeSelectedRange(true);
1956 }
1957 
1958 // Common code for both clicking with the trackball and touchUp
handleMouseClick(WebCore::Frame * framePtr,WebCore::Node * nodePtr)1959 bool WebViewCore::handleMouseClick(WebCore::Frame* framePtr, WebCore::Node* nodePtr)
1960 {
1961     bool valid = framePtr == NULL
1962             || CacheBuilder::validNode(m_mainFrame, framePtr, nodePtr);
1963     WebFrame* webFrame = WebFrame::getWebFrame(m_mainFrame);
1964     if (valid && nodePtr) {
1965     // Need to special case area tags because an image map could have an area element in the middle
1966     // so when attempting to get the default, the point chosen would be follow the wrong link.
1967         if (nodePtr->hasTagName(WebCore::HTMLNames::areaTag)) {
1968             webFrame->setUserInitiatedClick(true);
1969             nodePtr->dispatchSimulatedClick(0, true, true);
1970             webFrame->setUserInitiatedClick(false);
1971             DBG_NAV_LOG("area");
1972             return true;
1973         }
1974         WebCore::RenderObject* renderer = nodePtr->renderer();
1975         if (renderer && (renderer->isMenuList() || renderer->isListBox())) {
1976             WebCore::HTMLSelectElement* select = static_cast<WebCore::HTMLSelectElement*>(nodePtr);
1977             const WTF::Vector<WebCore::Element*>& listItems = select->listItems();
1978             SkTDArray<const uint16_t*> names;
1979             SkTDArray<int> enabledArray;
1980             SkTDArray<int> selectedArray;
1981             int size = listItems.size();
1982             bool multiple = select->multiple();
1983             for (int i = 0; i < size; i++) {
1984                 if (listItems[i]->hasTagName(WebCore::HTMLNames::optionTag)) {
1985                     WebCore::HTMLOptionElement* option = static_cast<WebCore::HTMLOptionElement*>(listItems[i]);
1986                     *names.append() = stringConverter(option->textIndentedToRespectGroupLabel());
1987                     *enabledArray.append() = option->disabled() ? 0 : 1;
1988                     if (multiple && option->selected())
1989                         *selectedArray.append() = i;
1990                 } else if (listItems[i]->hasTagName(WebCore::HTMLNames::optgroupTag)) {
1991                     WebCore::HTMLOptGroupElement* optGroup = static_cast<WebCore::HTMLOptGroupElement*>(listItems[i]);
1992                     *names.append() = stringConverter(optGroup->groupLabelText());
1993                     *enabledArray.append() = 0;
1994                 }
1995             }
1996             WebCoreReply* reply = new ListBoxReply(select, select->document()->frame(), this);
1997             // Use a pointer to HTMLSelectElement's superclass, where
1998             // optionToListIndex is public.
1999             SelectElement* selectElement = select;
2000             listBoxRequest(reply, names.begin(), size, enabledArray.begin(), enabledArray.count(),
2001                     multiple, selectedArray.begin(), multiple ? selectedArray.count() :
2002                     selectElement->optionToListIndex(select->selectedIndex()));
2003             DBG_NAV_LOG("menu list");
2004             return true;
2005         }
2006     }
2007     if (!valid || !framePtr)
2008         framePtr = m_mainFrame;
2009     webFrame->setUserInitiatedClick(true);
2010     WebCore::PlatformMouseEvent mouseDown(m_mousePos, m_mousePos, WebCore::LeftButton,
2011             WebCore::MouseEventPressed, 1, false, false, false, false,
2012             WTF::currentTime());
2013     // ignore the return from as it will return true if the hit point can trigger selection change
2014     framePtr->eventHandler()->handleMousePressEvent(mouseDown);
2015     WebCore::PlatformMouseEvent mouseUp(m_mousePos, m_mousePos, WebCore::LeftButton,
2016             WebCore::MouseEventReleased, 1, false, false, false, false,
2017             WTF::currentTime());
2018     bool handled = framePtr->eventHandler()->handleMouseReleaseEvent(mouseUp);
2019     webFrame->setUserInitiatedClick(false);
2020 
2021     // If the user clicked on a textfield, make the focusController active
2022     // so we show the blinking cursor.
2023     WebCore::Node* focusNode = currentFocus();
2024     DBG_NAV_LOGD("m_mousePos={%d,%d} focusNode=%p handled=%s", m_mousePos.x(),
2025         m_mousePos.y(), focusNode, handled ? "true" : "false");
2026     if (focusNode) {
2027         WebCore::RenderObject* renderer = focusNode->renderer();
2028         if (renderer && (renderer->isTextField() || renderer->isTextArea()))
2029             setFocusControllerActive(true);
2030     }
2031     return handled;
2032 }
2033 
popupReply(int index)2034 void WebViewCore::popupReply(int index)
2035 {
2036     if (m_popupReply) {
2037         m_popupReply->replyInt(index);
2038         Release(m_popupReply);
2039         m_popupReply = 0;
2040     }
2041 }
2042 
popupReply(const int * array,int count)2043 void WebViewCore::popupReply(const int* array, int count)
2044 {
2045     if (m_popupReply) {
2046         m_popupReply->replyIntArray(array, count);
2047         Release(m_popupReply);
2048         m_popupReply = NULL;
2049     }
2050 }
2051 
addMessageToConsole(const WebCore::String & message,unsigned int lineNumber,const WebCore::String & sourceID)2052 void WebViewCore::addMessageToConsole(const WebCore::String& message, unsigned int lineNumber, const WebCore::String& sourceID) {
2053     JNIEnv* env = JSC::Bindings::getJNIEnv();
2054     jstring jMessageStr = env->NewString((unsigned short *)message.characters(), message.length());
2055     jstring jSourceIDStr = env->NewString((unsigned short *)sourceID.characters(), sourceID.length());
2056     env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_addMessageToConsole, jMessageStr, lineNumber, jSourceIDStr);
2057     env->DeleteLocalRef(jMessageStr);
2058     env->DeleteLocalRef(jSourceIDStr);
2059     checkException(env);
2060 }
2061 
jsAlert(const WebCore::String & url,const WebCore::String & text)2062 void WebViewCore::jsAlert(const WebCore::String& url, const WebCore::String& text)
2063 {
2064     JNIEnv* env = JSC::Bindings::getJNIEnv();
2065     jstring jInputStr = env->NewString((unsigned short *)text.characters(), text.length());
2066     jstring jUrlStr = env->NewString((unsigned short *)url.characters(), url.length());
2067     env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsAlert, jUrlStr, jInputStr);
2068     env->DeleteLocalRef(jInputStr);
2069     env->DeleteLocalRef(jUrlStr);
2070     checkException(env);
2071 }
2072 
exceededDatabaseQuota(const WebCore::String & url,const WebCore::String & databaseIdentifier,const unsigned long long currentQuota,unsigned long long estimatedSize)2073 void WebViewCore::exceededDatabaseQuota(const WebCore::String& url, const WebCore::String& databaseIdentifier, const unsigned long long currentQuota, unsigned long long estimatedSize)
2074 {
2075 #if ENABLE(DATABASE)
2076     JNIEnv* env = JSC::Bindings::getJNIEnv();
2077     jstring jDatabaseIdentifierStr = env->NewString((unsigned short *)databaseIdentifier.characters(), databaseIdentifier.length());
2078     jstring jUrlStr = env->NewString((unsigned short *)url.characters(), url.length());
2079     env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_exceededDatabaseQuota, jUrlStr, jDatabaseIdentifierStr, currentQuota, estimatedSize);
2080     env->DeleteLocalRef(jDatabaseIdentifierStr);
2081     env->DeleteLocalRef(jUrlStr);
2082     checkException(env);
2083 #endif
2084 }
2085 
reachedMaxAppCacheSize(const unsigned long long spaceNeeded)2086 void WebViewCore::reachedMaxAppCacheSize(const unsigned long long spaceNeeded)
2087 {
2088 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
2089     JNIEnv* env = JSC::Bindings::getJNIEnv();
2090     env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_reachedMaxAppCacheSize, spaceNeeded);
2091     checkException(env);
2092 #endif
2093 }
2094 
populateVisitedLinks(WebCore::PageGroup * group)2095 void WebViewCore::populateVisitedLinks(WebCore::PageGroup* group)
2096 {
2097     m_groupForVisitedLinks = group;
2098     JNIEnv* env = JSC::Bindings::getJNIEnv();
2099     env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_populateVisitedLinks);
2100     checkException(env);
2101 }
2102 
geolocationPermissionsShowPrompt(const WebCore::String & origin)2103 void WebViewCore::geolocationPermissionsShowPrompt(const WebCore::String& origin)
2104 {
2105     JNIEnv* env = JSC::Bindings::getJNIEnv();
2106     jstring originString = env->NewString((unsigned short *)origin.characters(), origin.length());
2107     env->CallVoidMethod(m_javaGlue->object(env).get(),
2108                         m_javaGlue->m_geolocationPermissionsShowPrompt,
2109                         originString);
2110     env->DeleteLocalRef(originString);
2111     checkException(env);
2112 }
2113 
geolocationPermissionsHidePrompt()2114 void WebViewCore::geolocationPermissionsHidePrompt()
2115 {
2116     JNIEnv* env = JSC::Bindings::getJNIEnv();
2117     env->CallVoidMethod(m_javaGlue->object(env).get(),
2118                         m_javaGlue->m_geolocationPermissionsHidePrompt);
2119     checkException(env);
2120 }
2121 
jsConfirm(const WebCore::String & url,const WebCore::String & text)2122 bool WebViewCore::jsConfirm(const WebCore::String& url, const WebCore::String& text)
2123 {
2124     JNIEnv* env = JSC::Bindings::getJNIEnv();
2125     jstring jInputStr = env->NewString((unsigned short *)text.characters(), text.length());
2126     jstring jUrlStr = env->NewString((unsigned short *)url.characters(), url.length());
2127     jboolean result = env->CallBooleanMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsConfirm, jUrlStr, jInputStr);
2128     env->DeleteLocalRef(jInputStr);
2129     env->DeleteLocalRef(jUrlStr);
2130     checkException(env);
2131     return result;
2132 }
2133 
jsPrompt(const WebCore::String & url,const WebCore::String & text,const WebCore::String & defaultValue,WebCore::String & result)2134 bool WebViewCore::jsPrompt(const WebCore::String& url, const WebCore::String& text, const WebCore::String& defaultValue, WebCore::String& result)
2135 {
2136     JNIEnv* env = JSC::Bindings::getJNIEnv();
2137     jstring jInputStr = env->NewString((unsigned short *)text.characters(), text.length());
2138     jstring jDefaultStr = env->NewString((unsigned short *)defaultValue.characters(), defaultValue.length());
2139     jstring jUrlStr = env->NewString((unsigned short *)url.characters(), url.length());
2140     jstring returnVal = (jstring) env->CallObjectMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsPrompt, jUrlStr, jInputStr, jDefaultStr);
2141     // If returnVal is null, it means that the user cancelled the dialog.
2142     if (!returnVal)
2143         return false;
2144 
2145     result = to_string(env, returnVal);
2146     env->DeleteLocalRef(jInputStr);
2147     env->DeleteLocalRef(jDefaultStr);
2148     env->DeleteLocalRef(jUrlStr);
2149     checkException(env);
2150     return true;
2151 }
2152 
jsUnload(const WebCore::String & url,const WebCore::String & message)2153 bool WebViewCore::jsUnload(const WebCore::String& url, const WebCore::String& message)
2154 {
2155     JNIEnv* env = JSC::Bindings::getJNIEnv();
2156     jstring jInputStr = env->NewString((unsigned short *)message.characters(), message.length());
2157     jstring jUrlStr = env->NewString((unsigned short *)url.characters(), url.length());
2158     jboolean result = env->CallBooleanMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsUnload, jUrlStr, jInputStr);
2159     env->DeleteLocalRef(jInputStr);
2160     env->DeleteLocalRef(jUrlStr);
2161     checkException(env);
2162     return result;
2163 }
2164 
jsInterrupt()2165 bool WebViewCore::jsInterrupt()
2166 {
2167     JNIEnv* env = JSC::Bindings::getJNIEnv();
2168     jboolean result = env->CallBooleanMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsInterrupt);
2169     checkException(env);
2170     return result;
2171 }
2172 
2173 AutoJObject
getJavaObject()2174 WebViewCore::getJavaObject()
2175 {
2176     return getRealObject(JSC::Bindings::getJNIEnv(), m_javaGlue->m_obj);
2177 }
2178 
2179 jobject
getWebViewJavaObject()2180 WebViewCore::getWebViewJavaObject()
2181 {
2182     JNIEnv* env = JSC::Bindings::getJNIEnv();
2183     return env->GetObjectField(m_javaGlue->object(env).get(), gWebViewCoreFields.m_webView);
2184 }
2185 
updateTextSelection()2186 void WebViewCore::updateTextSelection() {
2187     WebCore::Node* focusNode = currentFocus();
2188     if (!focusNode)
2189         return;
2190     RenderObject* renderer = focusNode->renderer();
2191     if (!renderer || (!renderer->isTextArea() && !renderer->isTextField()))
2192         return;
2193     RenderTextControl* rtc = static_cast<RenderTextControl*>(renderer);
2194     JNIEnv* env = JSC::Bindings::getJNIEnv();
2195     env->CallVoidMethod(m_javaGlue->object(env).get(),
2196             m_javaGlue->m_updateTextSelection, reinterpret_cast<int>(focusNode),
2197             rtc->selectionStart(), rtc->selectionEnd(), m_textGeneration);
2198     checkException(env);
2199 }
2200 
updateTextfield(WebCore::Node * ptr,bool changeToPassword,const WebCore::String & text)2201 void WebViewCore::updateTextfield(WebCore::Node* ptr, bool changeToPassword,
2202         const WebCore::String& text)
2203 {
2204     if (m_blockTextfieldUpdates)
2205         return;
2206     JNIEnv* env = JSC::Bindings::getJNIEnv();
2207     if (changeToPassword) {
2208         env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_updateTextfield,
2209                 (int) ptr, true, 0, m_textGeneration);
2210         checkException(env);
2211         return;
2212     }
2213     int length = text.length();
2214     jstring string = env->NewString((unsigned short *) text.characters(), length);
2215     env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_updateTextfield,
2216             (int) ptr, false, string, m_textGeneration);
2217     env->DeleteLocalRef(string);
2218     checkException(env);
2219 }
2220 
clearTextEntry()2221 void WebViewCore::clearTextEntry()
2222 {
2223     JNIEnv* env = JSC::Bindings::getJNIEnv();
2224     env->CallVoidMethod(m_javaGlue->object(env).get(),
2225         m_javaGlue->m_clearTextEntry);
2226 }
2227 
setBackgroundColor(SkColor c)2228 void WebViewCore::setBackgroundColor(SkColor c)
2229 {
2230     WebCore::FrameView* view = m_mainFrame->view();
2231     if (!view)
2232         return;
2233 
2234     // need (int) cast to find the right constructor
2235     WebCore::Color bcolor((int)SkColorGetR(c), (int)SkColorGetG(c),
2236                           (int)SkColorGetB(c), (int)SkColorGetA(c));
2237     view->setBaseBackgroundColor(bcolor);
2238 }
2239 
startFullScreenPluginActivity(const char * libName,const char * className,NPP npp)2240 void WebViewCore::startFullScreenPluginActivity(const char* libName,
2241                                                 const char* className, NPP npp)
2242 {
2243     JNIEnv* env = JSC::Bindings::getJNIEnv();
2244 
2245     jstring libString = env->NewStringUTF(libName);
2246     jstring classString = env->NewStringUTF(className);
2247     env->CallVoidMethod(m_javaGlue->object(env).get(),
2248                         m_javaGlue->m_startFullScreenPluginActivity,
2249                         libString, classString, (int) npp);
2250     checkException(env);
2251 }
2252 
createSurface(const char * libName,const char * className,NPP npp,int x,int y,int width,int height)2253 jobject WebViewCore::createSurface(const char* libName, const char* className,
2254                                    NPP npp, int x, int y, int width, int height)
2255 {
2256     JNIEnv* env = JSC::Bindings::getJNIEnv();
2257 
2258     jstring libString = env->NewStringUTF(libName);
2259     jstring classString = env->NewStringUTF(className);
2260     jobject result = env->CallObjectMethod(m_javaGlue->object(env).get(),
2261                                            m_javaGlue->m_createSurface, libString,
2262                                            classString,(int) npp, x, y, width, height);
2263     checkException(env);
2264     return result;
2265 
2266 }
2267 
destroySurface(jobject childView)2268 void WebViewCore::destroySurface(jobject childView)
2269 {
2270     JNIEnv* env = JSC::Bindings::getJNIEnv();
2271     env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_destroySurface, childView);
2272     checkException(env);
2273 }
2274 
2275 //----------------------------------------------------------------------
2276 // Native JNI methods
2277 //----------------------------------------------------------------------
WebCoreStringToJString(JNIEnv * env,WebCore::String string)2278 static jstring WebCoreStringToJString(JNIEnv *env, WebCore::String string)
2279 {
2280     int length = string.length();
2281     if (!length)
2282         return 0;
2283     jstring ret = env->NewString((jchar *)string.characters(), length);
2284     env->DeleteLocalRef(ret);
2285     return ret;
2286 }
2287 
UpdateFrameCacheIfLoading(JNIEnv * env,jobject obj)2288 static void UpdateFrameCacheIfLoading(JNIEnv *env, jobject obj)
2289 {
2290     GET_NATIVE_VIEW(env, obj)->updateFrameCacheIfLoading();
2291 }
2292 
SetSize(JNIEnv * env,jobject obj,jint width,jint height,jint screenWidth,jfloat scale,jint realScreenWidth,jint screenHeight,jboolean ignoreHeight)2293 static void SetSize(JNIEnv *env, jobject obj, jint width, jint height,
2294         jint screenWidth, jfloat scale, jint realScreenWidth, jint screenHeight,
2295         jboolean ignoreHeight)
2296 {
2297 #ifdef ANDROID_INSTRUMENT
2298     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2299 #endif
2300     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2301     LOGV("webviewcore::nativeSetSize(%u %u)\n viewImpl: %p", (unsigned)width, (unsigned)height, viewImpl);
2302     LOG_ASSERT(viewImpl, "viewImpl not set in nativeSetSize");
2303     viewImpl->setSizeScreenWidthAndScale(width, height, screenWidth, scale,
2304         realScreenWidth, screenHeight, ignoreHeight);
2305 }
2306 
SetScrollOffset(JNIEnv * env,jobject obj,jint gen,jint x,jint y)2307 static void SetScrollOffset(JNIEnv *env, jobject obj, jint gen, jint x, jint y)
2308 {
2309 #ifdef ANDROID_INSTRUMENT
2310     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2311 #endif
2312     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2313     LOG_ASSERT(viewImpl, "need viewImpl");
2314 
2315     viewImpl->setScrollOffset(gen, x, y);
2316 }
2317 
SetGlobalBounds(JNIEnv * env,jobject obj,jint x,jint y,jint h,jint v)2318 static void SetGlobalBounds(JNIEnv *env, jobject obj, jint x, jint y, jint h,
2319                             jint v)
2320 {
2321 #ifdef ANDROID_INSTRUMENT
2322     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2323 #endif
2324     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2325     LOG_ASSERT(viewImpl, "need viewImpl");
2326 
2327     viewImpl->setGlobalBounds(x, y, h, v);
2328 }
2329 
Key(JNIEnv * env,jobject obj,jint keyCode,jint unichar,jint repeatCount,jboolean isShift,jboolean isAlt,jboolean isSym,jboolean isDown)2330 static jboolean Key(JNIEnv *env, jobject obj, jint keyCode, jint unichar,
2331         jint repeatCount, jboolean isShift, jboolean isAlt, jboolean isSym,
2332         jboolean isDown)
2333 {
2334 #ifdef ANDROID_INSTRUMENT
2335     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2336 #endif
2337     return GET_NATIVE_VIEW(env, obj)->key(PlatformKeyboardEvent(keyCode,
2338         unichar, repeatCount, isDown, isShift, isAlt, isSym));
2339 }
2340 
Click(JNIEnv * env,jobject obj,int framePtr,int nodePtr)2341 static void Click(JNIEnv *env, jobject obj, int framePtr, int nodePtr)
2342 {
2343 #ifdef ANDROID_INSTRUMENT
2344     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2345 #endif
2346     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2347     LOG_ASSERT(viewImpl, "viewImpl not set in Click");
2348 
2349     viewImpl->click(reinterpret_cast<WebCore::Frame*>(framePtr),
2350         reinterpret_cast<WebCore::Node*>(nodePtr));
2351 }
2352 
DeleteSelection(JNIEnv * env,jobject obj,jint start,jint end,jint textGeneration)2353 static void DeleteSelection(JNIEnv *env, jobject obj, jint start, jint end,
2354         jint textGeneration)
2355 {
2356 #ifdef ANDROID_INSTRUMENT
2357     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2358 #endif
2359     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2360     viewImpl->deleteSelection(start, end, textGeneration);
2361 }
2362 
SetSelection(JNIEnv * env,jobject obj,jint start,jint end)2363 static void SetSelection(JNIEnv *env, jobject obj, jint start, jint end)
2364 {
2365 #ifdef ANDROID_INSTRUMENT
2366     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2367 #endif
2368     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2369     viewImpl->setSelection(start, end);
2370 }
2371 
2372 
ReplaceTextfieldText(JNIEnv * env,jobject obj,jint oldStart,jint oldEnd,jstring replace,jint start,jint end,jint textGeneration)2373 static void ReplaceTextfieldText(JNIEnv *env, jobject obj,
2374     jint oldStart, jint oldEnd, jstring replace, jint start, jint end,
2375     jint textGeneration)
2376 {
2377 #ifdef ANDROID_INSTRUMENT
2378     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2379 #endif
2380     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2381     WebCore::String webcoreString = to_string(env, replace);
2382     viewImpl->replaceTextfieldText(oldStart,
2383             oldEnd, webcoreString, start, end, textGeneration);
2384 }
2385 
PassToJs(JNIEnv * env,jobject obj,jint generation,jstring currentText,jint keyCode,jint keyValue,jboolean down,jboolean cap,jboolean fn,jboolean sym)2386 static void PassToJs(JNIEnv *env, jobject obj,
2387     jint generation, jstring currentText, jint keyCode,
2388     jint keyValue, jboolean down, jboolean cap, jboolean fn, jboolean sym)
2389 {
2390 #ifdef ANDROID_INSTRUMENT
2391     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2392 #endif
2393     WebCore::String current = to_string(env, currentText);
2394     GET_NATIVE_VIEW(env, obj)->passToJs(generation, current,
2395         PlatformKeyboardEvent(keyCode, keyValue, 0, down, cap, fn, sym));
2396 }
2397 
ScrollFocusedTextInput(JNIEnv * env,jobject obj,jfloat xPercent,jint y)2398 static void ScrollFocusedTextInput(JNIEnv *env, jobject obj, jfloat xPercent,
2399     jint y)
2400 {
2401 #ifdef ANDROID_INSTRUMENT
2402     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2403 #endif
2404     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2405     viewImpl->scrollFocusedTextInput(xPercent, y);
2406 }
2407 
SetFocusControllerActive(JNIEnv * env,jobject obj,jboolean active)2408 static void SetFocusControllerActive(JNIEnv *env, jobject obj, jboolean active)
2409 {
2410 #ifdef ANDROID_INSTRUMENT
2411     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2412 #endif
2413     LOGV("webviewcore::nativeSetFocusControllerActive()\n");
2414     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2415     LOG_ASSERT(viewImpl, "viewImpl not set in nativeSetFocusControllerActive");
2416     viewImpl->setFocusControllerActive(active);
2417 }
2418 
SaveDocumentState(JNIEnv * env,jobject obj,jint frame)2419 static void SaveDocumentState(JNIEnv *env, jobject obj, jint frame)
2420 {
2421 #ifdef ANDROID_INSTRUMENT
2422     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2423 #endif
2424     LOGV("webviewcore::nativeSaveDocumentState()\n");
2425     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2426     LOG_ASSERT(viewImpl, "viewImpl not set in nativeSaveDocumentState");
2427     viewImpl->saveDocumentState((WebCore::Frame*) frame);
2428 }
2429 
addVisitedLink(const UChar * string,int length)2430 void WebViewCore::addVisitedLink(const UChar* string, int length)
2431 {
2432     if (m_groupForVisitedLinks)
2433         m_groupForVisitedLinks->addVisitedLink(string, length);
2434 }
2435 
RecordContent(JNIEnv * env,jobject obj,jobject region,jobject pt)2436 static bool RecordContent(JNIEnv *env, jobject obj, jobject region, jobject pt)
2437 {
2438 #ifdef ANDROID_INSTRUMENT
2439     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2440 #endif
2441     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2442     SkRegion* nativeRegion = GraphicsJNI::getNativeRegion(env, region);
2443     SkIPoint nativePt;
2444     bool result = viewImpl->recordContent(nativeRegion, &nativePt);
2445     GraphicsJNI::ipoint_to_jpoint(nativePt, env, pt);
2446     return result;
2447 }
2448 
SplitContent(JNIEnv * env,jobject obj)2449 static void SplitContent(JNIEnv *env, jobject obj)
2450 {
2451 #ifdef ANDROID_INSTRUMENT
2452     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2453 #endif
2454     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2455     viewImpl->splitContent();
2456 }
2457 
SendListBoxChoice(JNIEnv * env,jobject obj,jint choice)2458 static void SendListBoxChoice(JNIEnv* env, jobject obj, jint choice)
2459 {
2460 #ifdef ANDROID_INSTRUMENT
2461     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2462 #endif
2463     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2464     LOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoice");
2465     viewImpl->popupReply(choice);
2466 }
2467 
2468 // Set aside a predetermined amount of space in which to place the listbox
2469 // choices, to avoid unnecessary allocations.
2470 // The size here is arbitrary.  We want the size to be at least as great as the
2471 // number of items in the average multiple-select listbox.
2472 #define PREPARED_LISTBOX_STORAGE 10
2473 
SendListBoxChoices(JNIEnv * env,jobject obj,jbooleanArray jArray,jint size)2474 static void SendListBoxChoices(JNIEnv* env, jobject obj, jbooleanArray jArray,
2475         jint size)
2476 {
2477 #ifdef ANDROID_INSTRUMENT
2478     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2479 #endif
2480     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2481     LOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoices");
2482     jboolean* ptrArray = env->GetBooleanArrayElements(jArray, 0);
2483     SkAutoSTMalloc<PREPARED_LISTBOX_STORAGE, int> storage(size);
2484     int* array = storage.get();
2485     int count = 0;
2486     for (int i = 0; i < size; i++) {
2487         if (ptrArray[i]) {
2488             array[count++] = i;
2489         }
2490     }
2491     env->ReleaseBooleanArrayElements(jArray, ptrArray, JNI_ABORT);
2492     viewImpl->popupReply(array, count);
2493 }
2494 
FindAddress(JNIEnv * env,jobject obj,jstring addr,jboolean caseInsensitive)2495 static jstring FindAddress(JNIEnv *env, jobject obj, jstring addr,
2496     jboolean caseInsensitive)
2497 {
2498 #ifdef ANDROID_INSTRUMENT
2499     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2500 #endif
2501     if (!addr)
2502         return 0;
2503     int length = env->GetStringLength(addr);
2504     if (!length)
2505         return 0;
2506     const jchar* addrChars = env->GetStringChars(addr, 0);
2507     int start, end;
2508     bool success = CacheBuilder::FindAddress(addrChars, length,
2509         &start, &end, caseInsensitive) == CacheBuilder::FOUND_COMPLETE;
2510     jstring ret = 0;
2511     if (success) {
2512         ret = env->NewString((jchar*) addrChars + start, end - start);
2513         env->DeleteLocalRef(ret);
2514     }
2515     env->ReleaseStringChars(addr, addrChars);
2516     return ret;
2517 }
2518 
HandleTouchEvent(JNIEnv * env,jobject obj,jint action,jint x,jint y)2519 static jboolean HandleTouchEvent(JNIEnv *env, jobject obj, jint action, jint x, jint y)
2520 {
2521 #ifdef ANDROID_INSTRUMENT
2522     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2523 #endif
2524     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2525     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
2526     return viewImpl->handleTouchEvent(action, x, y);
2527 }
2528 
TouchUp(JNIEnv * env,jobject obj,jint touchGeneration,jint frame,jint node,jint x,jint y)2529 static void TouchUp(JNIEnv *env, jobject obj, jint touchGeneration,
2530         jint frame, jint node, jint x, jint y)
2531 {
2532 #ifdef ANDROID_INSTRUMENT
2533     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2534 #endif
2535     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2536     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
2537     viewImpl->touchUp(touchGeneration,
2538         (WebCore::Frame*) frame, (WebCore::Node*) node, x, y);
2539 }
2540 
RetrieveHref(JNIEnv * env,jobject obj,jint frame,jint node)2541 static jstring RetrieveHref(JNIEnv *env, jobject obj, jint frame,
2542         jint node)
2543 {
2544 #ifdef ANDROID_INSTRUMENT
2545     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2546 #endif
2547     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2548     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
2549     WebCore::String result = viewImpl->retrieveHref((WebCore::Frame*) frame,
2550             (WebCore::Node*) node);
2551     if (!result.isEmpty())
2552         return WebCoreStringToJString(env, result);
2553     return 0;
2554 }
2555 
MoveMouse(JNIEnv * env,jobject obj,jint frame,jint x,jint y)2556 static void MoveMouse(JNIEnv *env, jobject obj, jint frame,
2557         jint x, jint y)
2558 {
2559 #ifdef ANDROID_INSTRUMENT
2560     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2561 #endif
2562     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2563     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
2564     viewImpl->moveMouse((WebCore::Frame*) frame, x, y);
2565 }
2566 
MoveMouseIfLatest(JNIEnv * env,jobject obj,jint moveGeneration,jint frame,jint x,jint y)2567 static void MoveMouseIfLatest(JNIEnv *env, jobject obj, jint moveGeneration,
2568         jint frame, jint x, jint y)
2569 {
2570 #ifdef ANDROID_INSTRUMENT
2571     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2572 #endif
2573     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2574     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
2575     viewImpl->moveMouseIfLatest(moveGeneration,
2576         (WebCore::Frame*) frame, x, y);
2577 }
2578 
UpdateFrameCache(JNIEnv * env,jobject obj)2579 static void UpdateFrameCache(JNIEnv *env, jobject obj)
2580 {
2581 #ifdef ANDROID_INSTRUMENT
2582     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2583 #endif
2584     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2585     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
2586     viewImpl->updateFrameCache();
2587 }
2588 
GetContentMinPrefWidth(JNIEnv * env,jobject obj)2589 static jint GetContentMinPrefWidth(JNIEnv *env, jobject obj)
2590 {
2591 #ifdef ANDROID_INSTRUMENT
2592     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2593 #endif
2594     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2595     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
2596 
2597     WebCore::Frame* frame = viewImpl->mainFrame();
2598     if (frame) {
2599         WebCore::Document* document = frame->document();
2600         if (document) {
2601             WebCore::RenderObject* renderer = document->renderer();
2602             if (renderer && renderer->isRenderView()) {
2603                 return renderer->minPrefWidth();
2604             }
2605         }
2606     }
2607     return 0;
2608 }
2609 
SetViewportSettingsFromNative(JNIEnv * env,jobject obj)2610 static void SetViewportSettingsFromNative(JNIEnv *env, jobject obj)
2611 {
2612 #ifdef ANDROID_INSTRUMENT
2613     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2614 #endif
2615     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2616     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
2617 
2618     WebCore::Settings* s = viewImpl->mainFrame()->page()->settings();
2619     if (!s)
2620         return;
2621 
2622 #ifdef ANDROID_META_SUPPORT
2623     env->SetIntField(obj, gWebViewCoreFields.m_viewportWidth, s->viewportWidth());
2624     env->SetIntField(obj, gWebViewCoreFields.m_viewportHeight, s->viewportHeight());
2625     env->SetIntField(obj, gWebViewCoreFields.m_viewportInitialScale, s->viewportInitialScale());
2626     env->SetIntField(obj, gWebViewCoreFields.m_viewportMinimumScale, s->viewportMinimumScale());
2627     env->SetIntField(obj, gWebViewCoreFields.m_viewportMaximumScale, s->viewportMaximumScale());
2628     env->SetBooleanField(obj, gWebViewCoreFields.m_viewportUserScalable, s->viewportUserScalable());
2629     env->SetIntField(obj, gWebViewCoreFields.m_viewportDensityDpi, s->viewportTargetDensityDpi());
2630 #endif
2631 }
2632 
SetBackgroundColor(JNIEnv * env,jobject obj,jint color)2633 static void SetBackgroundColor(JNIEnv *env, jobject obj, jint color)
2634 {
2635 #ifdef ANDROID_INSTRUMENT
2636     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2637 #endif
2638     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2639     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
2640 
2641     viewImpl->setBackgroundColor((SkColor) color);
2642 }
2643 
GetSelection(JNIEnv * env,jobject obj,jobject selRgn)2644 static jstring GetSelection(JNIEnv *env, jobject obj, jobject selRgn)
2645 {
2646 #ifdef ANDROID_INSTRUMENT
2647     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2648 #endif
2649     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2650     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
2651     SkRegion* selectionRegion = GraphicsJNI::getNativeRegion(env, selRgn);
2652     WebCore::String result = viewImpl->getSelection(selectionRegion);
2653     if (!result.isEmpty())
2654         return WebCoreStringToJString(env, result);
2655     return 0;
2656 }
2657 
DumpDomTree(JNIEnv * env,jobject obj,jboolean useFile)2658 static void DumpDomTree(JNIEnv *env, jobject obj, jboolean useFile)
2659 {
2660     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2661     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
2662 
2663     viewImpl->dumpDomTree(useFile);
2664 }
2665 
DumpRenderTree(JNIEnv * env,jobject obj,jboolean useFile)2666 static void DumpRenderTree(JNIEnv *env, jobject obj, jboolean useFile)
2667 {
2668     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2669     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
2670 
2671     viewImpl->dumpRenderTree(useFile);
2672 }
2673 
DumpNavTree(JNIEnv * env,jobject obj)2674 static void DumpNavTree(JNIEnv *env, jobject obj)
2675 {
2676     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2677     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
2678 
2679     viewImpl->dumpNavTree();
2680 }
2681 
SetJsFlags(JNIEnv * env,jobject obj,jstring flags)2682 static void SetJsFlags(JNIEnv *env, jobject obj, jstring flags)
2683 {
2684 #if USE(V8)
2685     WebCore::String flagsString = to_string(env, flags);
2686     WebCore::CString utf8String = flagsString.utf8();
2687     WebCore::ScriptController::setFlags(utf8String.data(), utf8String.length());
2688 #endif
2689 }
2690 
2691 
2692 // Called from the Java side to set a new quota for the origin or new appcache
2693 // max size in response to a notification that the original quota was exceeded or
2694 // that the appcache has reached its maximum size.
SetNewStorageLimit(JNIEnv * env,jobject obj,jlong quota)2695 static void SetNewStorageLimit(JNIEnv* env, jobject obj, jlong quota) {
2696 #if ENABLE(DATABASE) || ENABLE(OFFLINE_WEB_APPLICATIONS)
2697     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2698     Frame* frame = viewImpl->mainFrame();
2699 
2700     // The main thread is blocked awaiting this response, so now we can wake it
2701     // up.
2702     ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client());
2703     chromeC->wakeUpMainThreadWithNewQuota(quota);
2704 #endif
2705 }
2706 
2707 // Called from Java to provide a Geolocation permission state for the specified origin.
GeolocationPermissionsProvide(JNIEnv * env,jobject obj,jstring origin,jboolean allow,jboolean remember)2708 static void GeolocationPermissionsProvide(JNIEnv* env, jobject obj, jstring origin, jboolean allow, jboolean remember) {
2709     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2710     Frame* frame = viewImpl->mainFrame();
2711 
2712     ChromeClientAndroid* chromeClient = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client());
2713     chromeClient->provideGeolocationPermissions(to_string(env, origin), allow, remember);
2714 }
2715 
RegisterURLSchemeAsLocal(JNIEnv * env,jobject obj,jstring scheme)2716 static void RegisterURLSchemeAsLocal(JNIEnv* env, jobject obj, jstring scheme) {
2717 #ifdef ANDROID_INSTRUMENT
2718     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2719 #endif
2720     WebCore::SecurityOrigin::registerURLSchemeAsLocal(to_string(env, scheme));
2721 }
2722 
ClearContent(JNIEnv * env,jobject obj)2723 static void ClearContent(JNIEnv *env, jobject obj)
2724 {
2725 #ifdef ANDROID_INSTRUMENT
2726     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2727 #endif
2728     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2729     viewImpl->clearContent();
2730 }
2731 
CopyContentToPicture(JNIEnv * env,jobject obj,jobject pict)2732 static void CopyContentToPicture(JNIEnv *env, jobject obj, jobject pict)
2733 {
2734 #ifdef ANDROID_INSTRUMENT
2735     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2736 #endif
2737     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2738     if (!viewImpl)
2739         return;
2740     SkPicture* picture = GraphicsJNI::getNativePicture(env, pict);
2741     viewImpl->copyContentToPicture(picture);
2742 }
2743 
DrawContent(JNIEnv * env,jobject obj,jobject canv,jint color)2744 static bool DrawContent(JNIEnv *env, jobject obj, jobject canv, jint color)
2745 {
2746     // Note: this is called from UI thread, don't count it for WebViewCoreTimeCounter
2747     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2748     SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv);
2749     return viewImpl->drawContent(canvas, color);
2750 }
2751 
PictureReady(JNIEnv * env,jobject obj)2752 static bool PictureReady(JNIEnv* env, jobject obj)
2753 {
2754     return GET_NATIVE_VIEW(env, obj)->pictureReady();
2755 }
2756 
UpdatePluginState(JNIEnv * env,jobject obj,jint framePtr,jint nodePtr,jint state)2757 static void UpdatePluginState(JNIEnv* env, jobject obj, jint framePtr, jint nodePtr, jint state)
2758 {
2759 #ifdef ANDROID_INSTRUMENT
2760     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
2761 #endif
2762     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2763     LOG_ASSERT(viewImpl, "viewImpl not set in nativeUpdatePluginState");
2764     viewImpl->updatePluginState((WebCore::Frame*) framePtr, (WebCore::Node*) nodePtr,
2765                                 (PluginState) state);
2766 }
2767 
Pause(JNIEnv * env,jobject obj)2768 static void Pause(JNIEnv* env, jobject obj)
2769 {
2770     // This is called for the foreground tab when the browser is put to the
2771     // background (and also for any tab when it is put to the background of the
2772     // browser). The browser can only be killed by the system when it is in the
2773     // background, so saving the Geolocation permission state now ensures that
2774     // is maintained when the browser is killed.
2775     ChromeClient* chromeClient = GET_NATIVE_VIEW(env, obj)->mainFrame()->page()->chrome()->client();
2776     ChromeClientAndroid* chromeClientAndroid = static_cast<ChromeClientAndroid*>(chromeClient);
2777     chromeClientAndroid->storeGeolocationPermissions();
2778 
2779     Frame* mainFrame = GET_NATIVE_VIEW(env, obj)->mainFrame();
2780     for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) {
2781         Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation();
2782         if (geolocation)
2783             geolocation->suspend();
2784     }
2785 
2786     ANPEvent event;
2787     SkANP::InitEvent(&event, kLifecycle_ANPEventType);
2788     event.data.lifecycle.action = kPause_ANPLifecycleAction;
2789     GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event);
2790 }
2791 
Resume(JNIEnv * env,jobject obj)2792 static void Resume(JNIEnv* env, jobject obj)
2793 {
2794     Frame* mainFrame = GET_NATIVE_VIEW(env, obj)->mainFrame();
2795     for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) {
2796         Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation();
2797         if (geolocation)
2798             geolocation->resume();
2799     }
2800 
2801     ANPEvent event;
2802     SkANP::InitEvent(&event, kLifecycle_ANPEventType);
2803     event.data.lifecycle.action = kResume_ANPLifecycleAction;
2804     GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event);
2805 }
2806 
FreeMemory(JNIEnv * env,jobject obj)2807 static void FreeMemory(JNIEnv* env, jobject obj)
2808 {
2809     ANPEvent event;
2810     SkANP::InitEvent(&event, kLifecycle_ANPEventType);
2811     event.data.lifecycle.action = kFreeMemory_ANPLifecycleAction;
2812     GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event);
2813 }
2814 
ProvideVisitedHistory(JNIEnv * env,jobject obj,jobject hist)2815 static void ProvideVisitedHistory(JNIEnv *env, jobject obj, jobject hist)
2816 {
2817     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2818     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
2819 
2820     jobjectArray array = static_cast<jobjectArray>(hist);
2821 
2822     jsize len = env->GetArrayLength(array);
2823     for (jsize i = 0; i < len; i++) {
2824         jstring item = static_cast<jstring>(env->GetObjectArrayElement(array, i));
2825         const UChar* str = static_cast<const UChar*>(env->GetStringChars(item, NULL));
2826         jsize len = env->GetStringLength(item);
2827         viewImpl->addVisitedLink(str, len);
2828         env->ReleaseStringChars(item, str);
2829         env->DeleteLocalRef(item);
2830     }
2831     env->DeleteLocalRef(array);
2832 }
2833 
2834 // ----------------------------------------------------------------------------
2835 
2836 /*
2837  * JNI registration.
2838  */
2839 static JNINativeMethod gJavaWebViewCoreMethods[] = {
2840     { "nativeClearContent", "()V",
2841         (void*) ClearContent },
2842     { "nativeCopyContentToPicture", "(Landroid/graphics/Picture;)V",
2843         (void*) CopyContentToPicture },
2844     { "nativeDrawContent", "(Landroid/graphics/Canvas;I)Z",
2845         (void*) DrawContent } ,
2846     { "nativeKey", "(IIIZZZZ)Z",
2847         (void*) Key },
2848     { "nativeClick", "(II)V",
2849         (void*) Click },
2850     { "nativePictureReady", "()Z",
2851         (void*) PictureReady } ,
2852     { "nativeSendListBoxChoices", "([ZI)V",
2853         (void*) SendListBoxChoices },
2854     { "nativeSendListBoxChoice", "(I)V",
2855         (void*) SendListBoxChoice },
2856     { "nativeSetSize", "(IIIFIIZ)V",
2857         (void*) SetSize },
2858     { "nativeSetScrollOffset", "(III)V",
2859         (void*) SetScrollOffset },
2860     { "nativeSetGlobalBounds", "(IIII)V",
2861         (void*) SetGlobalBounds },
2862     { "nativeSetSelection", "(II)V",
2863         (void*) SetSelection } ,
2864     { "nativeDeleteSelection", "(III)V",
2865         (void*) DeleteSelection } ,
2866     { "nativeReplaceTextfieldText", "(IILjava/lang/String;III)V",
2867         (void*) ReplaceTextfieldText } ,
2868     { "nativeMoveMouse", "(III)V",
2869         (void*) MoveMouse },
2870     { "nativeMoveMouseIfLatest", "(IIII)V",
2871         (void*) MoveMouseIfLatest },
2872     { "passToJs", "(ILjava/lang/String;IIZZZZ)V",
2873         (void*) PassToJs },
2874     { "nativeScrollFocusedTextInput", "(FI)V",
2875         (void*) ScrollFocusedTextInput },
2876     { "nativeSetFocusControllerActive", "(Z)V",
2877         (void*) SetFocusControllerActive },
2878     { "nativeSaveDocumentState", "(I)V",
2879         (void*) SaveDocumentState },
2880     { "nativeFindAddress", "(Ljava/lang/String;Z)Ljava/lang/String;",
2881         (void*) FindAddress },
2882     { "nativeHandleTouchEvent", "(III)Z",
2883             (void*) HandleTouchEvent },
2884     { "nativeTouchUp", "(IIIII)V",
2885         (void*) TouchUp },
2886     { "nativeRetrieveHref", "(II)Ljava/lang/String;",
2887         (void*) RetrieveHref },
2888     { "nativeUpdateFrameCache", "()V",
2889         (void*) UpdateFrameCache },
2890     { "nativeGetContentMinPrefWidth", "()I",
2891         (void*) GetContentMinPrefWidth },
2892     { "nativeRecordContent", "(Landroid/graphics/Region;Landroid/graphics/Point;)Z",
2893         (void*) RecordContent },
2894     { "setViewportSettingsFromNative", "()V",
2895         (void*) SetViewportSettingsFromNative },
2896     { "nativeSplitContent", "()V",
2897         (void*) SplitContent },
2898     { "nativeSetBackgroundColor", "(I)V",
2899         (void*) SetBackgroundColor },
2900     { "nativeGetSelection", "(Landroid/graphics/Region;)Ljava/lang/String;",
2901         (void*) GetSelection },
2902     { "nativeRegisterURLSchemeAsLocal", "(Ljava/lang/String;)V",
2903         (void*) RegisterURLSchemeAsLocal },
2904     { "nativeDumpDomTree", "(Z)V",
2905         (void*) DumpDomTree },
2906     { "nativeDumpRenderTree", "(Z)V",
2907         (void*) DumpRenderTree },
2908     { "nativeDumpNavTree", "()V",
2909         (void*) DumpNavTree },
2910     { "nativeSetNewStorageLimit", "(J)V",
2911         (void*) SetNewStorageLimit },
2912     { "nativeGeolocationPermissionsProvide", "(Ljava/lang/String;ZZ)V",
2913         (void*) GeolocationPermissionsProvide },
2914     { "nativePause", "()V", (void*) Pause },
2915     { "nativeResume", "()V", (void*) Resume },
2916     { "nativeFreeMemory", "()V", (void*) FreeMemory },
2917     { "nativeSetJsFlags", "(Ljava/lang/String;)V", (void*) SetJsFlags },
2918     { "nativeUpdatePluginState", "(III)V", (void*) UpdatePluginState },
2919     { "nativeUpdateFrameCacheIfLoading", "()V",
2920         (void*) UpdateFrameCacheIfLoading },
2921     { "nativeProvideVisitedHistory", "([Ljava/lang/String;)V",
2922         (void*) ProvideVisitedHistory },
2923 };
2924 
register_webviewcore(JNIEnv * env)2925 int register_webviewcore(JNIEnv* env)
2926 {
2927     jclass widget = env->FindClass("android/webkit/WebViewCore");
2928     LOG_ASSERT(widget,
2929             "Unable to find class android/webkit/WebViewCore");
2930     gWebViewCoreFields.m_nativeClass = env->GetFieldID(widget, "mNativeClass",
2931             "I");
2932     LOG_ASSERT(gWebViewCoreFields.m_nativeClass,
2933             "Unable to find android/webkit/WebViewCore.mNativeClass");
2934     gWebViewCoreFields.m_viewportWidth = env->GetFieldID(widget,
2935             "mViewportWidth", "I");
2936     LOG_ASSERT(gWebViewCoreFields.m_viewportWidth,
2937             "Unable to find android/webkit/WebViewCore.mViewportWidth");
2938     gWebViewCoreFields.m_viewportHeight = env->GetFieldID(widget,
2939             "mViewportHeight", "I");
2940     LOG_ASSERT(gWebViewCoreFields.m_viewportHeight,
2941             "Unable to find android/webkit/WebViewCore.mViewportHeight");
2942     gWebViewCoreFields.m_viewportInitialScale = env->GetFieldID(widget,
2943             "mViewportInitialScale", "I");
2944     LOG_ASSERT(gWebViewCoreFields.m_viewportInitialScale,
2945             "Unable to find android/webkit/WebViewCore.mViewportInitialScale");
2946     gWebViewCoreFields.m_viewportMinimumScale = env->GetFieldID(widget,
2947             "mViewportMinimumScale", "I");
2948     LOG_ASSERT(gWebViewCoreFields.m_viewportMinimumScale,
2949             "Unable to find android/webkit/WebViewCore.mViewportMinimumScale");
2950     gWebViewCoreFields.m_viewportMaximumScale = env->GetFieldID(widget,
2951             "mViewportMaximumScale", "I");
2952     LOG_ASSERT(gWebViewCoreFields.m_viewportMaximumScale,
2953             "Unable to find android/webkit/WebViewCore.mViewportMaximumScale");
2954     gWebViewCoreFields.m_viewportUserScalable = env->GetFieldID(widget,
2955             "mViewportUserScalable", "Z");
2956     LOG_ASSERT(gWebViewCoreFields.m_viewportUserScalable,
2957             "Unable to find android/webkit/WebViewCore.mViewportUserScalable");
2958     gWebViewCoreFields.m_viewportDensityDpi = env->GetFieldID(widget,
2959             "mViewportDensityDpi", "I");
2960     LOG_ASSERT(gWebViewCoreFields.m_viewportDensityDpi,
2961             "Unable to find android/webkit/WebViewCore.mViewportDensityDpi");
2962     gWebViewCoreFields.m_webView = env->GetFieldID(widget,
2963             "mWebView", "Landroid/webkit/WebView;");
2964     LOG_ASSERT(gWebViewCoreFields.m_webView,
2965             "Unable to find android/webkit/WebViewCore.mWebView");
2966 
2967     return jniRegisterNativeMethods(env, "android/webkit/WebViewCore",
2968             gJavaWebViewCoreMethods, NELEM(gJavaWebViewCoreMethods));
2969 }
2970 
2971 } /* namespace android */
2972