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