• 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 <wtf/Platform.h>
30 
31 #include "android_graphics.h"
32 #include "Arena.h"
33 #include "AtomicString.h"
34 #include "Cache.h"
35 #include "ChromeClientAndroid.h"
36 #include "ContextMenuClientAndroid.h"
37 #include "CString.h"
38 #include "Document.h"
39 #include "DocumentLoader.h"
40 #include "DragClientAndroid.h"
41 #include "EditorClientAndroid.h"
42 #include "Element.h"
43 #include "Font.h"
44 #include "Frame.h"
45 #include "FrameLoader.h"
46 #include "FrameLoaderClientAndroid.h"
47 #include "FrameTree.h"
48 #include "FrameView.h"
49 #include "GCController.h"
50 #include "GraphicsContext.h"
51 #include "HistoryItem.h"
52 #include "HTMLElement.h"
53 #include "HTMLFormElement.h"
54 #include "HTMLInputElement.h"
55 #include "HTMLNames.h"
56 #include "IconDatabase.h"
57 #include "Image.h"
58 #include "InspectorClientAndroid.h"
59 #include "JSDOMWindow.h"
60 #include <runtime/InitializeThreading.h>
61 #include <runtime/JSLock.h>
62 #include "KURL.h"
63 #include "Page.h"
64 #include "PageCache.h"
65 #include "PlatformString.h"
66 #include "RenderPart.h"
67 #include "RenderSkinAndroid.h"
68 #include "RenderTreeAsText.h"
69 #include "RenderView.h"
70 #include "ResourceHandle.h"
71 #include "ScriptController.h"
72 #include "ScriptValue.h"
73 #include "SelectionController.h"
74 #include "Settings.h"
75 #include "SubstituteData.h"
76 #include "WebCoreFrameBridge.h"
77 #include "WebCoreJni.h"
78 #include "WebCoreResourceLoader.h"
79 #include "WebHistory.h"
80 #include "WebIconDatabase.h"
81 #include "WebFrameView.h"
82 #include "WebViewCore.h"
83 #include "wds/DebugServer.h"
84 
85 #include <runtime_root.h>
86 #include <runtime_object.h>
87 #include <jni_utility.h>
88 #include "jni.h"
89 #include "jni_instance.h"
90 
91 #include <JNIHelp.h>
92 #include <SkGraphics.h>
93 #include <utils/misc.h>
94 #include <utils/AssetManager.h>
95 #include <android_runtime/android_util_AssetManager.h>
96 
97 #ifdef ANDROID_INSTRUMENT
98 #include "TimeCounter.h"
99 #include <runtime/JSLock.h>
100 #endif
101 
102 using namespace JSC;
103 using namespace JSC::Bindings;
104 
105 namespace android {
106 
107 // ----------------------------------------------------------------------------
108 
109 #define WEBCORE_MEMORY_CAP 15 * 1024 * 1024
110 
111 // ----------------------------------------------------------------------------
112 
113 struct WebFrame::JavaBrowserFrame
114 {
115     jobject     mObj;
116     jobject     mHistoryList; // WebBackForwardList object
117     jmethodID   mStartLoadingResource;
118     jmethodID   mLoadStarted;
119     jmethodID   mTransitionToCommitted;
120     jmethodID   mLoadFinished;
121     jmethodID   mReportError;
122     jmethodID   mSetTitle;
123     jmethodID   mWindowObjectCleared;
124     jmethodID   mSetProgress;
125     jmethodID   mDidReceiveIcon;
126     jmethodID   mUpdateVisitedHistory;
127     jmethodID   mHandleUrl;
128     jmethodID   mCreateWindow;
129     jmethodID   mCloseWindow;
130     jmethodID   mDecidePolicyForFormResubmission;
131     jmethodID   mRequestFocus;
132     jmethodID   mGetRawResFilename;
frameandroid::WebFrame::JavaBrowserFrame133     AutoJObject frame(JNIEnv* env) {
134         return getRealObject(env, mObj);
135     }
historyandroid::WebFrame::JavaBrowserFrame136     AutoJObject history(JNIEnv* env) {
137         return getRealObject(env, mHistoryList);
138     }
139 };
140 
141 static jfieldID gFrameField;
142 #define GET_NATIVE_FRAME(env, obj) ((WebCore::Frame*)env->GetIntField(obj, gFrameField))
143 #define SET_NATIVE_FRAME(env, obj, frame) (env->SetIntField(obj, gFrameField, frame))
144 
145 // ----------------------------------------------------------------------------
146 
WebFrame(JNIEnv * env,jobject obj,jobject historyList,WebCore::Page * page)147 WebFrame::WebFrame(JNIEnv* env, jobject obj, jobject historyList, WebCore::Page* page)
148     : mPage(page)
149 {
150     jclass clazz = env->GetObjectClass(obj);
151     mJavaFrame = new JavaBrowserFrame;
152     mJavaFrame->mObj = adoptGlobalRef(env, obj);
153     mJavaFrame->mHistoryList = adoptGlobalRef(env, historyList);
154     mJavaFrame->mStartLoadingResource = env->GetMethodID(clazz, "startLoadingResource",
155             "(ILjava/lang/String;Ljava/lang/String;Ljava/util/HashMap;[BIZZ)Landroid/webkit/LoadListener;");
156     mJavaFrame->mLoadStarted = env->GetMethodID(clazz, "loadStarted",
157             "(Ljava/lang/String;Landroid/graphics/Bitmap;IZ)V");
158     mJavaFrame->mTransitionToCommitted = env->GetMethodID(clazz, "transitionToCommitted",
159             "(IZ)V");
160     mJavaFrame->mLoadFinished = env->GetMethodID(clazz, "loadFinished",
161             "(Ljava/lang/String;IZ)V");
162     mJavaFrame->mReportError = env->GetMethodID(clazz, "reportError",
163             "(ILjava/lang/String;Ljava/lang/String;)V");
164     mJavaFrame->mSetTitle = env->GetMethodID(clazz, "setTitle",
165             "(Ljava/lang/String;)V");
166     mJavaFrame->mWindowObjectCleared = env->GetMethodID(clazz, "windowObjectCleared",
167             "(I)V");
168     mJavaFrame->mSetProgress = env->GetMethodID(clazz, "setProgress",
169             "(I)V");
170     mJavaFrame->mDidReceiveIcon = env->GetMethodID(clazz, "didReceiveIcon",
171             "(Landroid/graphics/Bitmap;)V");
172     mJavaFrame->mUpdateVisitedHistory = env->GetMethodID(clazz, "updateVisitedHistory",
173             "(Ljava/lang/String;Z)V");
174     mJavaFrame->mHandleUrl = env->GetMethodID(clazz, "handleUrl",
175             "(Ljava/lang/String;)Z");
176     mJavaFrame->mCreateWindow = env->GetMethodID(clazz, "createWindow",
177             "(ZZ)Landroid/webkit/BrowserFrame;");
178     mJavaFrame->mCloseWindow = env->GetMethodID(clazz, "closeWindow",
179             "(Landroid/webkit/WebViewCore;)V");
180     mJavaFrame->mDecidePolicyForFormResubmission = env->GetMethodID(clazz,
181             "decidePolicyForFormResubmission", "(I)V");
182     mJavaFrame->mRequestFocus = env->GetMethodID(clazz, "requestFocus",
183             "()V");
184     mJavaFrame->mGetRawResFilename = env->GetMethodID(clazz, "getRawResFilename",
185             "(I)Ljava/lang/String;");
186 
187     LOG_ASSERT(mJavaFrame->mStartLoadingResource, "Could not find method startLoadingResource");
188     LOG_ASSERT(mJavaFrame->mLoadStarted, "Could not find method loadStarted");
189     LOG_ASSERT(mJavaFrame->mTransitionToCommitted, "Could not find method transitionToCommitted");
190     LOG_ASSERT(mJavaFrame->mLoadFinished, "Could not find method loadFinished");
191     LOG_ASSERT(mJavaFrame->mReportError, "Could not find method reportError");
192     LOG_ASSERT(mJavaFrame->mSetTitle, "Could not find method setTitle");
193     LOG_ASSERT(mJavaFrame->mWindowObjectCleared, "Could not find method windowObjectCleared");
194     LOG_ASSERT(mJavaFrame->mSetProgress, "Could not find method setProgress");
195     LOG_ASSERT(mJavaFrame->mDidReceiveIcon, "Could not find method didReceiveIcon");
196     LOG_ASSERT(mJavaFrame->mUpdateVisitedHistory, "Could not find method updateVisitedHistory");
197     LOG_ASSERT(mJavaFrame->mHandleUrl, "Could not find method handleUrl");
198     LOG_ASSERT(mJavaFrame->mCreateWindow, "Could not find method createWindow");
199     LOG_ASSERT(mJavaFrame->mCloseWindow, "Could not find method closeWindow");
200     LOG_ASSERT(mJavaFrame->mDecidePolicyForFormResubmission, "Could not find method decidePolicyForFormResubmission");
201     LOG_ASSERT(mJavaFrame->mRequestFocus, "Could not find method requestFocus");
202     LOG_ASSERT(mJavaFrame->mGetRawResFilename, "Could not find method getRawResFilename");
203 
204     mUserAgent = WebCore::String();
205     mUserInitiatedClick = false;
206 }
207 
~WebFrame()208 WebFrame::~WebFrame()
209 {
210     if (mJavaFrame->mObj) {
211         JNIEnv* env = JSC::Bindings::getJNIEnv();
212         env->DeleteGlobalRef(mJavaFrame->mObj);
213         env->DeleteGlobalRef(mJavaFrame->mHistoryList);
214         mJavaFrame->mObj = 0;
215     }
216     delete mJavaFrame;
217 }
218 
getWebFrame(const WebCore::Frame * frame)219 WebFrame* WebFrame::getWebFrame(const WebCore::Frame* frame)
220 {
221     FrameLoaderClientAndroid* client =
222             static_cast<FrameLoaderClientAndroid*> (frame->loader()->client());
223     return client->webFrame();
224 }
225 
createJavaMapFromHTTPHeaders(JNIEnv * env,const WebCore::HTTPHeaderMap & map)226 static jobject createJavaMapFromHTTPHeaders(JNIEnv* env, const WebCore::HTTPHeaderMap& map)
227 {
228     jclass mapClass = env->FindClass("java/util/HashMap");
229     LOG_ASSERT(mapClass, "Could not find HashMap class!");
230     jmethodID init = env->GetMethodID(mapClass, "<init>", "(I)V");
231     LOG_ASSERT(init, "Could not find constructor for HashMap");
232     jobject hashMap = env->NewObject(mapClass, init, map.size());
233     LOG_ASSERT(hashMap, "Could not create a new HashMap");
234     jmethodID put = env->GetMethodID(mapClass, "put",
235             "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
236     LOG_ASSERT(put, "Could not find put method on HashMap");
237 
238     WebCore::HTTPHeaderMap::const_iterator end = map.end();
239     for (WebCore::HTTPHeaderMap::const_iterator i = map.begin(); i != end; ++i) {
240         if (i->first.length() == 0 || i->second.length() == 0)
241             continue;
242         jstring key = env->NewString((unsigned short *)i->first.characters(), i->first.length());
243         jstring val = env->NewString((unsigned short *)i->second.characters(), i->second.length());
244         if (key && val) {
245             env->CallObjectMethod(hashMap, put, key, val);
246             env->DeleteLocalRef(key);
247             env->DeleteLocalRef(val);
248         }
249     }
250     env->DeleteLocalRef(mapClass);
251 
252     return hashMap;
253 }
254 
255 WebCoreResourceLoader*
startLoadingResource(WebCore::ResourceHandle * loader,const WebCore::ResourceRequest & request,bool isHighPriority,bool synchronous)256 WebFrame::startLoadingResource(WebCore::ResourceHandle* loader,
257                                   const WebCore::ResourceRequest& request,
258                                   bool isHighPriority, bool synchronous)
259 {
260 #ifdef ANDROID_INSTRUMENT
261     TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
262 #endif
263     LOGV("::WebCore:: startLoadingResource(%p, %s)",
264             loader, request.url().string().ascii().data());
265 
266     WebCore::String method = request.httpMethod();
267     WebCore::HTTPHeaderMap headers = request.httpHeaderFields();
268 
269     JNIEnv* env = JSC::Bindings::getJNIEnv();
270     WebCore::String urlStr = request.url().string();
271     jstring jUrlStr = env->NewString(urlStr.characters(), urlStr.length());
272     jstring jMethodStr = NULL;
273     if (!method.isEmpty())
274         jMethodStr = env->NewString(method.characters(), method.length());
275     jbyteArray jPostDataStr = NULL;
276     WebCore::FormData* formdata = request.httpBody();
277     if (formdata) {
278         // We can use the formdata->flatten() but it will result in two
279         // memcpys, first through loading up the vector with the form data
280         // then another to copy it out of the vector and into the java byte
281         // array. Instead, we copy the form data ourselves below saving a
282         // memcpy.
283         const WTF::Vector<WebCore::FormDataElement>& elements =
284                 formdata->elements();
285 
286         // Sizing pass
287         int size = 0;
288         size_t n = elements.size();
289         for (size_t i = 0; i < n; ++i) {
290             const WebCore::FormDataElement& e = elements[i];
291             if (e.m_type == WebCore::FormDataElement::data) {
292                 size += e.m_data.size();
293             }
294         }
295 
296         // Only create the byte array if there is POST data to pass up.
297         // The Java code is expecting null if there is no data.
298         if (size > 0) {
299             // Copy the actual form data.
300             jPostDataStr = env->NewByteArray(size);
301             if (jPostDataStr) {
302                 // Write  the form data to the java array.
303                 jbyte* bytes = env->GetByteArrayElements(jPostDataStr, NULL);
304                 int offset = 0;
305                 for (size_t i = 0; i < n; ++i) {
306                     const WebCore::FormDataElement& e = elements[i];
307                     if (e.m_type == WebCore::FormDataElement::data) {
308                         int delta = e.m_data.size();
309                         memcpy(bytes + offset, e.m_data.data(), delta);
310                         offset += delta;
311                     }
312                 }
313                 env->ReleaseByteArrayElements(jPostDataStr, bytes, 0);
314             }
315         }
316     }
317 
318     jobject jHeaderMap = createJavaMapFromHTTPHeaders(env, headers);
319 
320     // Convert the WebCore Cache Policy to a WebView Cache Policy.
321     int cacheMode = 0;  // WebView.LOAD_NORMAL
322     switch (request.cachePolicy()) {
323         case WebCore::ReloadIgnoringCacheData:
324             cacheMode = 2; // WebView.LOAD_NO_CACHE
325             break;
326         case WebCore::ReturnCacheDataDontLoad:
327             cacheMode = 3; // WebView.LOAD_CACHE_ONLY
328             break;
329         case WebCore::ReturnCacheDataElseLoad:
330             cacheMode = 1;   // WebView.LOAD_CACHE_ELSE_NETWORK
331             break;
332         case WebCore::UseProtocolCachePolicy:
333         default:
334             break;
335     }
336 
337     LOGV("::WebCore:: startLoadingResource %s with cacheMode %d", urlStr.ascii().data(), cacheMode);
338 
339 
340     jobject jLoadListener =
341         env->CallObjectMethod(mJavaFrame->frame(env).get(), mJavaFrame->mStartLoadingResource,
342                                               (int)loader, jUrlStr, jMethodStr, jHeaderMap,
343                                               jPostDataStr, cacheMode, isHighPriority, synchronous);
344 
345     env->DeleteLocalRef(jUrlStr);
346     env->DeleteLocalRef(jMethodStr);
347     env->DeleteLocalRef(jPostDataStr);
348     env->DeleteLocalRef(jHeaderMap);
349     if (checkException(env))
350         return NULL;
351 
352     WebCoreResourceLoader* h = NULL;
353     if (jLoadListener)
354         h = new WebCoreResourceLoader(env, jLoadListener);
355     env->DeleteLocalRef(jLoadListener);
356     return h;
357 }
358 
359 void
reportError(int errorCode,const WebCore::String & description,const WebCore::String & failingUrl)360 WebFrame::reportError(int errorCode, const WebCore::String& description,
361         const WebCore::String& failingUrl)
362 {
363 #ifdef ANDROID_INSTRUMENT
364     TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
365 #endif
366     LOGV("::WebCore:: reportError(%d, %s)", errorCode, description.ascii().data());
367     JNIEnv* env = JSC::Bindings::getJNIEnv();
368 
369     jstring descStr = env->NewString((unsigned short*)description.characters(), description.length());
370     jstring failUrl = env->NewString((unsigned short*)failingUrl.characters(), failingUrl.length());
371     env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mReportError, errorCode, descStr, failUrl);
372     env->DeleteLocalRef(descStr);
373     env->DeleteLocalRef(failUrl);
374 }
375 
376 void
loadStarted(WebCore::Frame * frame)377 WebFrame::loadStarted(WebCore::Frame* frame)
378 {
379 #ifdef ANDROID_INSTRUMENT
380     TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
381 #endif
382     const WebCore::KURL& url = frame->loader()->activeDocumentLoader()->url();
383     if (url.isEmpty())
384         return;
385     LOGV("::WebCore:: loadStarted %s", url.string().ascii().data());
386 
387     bool isMainFrame = (!frame->tree() || !frame->tree()->parent());
388     WebCore::FrameLoadType loadType = frame->loader()->loadType();
389 
390     if (loadType == WebCore::FrameLoadTypeReplace ||
391             loadType == WebCore::FrameLoadTypeSame ||
392             (loadType == WebCore::FrameLoadTypeRedirectWithLockedBackForwardList &&
393              !isMainFrame))
394         return;
395 
396     JNIEnv* env = JSC::Bindings::getJNIEnv();
397     WebCore::String urlString(url.string());
398     // If this is the main frame and we already have a favicon in the database,
399     // send it along with the page started notification.
400     jobject favicon = NULL;
401     if (isMainFrame) {
402         WebCore::Image* icon = WebCore::iconDatabase()->iconForPageURL(urlString, WebCore::IntSize(16, 16));
403         if (icon)
404             favicon = webcoreImageToJavaBitmap(env, icon);
405         LOGV("favicons", "Starting load with icon %p for %s", icon, url.string().utf8().data());
406     }
407     jstring urlStr = env->NewString((unsigned short*)urlString.characters(), urlString.length());
408 
409     env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mLoadStarted, urlStr, favicon,
410             (int)loadType, isMainFrame);
411     checkException(env);
412     env->DeleteLocalRef(urlStr);
413     if (favicon)
414         env->DeleteLocalRef(favicon);
415 }
416 
417 void
transitionToCommitted(WebCore::Frame * frame)418 WebFrame::transitionToCommitted(WebCore::Frame* frame)
419 {
420 #ifdef ANDROID_INSTRUMENT
421     TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
422 #endif
423     JNIEnv* env = JSC::Bindings::getJNIEnv();
424     WebCore::FrameLoadType loadType = frame->loader()->loadType();
425     bool isMainFrame = (!frame->tree() || !frame->tree()->parent());
426     env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mTransitionToCommitted,
427             (int)loadType, isMainFrame);
428     checkException(env);
429 }
430 
431 void
didFinishLoad(WebCore::Frame * frame)432 WebFrame::didFinishLoad(WebCore::Frame* frame)
433 {
434 #ifdef ANDROID_INSTRUMENT
435     TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
436 #endif
437     JNIEnv* env = JSC::Bindings::getJNIEnv();
438     WebCore::FrameLoader* loader = frame->loader();
439     const WebCore::KURL& url = loader->activeDocumentLoader()->url();
440     if (url.isEmpty())
441         return;
442     LOGV("::WebCore:: didFinishLoad %s", url.string().ascii().data());
443 
444     bool isMainFrame = (!frame->tree() || !frame->tree()->parent());
445     WebCore::FrameLoadType loadType = loader->loadType();
446     WebCore::String urlString(url.string());
447     jstring urlStr = env->NewString((unsigned short*)urlString.characters(), urlString.length());
448     env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mLoadFinished, urlStr,
449             (int)loadType, isMainFrame);
450     checkException(env);
451     env->DeleteLocalRef(urlStr);
452 }
453 
454 void
addHistoryItem(WebCore::HistoryItem * item)455 WebFrame::addHistoryItem(WebCore::HistoryItem* item)
456 {
457 #ifdef ANDROID_INSTRUMENT
458     TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
459 #endif
460     LOGV("::WebCore:: addHistoryItem");
461     JNIEnv* env = JSC::Bindings::getJNIEnv();
462     WebHistory::AddItem(mJavaFrame->history(env), item);
463 }
464 
465 void
removeHistoryItem(int index)466 WebFrame::removeHistoryItem(int index)
467 {
468 #ifdef ANDROID_INSTRUMENT
469     TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
470 #endif
471     LOGV("::WebCore:: removeHistoryItem at %d", index);
472     JNIEnv* env = JSC::Bindings::getJNIEnv();
473     WebHistory::RemoveItem(mJavaFrame->history(env), index);
474 }
475 
476 void
updateHistoryIndex(int newIndex)477 WebFrame::updateHistoryIndex(int newIndex)
478 {
479 #ifdef ANDROID_INSTRUMENT
480     TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
481 #endif
482     LOGV("::WebCore:: updateHistoryIndex to %d", newIndex);
483     JNIEnv* env = JSC::Bindings::getJNIEnv();
484     WebHistory::UpdateHistoryIndex(mJavaFrame->history(env), newIndex);
485 }
486 
487 void
setTitle(const WebCore::String & title)488 WebFrame::setTitle(const WebCore::String& title)
489 {
490 #ifdef ANDROID_INSTRUMENT
491     TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
492 #endif
493 #ifndef NDEBUG
494     LOGV("setTitle(%s)", title.ascii().data());
495 #endif
496     JNIEnv* env = JSC::Bindings::getJNIEnv();
497     jstring jTitleStr = env->NewString((unsigned short *)title.characters(), title.length());
498 
499     env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mSetTitle,
500                                         jTitleStr);
501     checkException(env);
502     env->DeleteLocalRef(jTitleStr);
503 }
504 
505 void
windowObjectCleared(WebCore::Frame * frame)506 WebFrame::windowObjectCleared(WebCore::Frame* frame)
507 {
508 #ifdef ANDROID_INSTRUMENT
509     TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
510 #endif
511     LOGV("::WebCore:: windowObjectCleared");
512     JNIEnv* env = JSC::Bindings::getJNIEnv();
513 
514     env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mWindowObjectCleared, (int)frame);
515     checkException(env);
516 }
517 
518 void
setProgress(float newProgress)519 WebFrame::setProgress(float newProgress)
520 {
521 #ifdef ANDROID_INSTRUMENT
522     TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
523 #endif
524     JNIEnv* env = JSC::Bindings::getJNIEnv();
525     int progress = (int) (100 * newProgress);
526     env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mSetProgress, progress);
527     checkException(env);
528 }
529 
530 const WebCore::String
userAgentForURL(const WebCore::KURL * url)531 WebFrame::userAgentForURL(const WebCore::KURL* url)
532 {
533     return mUserAgent;
534 }
535 
536 void
didReceiveIcon(WebCore::Image * icon)537 WebFrame::didReceiveIcon(WebCore::Image* icon)
538 {
539 #ifdef ANDROID_INSTRUMENT
540     TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
541 #endif
542     LOG_ASSERT(icon, "DidReceiveIcon called without an image!");
543     JNIEnv* env = JSC::Bindings::getJNIEnv();
544     jobject bitmap = webcoreImageToJavaBitmap(env, icon);
545     if (!bitmap)
546         return;
547 
548     env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mDidReceiveIcon, bitmap);
549     env->DeleteLocalRef(bitmap);
550     checkException(env);
551 }
552 
553 void
updateVisitedHistory(const WebCore::KURL & url,bool reload)554 WebFrame::updateVisitedHistory(const WebCore::KURL& url, bool reload)
555 {
556 #ifdef ANDROID_INSTRUMENT
557     TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
558 #endif
559     WebCore::String urlStr(url.string());
560     JNIEnv* env = JSC::Bindings::getJNIEnv();
561     jstring jUrlStr = env->NewString((unsigned short*)urlStr.characters(), urlStr.length());
562 
563     env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mUpdateVisitedHistory, jUrlStr, reload);
564     checkException(env);
565 }
566 
567 bool
canHandleRequest(const WebCore::ResourceRequest & request)568 WebFrame::canHandleRequest(const WebCore::ResourceRequest& request)
569 {
570 #ifdef ANDROID_INSTRUMENT
571     TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
572 #endif
573     // Internal loads are ok but any request that is due to a user hitting a key
574     // should be checked.
575     bool userGesture = false;
576 #ifdef ANDROID_USER_GESTURE
577     userGesture = request.userGesture();
578 #endif
579     // always handle "POST" in place
580     if (equalIgnoringCase(request.httpMethod(), "POST"))
581         return true;
582     WebCore::KURL requestUrl = request.url();
583     if (!mUserInitiatedClick && !userGesture &&
584         (requestUrl.protocolIs("http") || requestUrl.protocolIs("https") ||
585             requestUrl.protocolIs("file") || requestUrl.protocolIs("about") ||
586             requestUrl.protocolIs("javascript")))
587         return true;
588     WebCore::String url(request.url().string());
589     // Empty urls should not be sent to java
590     if (url.isEmpty())
591         return true;
592     JNIEnv* env = JSC::Bindings::getJNIEnv();
593     jstring jUrlStr = env->NewString((unsigned short *)url.characters(), url.length());
594 
595     // check to see whether browser app wants to hijack url loading.
596     // if browser app handles the url, we will return false to bail out WebCore loading
597     jboolean ret = env->CallBooleanMethod(mJavaFrame->frame(env).get(), mJavaFrame->mHandleUrl, jUrlStr);
598     checkException(env);
599     return (ret == 0);
600 }
601 
602 WebCore::Frame*
createWindow(bool dialog,bool userGesture)603 WebFrame::createWindow(bool dialog, bool userGesture)
604 {
605 #ifdef ANDROID_INSTRUMENT
606     TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
607 #endif
608     JNIEnv* env = JSC::Bindings::getJNIEnv();
609     jobject obj = env->CallObjectMethod(mJavaFrame->frame(env).get(),
610             mJavaFrame->mCreateWindow, dialog, userGesture);
611     if (obj) {
612         WebCore::Frame* frame = GET_NATIVE_FRAME(env, obj);
613         return frame;
614     }
615     return NULL;
616 }
617 
618 void
requestFocus() const619 WebFrame::requestFocus() const
620 {
621 #ifdef ANDROID_INSTRUMENT
622     TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
623 #endif
624     JNIEnv* env = JSC::Bindings::getJNIEnv();
625     env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mRequestFocus);
626     checkException(env);
627 }
628 
629 void
closeWindow(WebViewCore * webViewCore)630 WebFrame::closeWindow(WebViewCore* webViewCore)
631 {
632 #ifdef ANDROID_INSTRUMENT
633     TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
634 #endif
635     assert(webViewCore);
636     JNIEnv* env = JSC::Bindings::getJNIEnv();
637     env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mCloseWindow,
638             webViewCore->getJavaObject().get());
639 }
640 
641 struct PolicyFunctionWrapper {
642     WebCore::FramePolicyFunction func;
643 };
644 
645 void
decidePolicyForFormResubmission(WebCore::FramePolicyFunction func)646 WebFrame::decidePolicyForFormResubmission(WebCore::FramePolicyFunction func)
647 {
648 #ifdef ANDROID_INSTRUMENT
649     TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
650 #endif
651     JNIEnv* env = JSC::Bindings::getJNIEnv();
652     PolicyFunctionWrapper* p = new PolicyFunctionWrapper;
653     p->func = func;
654     env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mDecidePolicyForFormResubmission, p);
655 }
656 
657 WebCore::String
getRawResourceFilename(RAW_RES_ID id) const658 WebFrame::getRawResourceFilename(RAW_RES_ID id) const
659 {
660     JNIEnv* env = JSC::Bindings::getJNIEnv();
661     jstring ret = (jstring) env->CallObjectMethod(mJavaFrame->frame(env).get(),
662             mJavaFrame->mGetRawResFilename, (int)id);
663 
664     return to_string(env, ret);
665 }
666 
667 // ----------------------------------------------------------------------------
CallPolicyFunction(JNIEnv * env,jobject obj,jint func,jint decision)668 static void CallPolicyFunction(JNIEnv* env, jobject obj, jint func, jint decision)
669 {
670 #ifdef ANDROID_INSTRUMENT
671     TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
672 #endif
673     WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
674     LOG_ASSERT(pFrame, "nativeCallPolicyFunction must take a valid frame pointer!");
675     PolicyFunctionWrapper* pFunc = (PolicyFunctionWrapper*)func;
676     LOG_ASSERT(pFunc, "nativeCallPolicyFunction must take a valid function pointer!");
677 
678     (pFrame->loader()->*(pFunc->func))((WebCore::PolicyAction)decision);
679 }
680 
CreateFrame(JNIEnv * env,jobject obj,jobject javaview,jobject jAssetManager,jobject historyList)681 static void CreateFrame(JNIEnv* env, jobject obj, jobject javaview, jobject jAssetManager, jobject historyList)
682 {
683     JSC::initializeThreading();
684 #ifdef ANDROID_INSTRUMENT
685     TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
686 #endif
687     ChromeClientAndroid*      chromeC = new ChromeClientAndroid;
688     EditorClientAndroid*      editorC = new EditorClientAndroid;
689     WebCore::ContextMenuClient* contextMenuC = new ContextMenuClientAndroid;
690     WebCore::DragClient*        dragC = new DragClientAndroid;
691     InspectorClientAndroid* inspectorC = new InspectorClientAndroid;
692     // Create a new page
693     WebCore::Page* page = new WebCore::Page(chromeC, contextMenuC, editorC, dragC, inspectorC);
694     // css files without explicit MIMETYPE is treated as generic text files in
695     // the Java side. So we can't enforce CSS MIMETYPE.
696     page->settings()->setEnforceCSSMIMETypeInStrictMode(false);
697     /* TODO: Don't turn on PageCache until we can restore the ScrollView State.
698      * This caused bug http://b/issue?id=1202983
699     page->settings()->setUsesPageCache(true);
700     // 10 is a random number chosen because it is small enough to give the user
701     // a good back/forward page cache without allowing the page cache to get too
702     // big.
703     WebCore::pageCache()->setCapacity(10);
704     */
705     editorC->setPage(page);
706     page->setGroupName("android.webkit");
707 
708     // Create a WebFrame to access the Java BrowserFrame associated with this page
709     WebFrame* webFrame = new WebFrame(env, obj, historyList, page);
710     // Attach webFrame to chromeC and release our ownership
711     chromeC->setWebFrame(webFrame);
712     Release(webFrame);
713 
714     FrameLoaderClientAndroid* loaderC = new FrameLoaderClientAndroid(webFrame);
715     // Create a Frame and the page holds its reference
716     WebCore::Frame* frame = WebCore::Frame::create(page, NULL, loaderC).get();
717     loaderC->setFrame(frame);
718 #if ENABLE(WDS)
719     WDS::server()->addFrame(frame);
720 #endif
721 
722     // Create a WebViewCore to access the Java WebViewCore associated with this page
723     WebViewCore* webViewCore = new WebViewCore(env, javaview, frame);
724 
725     // Create a FrameView
726     WebCore::FrameView* frameView = new WebCore::FrameView(frame);
727     // Create a WebFrameView
728     WebFrameView* webFrameView = new WebFrameView(frameView, webViewCore);
729     // As webFrameView Retains webViewCore, release our ownership
730     Release(webViewCore);
731     // As frameView Retains webFrameView, release our ownership
732     Release(webFrameView);
733     // Attach the frameView to the frame and release our ownership
734     frame->setView(frameView);
735     frameView->deref();
736 
737     // Set the frame to active to turn on keyboard focus.
738     frame->init();
739     frame->selection()->setFocused(true);
740 
741     // Allow local access to file:/// and substitute data
742     WebCore::FrameLoader::setLocalLoadPolicy(
743             WebCore::FrameLoader::AllowLocalLoadsForLocalAndSubstituteData);
744 
745     LOGV("::WebCore:: createFrame %p", frame);
746 
747     // Set the mNativeFrame field in Frame
748     SET_NATIVE_FRAME(env, obj, (int)frame);
749 
750     // Setup the asset manager.
751     AssetManager* am = assetManagerForJavaObject(env, jAssetManager);
752     // Initialize our skinning classes
753     WebCore::RenderSkinAndroid::Init(am);
754 }
755 
DestroyFrame(JNIEnv * env,jobject obj)756 static void DestroyFrame(JNIEnv* env, jobject obj)
757 {
758 #ifdef ANDROID_INSTRUMENT
759     TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
760 #endif
761     WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
762     LOG_ASSERT(pFrame, "nativeDestroyFrame must take a valid frame pointer!");
763 
764     LOGV("::WebCore:: deleting frame %p", pFrame);
765 
766     WebCore::FrameView* view = pFrame->view();
767     view->ref();
768     // detachFromParent will cause the page to be closed.
769     WebCore::FrameLoader* fl = pFrame->loader();
770     // retain a pointer because detachFromParent will set the page to null.
771     WebCore::Page* page = pFrame->page();
772     if (fl)
773         fl->detachFromParent();
774     delete page;
775     view->deref();
776 
777     SET_NATIVE_FRAME(env, obj, 0);
778 #if ENABLE(WDS)
779     WDS::server()->removeFrame(pFrame);
780 #endif
781 }
782 
LoadUrl(JNIEnv * env,jobject obj,jstring url)783 static void LoadUrl(JNIEnv *env, jobject obj, jstring url)
784 {
785 #ifdef ANDROID_INSTRUMENT
786     TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
787 #endif
788     WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
789     LOG_ASSERT(pFrame, "nativeLoadUrl must take a valid frame pointer!");
790 
791     WebCore::String webcoreUrl = to_string(env, url);
792     WebCore::KURL kurl(WebCore::KURL(), webcoreUrl);
793     WebCore::ResourceRequest request(kurl);
794     LOGV("LoadUrl %s", kurl.string().latin1().data());
795     pFrame->loader()->load(request, false);
796 }
797 
PostUrl(JNIEnv * env,jobject obj,jstring url,jbyteArray postData)798 static void PostUrl(JNIEnv *env, jobject obj, jstring url, jbyteArray postData)
799 {
800 #ifdef ANDROID_INSTRUMENT
801     TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
802 #endif
803     WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
804     LOG_ASSERT(pFrame, "nativePostUrl must take a valid frame pointer!");
805 
806     WebCore::KURL kurl(WebCore::KURL(), to_string(env, url));
807     WebCore::ResourceRequest request(kurl);
808     request.setHTTPContentType("application/x-www-form-urlencoded");
809 
810     if (postData) {
811         jsize size = env->GetArrayLength(postData);
812         jbyte* bytes = env->GetByteArrayElements(postData, NULL);
813         request.setHTTPBody(WebCore::FormData::create((const void*)bytes, size));
814         env->ReleaseByteArrayElements(postData, bytes, 0);
815     }
816 
817     LOGV("PostUrl %s", kurl.string().latin1().data());
818     pFrame->loader()->loadPostRequest(request, String(), String(), false,
819             WebCore::FrameLoadTypeStandard, 0, 0, true);
820 }
821 
LoadData(JNIEnv * env,jobject obj,jstring baseUrl,jstring data,jstring mimeType,jstring encoding,jstring failUrl)822 static void LoadData(JNIEnv *env, jobject obj, jstring baseUrl, jstring data,
823         jstring mimeType, jstring encoding, jstring failUrl)
824 {
825 #ifdef ANDROID_INSTRUMENT
826     TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
827 #endif
828     WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
829     LOG_ASSERT(pFrame, "nativeLoadData must take a valid frame pointer!");
830 
831     // Setup the resource request
832     WebCore::ResourceRequest request(to_string(env, baseUrl));
833 
834     // Setup the substituteData
835     const char* dataStr = env->GetStringUTFChars(data, NULL);
836     WTF::PassRefPtr<WebCore::SharedBuffer> sharedBuffer =
837         WebCore::SharedBuffer::create();
838     LOG_ASSERT(dataStr, "nativeLoadData has a null data string.");
839     sharedBuffer->append(dataStr, strlen(dataStr));
840     env->ReleaseStringUTFChars(data, dataStr);
841 
842     WebCore::SubstituteData substituteData(sharedBuffer,
843             to_string(env, mimeType), to_string(env, encoding),
844             WebCore::KURL(to_string(env, failUrl)));
845 
846     // Perform the load
847     pFrame->loader()->load(request, substituteData, false);
848 }
849 
StopLoading(JNIEnv * env,jobject obj)850 static void StopLoading(JNIEnv *env, jobject obj)
851 {
852 #ifdef ANDROID_INSTRUMENT
853     TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
854 #endif
855     WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
856     LOG_ASSERT(pFrame, "nativeStopLoading must take a valid frame pointer!");
857     LOGV("::WebCore:: stopLoading %p", pFrame);
858 
859     // Stop loading the page and do not send an unload event
860     pFrame->loader()->stopForUserCancel();
861 }
862 
ExternalRepresentation(JNIEnv * env,jobject obj)863 static jstring ExternalRepresentation(JNIEnv *env, jobject obj)
864 {
865 #ifdef ANDROID_INSTRUMENT
866     TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
867 #endif
868     WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
869     LOG_ASSERT(pFrame, "android_webcore_nativeExternalRepresentation must take a valid frame pointer!");
870 
871     // Request external representation of the render tree
872     WebCore::String renderDump = WebCore::externalRepresentation(pFrame->contentRenderer());
873     unsigned len = renderDump.length();
874     if (!len)
875         return NULL;
876     return env->NewString(renderDump.characters(), len);
877 }
878 
DocumentAsText(JNIEnv * env,jobject obj)879 static jstring DocumentAsText(JNIEnv *env, jobject obj)
880 {
881 #ifdef ANDROID_INSTRUMENT
882     TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
883 #endif
884     WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
885     LOG_ASSERT(pFrame, "android_webcore_nativeDocumentAsText must take a valid frame pointer!");
886 
887     WebCore::Element *documentElement = pFrame->document()->documentElement();
888     if (!documentElement)
889         return NULL;
890     WebCore::String renderDump = ((WebCore::HTMLElement*)documentElement)->innerText();
891     renderDump.append("\n");
892     unsigned len = renderDump.length();
893     if (!len)
894         return NULL;
895     return env->NewString((unsigned short*)renderDump.characters(), len);
896 }
897 
Reload(JNIEnv * env,jobject obj,jboolean allowStale)898 static void Reload(JNIEnv *env, jobject obj, jboolean allowStale)
899 {
900 #ifdef ANDROID_INSTRUMENT
901     TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
902 #endif
903     WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
904     LOG_ASSERT(pFrame, "nativeReload must take a valid frame pointer!");
905 
906     WebCore::FrameLoader* loader = pFrame->loader();
907     if (allowStale) {
908         // load the current page with FrameLoadTypeIndexedBackForward so that it
909         // will use cache when it is possible
910         WebCore::Page* page = pFrame->page();
911         WebCore::HistoryItem* item = page->backForwardList()->currentItem();
912         if (item)
913             page->goToItem(item, FrameLoadTypeIndexedBackForward);
914     } else
915         loader->reload(true);
916 }
917 
GoBackOrForward(JNIEnv * env,jobject obj,jint pos)918 static void GoBackOrForward(JNIEnv *env, jobject obj, jint pos)
919 {
920 #ifdef ANDROID_INSTRUMENT
921     TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
922 #endif
923     WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
924     LOG_ASSERT(pFrame, "nativeGoBackOrForward must take a valid frame pointer!");
925 
926     if (pos == 1)
927         pFrame->page()->goForward();
928     else if (pos == -1)
929         pFrame->page()->goBack();
930     else
931         pFrame->loader()->goBackOrForward(pos);
932 }
933 
StringByEvaluatingJavaScriptFromString(JNIEnv * env,jobject obj,jstring script)934 static jobject StringByEvaluatingJavaScriptFromString(JNIEnv *env, jobject obj, jstring script)
935 {
936 #ifdef ANDROID_INSTRUMENT
937     TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
938 #endif
939     WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
940     LOG_ASSERT(pFrame, "stringByEvaluatingJavaScriptFromString must take a valid frame pointer!");
941 
942     WebCore::ScriptValue value =
943             pFrame->loader()->executeScript(to_string(env, script), true);
944     WebCore::String result = WebCore::String();
945     if (!value.getString(result))
946         return NULL;
947     unsigned len = result.length();
948     if (len == 0)
949         return NULL;
950     return env->NewString((unsigned short*)result.characters(), len);
951 }
952 
953 // Wrap the JavaInstance used when binding custom javascript interfaces. Use a
954 // weak reference so that the gc can collect the WebView. Override virtualBegin
955 // and virtualEnd and swap the weak reference for the real object.
956 class WeakJavaInstance : public JavaInstance {
957 public:
create(jobject obj,PassRefPtr<RootObject> root)958     static PassRefPtr<WeakJavaInstance> create(jobject obj,
959             PassRefPtr<RootObject> root) {
960         return adoptRef(new WeakJavaInstance(obj, root));
961     }
962 
963 protected:
WeakJavaInstance(jobject instance,PassRefPtr<RootObject> rootObject)964     WeakJavaInstance(jobject instance, PassRefPtr<RootObject> rootObject)
965         : JavaInstance(instance, rootObject)
966     {
967         JNIEnv* env = getJNIEnv();
968         // JavaInstance creates a global ref to instance in its constructor.
969         env->DeleteGlobalRef(_instance->_instance);
970         // Set the object to our WeakReference wrapper.
971         _instance->_instance = adoptGlobalRef(env, instance);
972     }
973 
virtualBegin()974     virtual void virtualBegin() {
975         _weakRef = _instance->_instance;
976         JNIEnv* env = getJNIEnv();
977         // This is odd. getRealObject returns an AutoJObject which is used to
978         // cleanly create and delete a local reference. But, here we need to
979         // maintain the local reference across calls to virtualBegin() and
980         // virtualEnd(). So, release the local reference from the AutoJObject
981         // and delete the local reference in virtualEnd().
982         _realObject = getRealObject(env, _weakRef).release();
983         // Point to the real object
984         _instance->_instance = _realObject;
985         // Call the base class method
986         INHERITED::virtualBegin();
987     }
988 
virtualEnd()989     virtual void virtualEnd() {
990         // Call the base class method first to pop the local frame.
991         INHERITED::virtualEnd();
992         // Get rid of the local reference to the real object.
993         getJNIEnv()->DeleteLocalRef(_realObject);
994         // Point back to the WeakReference.
995         _instance->_instance = _weakRef;
996     }
997 
998 private:
999     typedef JavaInstance INHERITED;
1000     jobject _realObject;
1001     jobject _weakRef;
1002 };
1003 
AddJavascriptInterface(JNIEnv * env,jobject obj,jint nativeFramePointer,jobject javascriptObj,jstring interfaceName)1004 static void AddJavascriptInterface(JNIEnv *env, jobject obj, jint nativeFramePointer,
1005         jobject javascriptObj, jstring interfaceName)
1006 {
1007 #ifdef ANDROID_INSTRUMENT
1008     TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
1009 #endif
1010     WebCore::Frame* pFrame = (WebCore::Frame*)nativeFramePointer;
1011     LOG_ASSERT(pFrame, "nativeAddJavascriptInterface must take a valid frame pointer!");
1012 
1013     JavaVM* vm;
1014     env->GetJavaVM(&vm);
1015     LOGV("::WebCore:: addJSInterface: %p", pFrame);
1016 
1017     // Copied from qwebframe.cpp
1018     JSC::JSLock lock(false);
1019     WebCore::JSDOMWindow *window = WebCore::toJSDOMWindow(pFrame);
1020     JSC::Bindings::RootObject *root = pFrame->script()->bindingRootObject();
1021     if (window) {
1022         JSC::Bindings::setJavaVM(vm);
1023         // Add the binding to JS environment
1024         JSC::ExecState* exec = window->globalExec();
1025         JSC::JSObject *addedObject = WeakJavaInstance::create(javascriptObj,
1026                 root)->createRuntimeObject(exec);
1027         const jchar* s = env->GetStringChars(interfaceName, NULL);
1028         if (s) {
1029             // Add the binding name to the window's table of child objects.
1030             JSC::PutPropertySlot slot;
1031             window->put(exec, JSC::Identifier(exec, (const UChar *)s,
1032                     env->GetStringLength(interfaceName)), addedObject, slot);
1033             env->ReleaseStringChars(interfaceName, s);
1034             checkException(env);
1035         }
1036     }
1037 }
1038 
SetCacheDisabled(JNIEnv * env,jobject obj,jboolean disabled)1039 static void SetCacheDisabled(JNIEnv *env, jobject obj, jboolean disabled)
1040 {
1041 #ifdef ANDROID_INSTRUMENT
1042     TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
1043 #endif
1044     WebCore::cache()->setDisabled(disabled);
1045 }
1046 
CacheDisabled(JNIEnv * env,jobject obj)1047 static jboolean CacheDisabled(JNIEnv *env, jobject obj)
1048 {
1049 #ifdef ANDROID_INSTRUMENT
1050     TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
1051 #endif
1052     return WebCore::cache()->disabled();
1053 }
1054 
ClearCache(JNIEnv * env,jobject obj)1055 static void ClearCache(JNIEnv *env, jobject obj)
1056 {
1057 #ifdef ANDROID_INSTRUMENT
1058     TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
1059 
1060     JSC::JSLock lock(false);
1061     JSC::Heap::Statistics jsHeapStatistics = WebCore::JSDOMWindow::commonJSGlobalData()->heap.statistics();
1062     LOGD("About to gc and JavaScript heap size is %d and has %d bytes free",
1063             jsHeapStatistics.size, jsHeapStatistics.free);
1064     LOGD("About to clear cache and current cache has %d bytes live and %d bytes dead",
1065             cache()->getLiveSize(), cache()->getDeadSize());
1066 #endif
1067     if (!WebCore::cache()->disabled()) {
1068         // Disabling the cache will remove all resources from the cache.  They may
1069         // still live on if they are referenced by some Web page though.
1070         WebCore::cache()->setDisabled(true);
1071         WebCore::cache()->setDisabled(false);
1072     }
1073     // force JavaScript to GC when clear cache
1074     WebCore::gcController().garbageCollectSoon();
1075 }
1076 
DocumentHasImages(JNIEnv * env,jobject obj)1077 static jboolean DocumentHasImages(JNIEnv *env, jobject obj)
1078 {
1079 #ifdef ANDROID_INSTRUMENT
1080     TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
1081 #endif
1082     WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
1083     LOG_ASSERT(pFrame, "DocumentHasImages must take a valid frame pointer!");
1084 
1085     return pFrame->document()->images()->length() > 0;
1086 }
1087 
HasPasswordField(JNIEnv * env,jobject obj)1088 static jboolean HasPasswordField(JNIEnv *env, jobject obj)
1089 {
1090 #ifdef ANDROID_INSTRUMENT
1091     TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
1092 #endif
1093     WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
1094     LOG_ASSERT(pFrame, "HasPasswordField must take a valid frame pointer!");
1095 
1096     bool found = false;
1097     WTF::PassRefPtr<WebCore::HTMLCollection> form = pFrame->document()->forms();
1098     WebCore::Node* node = form->firstItem();
1099     while (node && !found) {
1100         WTF::Vector<WebCore::HTMLFormControlElement*> elements =
1101         		((WebCore::HTMLFormElement*)node)->formElements;
1102         size_t size = elements.size();
1103         for (size_t i = 0; i< size && !found; i++) {
1104             WebCore::HTMLFormControlElement* e = elements[i];
1105             if (e->hasLocalName(WebCore::HTMLNames::inputTag)) {
1106                 if (((WebCore::HTMLInputElement*)e)->inputType() ==
1107                 		WebCore::HTMLInputElement::PASSWORD)
1108                     found = true;
1109             }
1110         }
1111         node = form->nextItem();
1112     }
1113     return found;
1114 }
1115 
GetUsernamePassword(JNIEnv * env,jobject obj)1116 static jobjectArray GetUsernamePassword(JNIEnv *env, jobject obj)
1117 {
1118 #ifdef ANDROID_INSTRUMENT
1119     TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
1120 #endif
1121     WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
1122     LOG_ASSERT(pFrame, "GetUsernamePassword must take a valid frame pointer!");
1123     jobjectArray strArray = NULL;
1124 
1125     WebCore::String username, password;
1126     bool found = false;
1127     WTF::PassRefPtr<WebCore::HTMLCollection> form = pFrame->document()->forms();
1128     WebCore::Node* node = form->firstItem();
1129     while (node && !found) {
1130         WTF::Vector<WebCore::HTMLFormControlElement*> elements =
1131         		((WebCore::HTMLFormElement*)node)->formElements;
1132         size_t size = elements.size();
1133         for (size_t i = 0; i< size && !found; i++) {
1134             WebCore::HTMLFormControlElement* e = elements[i];
1135             if (e->hasLocalName(WebCore::HTMLNames::inputTag)) {
1136                 WebCore::HTMLInputElement* input = (WebCore::HTMLInputElement*)e;
1137                 if (input->autoComplete() == false)
1138                     continue;
1139                 if (input->inputType() == WebCore::HTMLInputElement::PASSWORD)
1140                     password = input->value();
1141                 else if (input->inputType() == WebCore::HTMLInputElement::TEXT)
1142                     username = input->value();
1143                 if (!username.isNull() && !password.isNull())
1144                     found = true;
1145             }
1146         }
1147         node = form->nextItem();
1148     }
1149     if (found) {
1150         jclass stringClass = env->FindClass("java/lang/String");
1151         strArray = env->NewObjectArray(2, stringClass, NULL);
1152         env->SetObjectArrayElement(strArray, 0, env->NewString((unsigned short *)
1153                 username.characters(), username.length()));
1154         env->SetObjectArrayElement(strArray, 1, env->NewString((unsigned short *)
1155                 password.characters(), password.length()));
1156     }
1157     return strArray;
1158 }
1159 
SetUsernamePassword(JNIEnv * env,jobject obj,jstring username,jstring password)1160 static void SetUsernamePassword(JNIEnv *env, jobject obj,
1161     jstring username, jstring password)
1162 {
1163 #ifdef ANDROID_INSTRUMENT
1164     TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
1165 #endif
1166     WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
1167     LOG_ASSERT(pFrame, "SetUsernamePassword must take a valid frame pointer!");
1168 
1169     WebCore::HTMLInputElement* usernameEle = NULL;
1170     WebCore::HTMLInputElement* passwordEle = NULL;
1171     bool found = false;
1172     WTF::PassRefPtr<WebCore::HTMLCollection> form = pFrame->document()->forms();
1173     WebCore::Node* node = form->firstItem();
1174     while (node && !found) {
1175         WTF::Vector<WebCore::HTMLFormControlElement*> elements =
1176         		((WebCore::HTMLFormElement*)node)->formElements;
1177         size_t size = elements.size();
1178         for (size_t i = 0; i< size && !found; i++) {
1179             WebCore::HTMLFormControlElement* e = elements[i];
1180             if (e->hasLocalName(WebCore::HTMLNames::inputTag)) {
1181                 WebCore::HTMLInputElement* input = (WebCore::HTMLInputElement*)e;
1182                 if (input->autoComplete() == false)
1183                     continue;
1184                 if (input->inputType() == WebCore::HTMLInputElement::PASSWORD)
1185                     passwordEle = input;
1186                 else if (input->inputType() == WebCore::HTMLInputElement::TEXT)
1187                     usernameEle = input;
1188                 if (usernameEle != NULL && passwordEle != NULL)
1189                     found = true;
1190             }
1191         }
1192         node = form->nextItem();
1193     }
1194     if (found) {
1195         usernameEle->setValue(to_string(env, username));
1196         passwordEle->setValue(to_string(env, password));
1197     }
1198 }
1199 
GetFormTextData(JNIEnv * env,jobject obj)1200 static jobject GetFormTextData(JNIEnv *env, jobject obj)
1201 {
1202 #ifdef ANDROID_INSTRUMENT
1203     TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
1204 #endif
1205     WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
1206     LOG_ASSERT(pFrame, "GetFormTextData must take a valid frame pointer!");
1207     jobject hashMap = NULL;
1208 
1209     WTF::PassRefPtr<WebCore::HTMLCollection> collection = pFrame->document()->forms();
1210     if (collection->length() > 0) {
1211         jclass mapClass = env->FindClass("java/util/HashMap");
1212         LOG_ASSERT(mapClass, "Could not find HashMap class!");
1213         jmethodID init = env->GetMethodID(mapClass, "<init>", "(I)V");
1214         LOG_ASSERT(init, "Could not find constructor for HashMap");
1215         hashMap = env->NewObject(mapClass, init, 1);
1216         LOG_ASSERT(hashMap, "Could not create a new HashMap");
1217         jmethodID put = env->GetMethodID(mapClass, "put",
1218                 "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
1219         LOG_ASSERT(put, "Could not find put method on HashMap");
1220 
1221         static const WebCore::AtomicString text("text");
1222         static const WebCore::AtomicString off("off");
1223 
1224         WebCore::HTMLFormElement* form;
1225         WebCore::HTMLInputElement* input;
1226         for (WebCore::Node* node = collection->firstItem(); node; node = collection->nextItem()) {
1227             form = static_cast<WebCore::HTMLFormElement*>(node);
1228             if (form->autoComplete()) {
1229                 WTF::Vector<WebCore::HTMLFormControlElement*> elements = form->formElements;
1230                 size_t size = elements.size();
1231                 for (size_t i = 0; i < size; i++) {
1232                     WebCore::HTMLFormControlElement* e = elements[i];
1233                     if (e->type() == text) {
1234                         if (e->hasAttribute(WebCore::HTMLNames::autocompleteAttr)) {
1235                             const WebCore::AtomicString& attr = e->getAttribute(WebCore::HTMLNames::autocompleteAttr);
1236                             if (attr == off)
1237                                 continue;
1238                         }
1239                         input = (WebCore::HTMLInputElement*) e;
1240                         WebCore::String value = input->value();
1241                         int len = value.length();
1242                         if (len) {
1243                             const WebCore::AtomicString& name = input->name();
1244                             jstring key = env->NewString((jchar *)name.characters(), name.length());
1245                             jstring val = env->NewString((jchar *)value.characters(), len);
1246                             LOG_ASSERT(key && val, "name or value not set");
1247                             env->CallObjectMethod(hashMap, put, key, val);
1248                             env->DeleteLocalRef(key);
1249                             env->DeleteLocalRef(val);
1250                         }
1251                     }
1252                 }
1253             }
1254         }
1255         env->DeleteLocalRef(mapClass);
1256 
1257     }
1258     return hashMap;
1259 }
1260 
1261 // ----------------------------------------------------------------------------
1262 
1263 /*
1264  * JNI registration.
1265  */
1266 static JNINativeMethod gBrowserFrameNativeMethods[] = {
1267     /* name, signature, funcPtr */
1268     { "nativeCallPolicyFunction", "(II)V",
1269         (void*) CallPolicyFunction },
1270     { "nativeCreateFrame", "(Landroid/webkit/WebViewCore;Landroid/content/res/AssetManager;Landroid/webkit/WebBackForwardList;)V",
1271         (void*) CreateFrame },
1272     { "nativeDestroyFrame", "()V",
1273         (void*) DestroyFrame },
1274     { "nativeStopLoading", "()V",
1275         (void*) StopLoading },
1276     { "nativeLoadUrl", "(Ljava/lang/String;)V",
1277         (void*) LoadUrl },
1278     { "nativePostUrl", "(Ljava/lang/String;[B)V",
1279         (void*) PostUrl },
1280     { "nativeLoadData", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V",
1281         (void*) LoadData },
1282     { "externalRepresentation", "()Ljava/lang/String;",
1283         (void*) ExternalRepresentation },
1284     { "documentAsText", "()Ljava/lang/String;",
1285         (void*) DocumentAsText },
1286     { "reload", "(Z)V",
1287         (void*) Reload },
1288     { "nativeGoBackOrForward", "(I)V",
1289         (void*) GoBackOrForward },
1290     { "nativeAddJavascriptInterface", "(ILjava/lang/Object;Ljava/lang/String;)V",
1291         (void*) AddJavascriptInterface },
1292     { "stringByEvaluatingJavaScriptFromString",
1293             "(Ljava/lang/String;)Ljava/lang/String;",
1294         (void*) StringByEvaluatingJavaScriptFromString },
1295     { "setCacheDisabled", "(Z)V",
1296         (void*) SetCacheDisabled },
1297     { "cacheDisabled", "()Z",
1298         (void*) CacheDisabled },
1299     { "clearCache", "()V",
1300         (void*) ClearCache },
1301     { "documentHasImages", "()Z",
1302         (void*) DocumentHasImages },
1303     { "hasPasswordField", "()Z",
1304         (void*) HasPasswordField },
1305     { "getUsernamePassword", "()[Ljava/lang/String;",
1306         (void*) GetUsernamePassword },
1307     { "setUsernamePassword", "(Ljava/lang/String;Ljava/lang/String;)V",
1308         (void*) SetUsernamePassword },
1309     { "getFormTextData", "()Ljava/util/HashMap;",
1310         (void*) GetFormTextData }
1311 };
1312 
register_webframe(JNIEnv * env)1313 int register_webframe(JNIEnv* env)
1314 {
1315     jclass clazz = env->FindClass("android/webkit/BrowserFrame");
1316     LOG_ASSERT(clazz, "Cannot find BrowserFrame");
1317     gFrameField = env->GetFieldID(clazz, "mNativeFrame", "I");
1318     LOG_ASSERT(gFrameField, "Cannot find mNativeFrame on BrowserFrame");
1319 
1320     return jniRegisterNativeMethods(env, "android/webkit/BrowserFrame",
1321             gBrowserFrameNativeMethods, NELEM(gBrowserFrameNativeMethods));
1322 }
1323 
1324 } /* namespace android */
1325 
1326