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