1 /*
2 * Copyright 2007, 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 #define LOG_TAG "WebCore"
26
27 #include "config.h"
28
29 #include "android_graphics.h"
30 #include "CString.h"
31 #include "DocumentLoader.h"
32 #include "DOMImplementation.h"
33 #include "Frame.h"
34 #include "FrameLoader.h"
35 #include "FrameLoaderClientAndroid.h"
36 #include "FrameTree.h"
37 #include "GraphicsContext.h"
38 #include "HTMLFrameOwnerElement.h"
39 #include "HTMLPlugInElement.h"
40 #include "IconDatabase.h"
41 #include "MIMETypeRegistry.h"
42 #include "NotImplemented.h"
43 #include "Page.h"
44 #include "PlatformGraphicsContext.h"
45 #include "PlatformString.h"
46 #include "PluginDatabase.h"
47 #include "PluginView.h"
48 #include "ProgressTracker.h"
49 #include "RenderPart.h"
50 #include "ResourceError.h"
51 #include "SelectionController.h"
52 #include "SkCanvas.h"
53 #include "SkRect.h"
54 #include "TextEncoding.h"
55 #include "Document.h"
56 #include "FrameView.h"
57 #include "HistoryItem.h"
58 #include "ResourceHandle.h"
59 #include "ResourceHandleInternal.h"
60 #include "WebCoreFrameBridge.h"
61 #include "WebCoreResourceLoader.h"
62 #include "WebHistory.h"
63 #include "WebIconDatabase.h"
64 #include "WebFrameView.h"
65 #include "WebViewCore.h"
66 #include "Settings.h"
67
68 #include <utils/AssetManager.h>
69
70 extern android::AssetManager* globalAssetManager();
71
72 namespace android {
73
74 static const int EXTRA_LAYOUT_DELAY = 1000;
75
FrameLoaderClientAndroid(WebFrame * webframe)76 FrameLoaderClientAndroid::FrameLoaderClientAndroid(WebFrame* webframe)
77 : m_frame(NULL)
78 , m_webFrame(webframe) {
79 Retain(m_webFrame);
80 }
81
get(const WebCore::Frame * frame)82 FrameLoaderClientAndroid* FrameLoaderClientAndroid::get(const WebCore::Frame* frame)
83 {
84 return static_cast<FrameLoaderClientAndroid*> (frame->loader()->client());
85 }
86
frameLoaderDestroyed()87 void FrameLoaderClientAndroid::frameLoaderDestroyed() {
88 registerForIconNotification(false);
89 m_frame = 0;
90 Release(m_webFrame);
91 delete this;
92 }
93
hasWebView() const94 bool FrameLoaderClientAndroid::hasWebView() const {
95 // FIXME,
96 // there is one web view per page, or top frame.
97 // as android's view is created from Java side, it is always there.
98 return true;
99 }
100
makeRepresentation(DocumentLoader *)101 void FrameLoaderClientAndroid::makeRepresentation(DocumentLoader*) {
102 // don't use representation
103 verifiedOk();
104 }
105
forceLayout()106 void FrameLoaderClientAndroid::forceLayout() {
107 ASSERT(m_frame);
108 m_frame->view()->forceLayout();
109 // FIXME, should we adjust view size here?
110 m_frame->view()->adjustViewSize();
111 }
112
forceLayoutForNonHTML()113 void FrameLoaderClientAndroid::forceLayoutForNonHTML() {
114 notImplemented();
115 }
116
setCopiesOnScroll()117 void FrameLoaderClientAndroid::setCopiesOnScroll() {
118 // this is a hint about whether we need to force redraws, or can
119 // just copy the scrolled content. Since we always force a redraw
120 // anyways, we can ignore this call.
121 verifiedOk();
122 }
123
detachedFromParent2()124 void FrameLoaderClientAndroid::detachedFromParent2() {
125 // FIXME, ready to detach frame from view
126 }
127
detachedFromParent3()128 void FrameLoaderClientAndroid::detachedFromParent3() {
129 // FIXME, ready to release view
130 notImplemented();
131 }
132
133 // This function is responsible for associating the "id" with a given
134 // subresource load. The following functions that accept an "id" are
135 // called for each subresource, so they should not be dispatched to the m_frame.
assignIdentifierToInitialRequest(unsigned long id,DocumentLoader *,const ResourceRequest &)136 void FrameLoaderClientAndroid::assignIdentifierToInitialRequest(unsigned long id,
137 DocumentLoader*, const ResourceRequest&) {
138 lowPriority_notImplemented();
139 }
140
dispatchWillSendRequest(DocumentLoader *,unsigned long id,ResourceRequest &,const ResourceResponse &)141 void FrameLoaderClientAndroid::dispatchWillSendRequest(DocumentLoader*, unsigned long id,
142 ResourceRequest&, const ResourceResponse&) {
143 lowPriority_notImplemented();
144 }
145
shouldUseCredentialStorage(DocumentLoader *,unsigned long identifier)146 bool FrameLoaderClientAndroid::shouldUseCredentialStorage(DocumentLoader*, unsigned long identifier)
147 {
148 notImplemented();
149 return false;
150 }
151
dispatchDidReceiveAuthenticationChallenge(DocumentLoader *,unsigned long id,const AuthenticationChallenge &)152 void FrameLoaderClientAndroid::dispatchDidReceiveAuthenticationChallenge(DocumentLoader*,
153 unsigned long id, const AuthenticationChallenge&) {
154 lowPriority_notImplemented();
155 }
156
dispatchDidCancelAuthenticationChallenge(DocumentLoader *,unsigned long id,const AuthenticationChallenge &)157 void FrameLoaderClientAndroid::dispatchDidCancelAuthenticationChallenge(DocumentLoader*,
158 unsigned long id, const AuthenticationChallenge&) {
159 lowPriority_notImplemented();
160 }
161
dispatchDidReceiveResponse(DocumentLoader *,unsigned long id,const ResourceResponse &)162 void FrameLoaderClientAndroid::dispatchDidReceiveResponse(DocumentLoader*,
163 unsigned long id, const ResourceResponse&) {
164 lowPriority_notImplemented();
165 }
166
dispatchDidReceiveContentLength(DocumentLoader *,unsigned long id,int lengthReceived)167 void FrameLoaderClientAndroid::dispatchDidReceiveContentLength(DocumentLoader*,
168 unsigned long id, int lengthReceived) {
169 lowPriority_notImplemented();
170 }
171
dispatchDidFinishLoading(DocumentLoader *,unsigned long id)172 void FrameLoaderClientAndroid::dispatchDidFinishLoading(DocumentLoader*,
173 unsigned long id) {
174 lowPriority_notImplemented();
175 }
176
dispatchDidFailLoading(DocumentLoader * docLoader,unsigned long id,const ResourceError &)177 void FrameLoaderClientAndroid::dispatchDidFailLoading(DocumentLoader* docLoader,
178 unsigned long id, const ResourceError&) {
179 lowPriority_notImplemented();
180 }
181
dispatchDidLoadResourceFromMemoryCache(DocumentLoader *,const ResourceRequest &,const ResourceResponse &,int length)182 bool FrameLoaderClientAndroid::dispatchDidLoadResourceFromMemoryCache(DocumentLoader*,
183 const ResourceRequest&, const ResourceResponse&, int length) {
184 notImplemented();
185 return false;
186 }
187
dispatchDidLoadResourceByXMLHttpRequest(unsigned long identifier,const ScriptString &)188 void FrameLoaderClientAndroid::dispatchDidLoadResourceByXMLHttpRequest(unsigned long identifier, const ScriptString&) {
189 return;
190 }
191
dispatchDidHandleOnloadEvents()192 void FrameLoaderClientAndroid::dispatchDidHandleOnloadEvents() {
193 }
194
dispatchDidReceiveServerRedirectForProvisionalLoad()195 void FrameLoaderClientAndroid::dispatchDidReceiveServerRedirectForProvisionalLoad() {
196 ASSERT(m_frame);
197 // Tell the load it was a redirect.
198 m_webFrame->loadStarted(m_frame);
199 }
200
dispatchDidCancelClientRedirect()201 void FrameLoaderClientAndroid::dispatchDidCancelClientRedirect() {
202 notImplemented();
203 }
204
dispatchWillPerformClientRedirect(const KURL &,double interval,double fireDate)205 void FrameLoaderClientAndroid::dispatchWillPerformClientRedirect(const KURL&,
206 double interval, double fireDate) {
207 notImplemented();
208 }
209
dispatchDidChangeLocationWithinPage()210 void FrameLoaderClientAndroid::dispatchDidChangeLocationWithinPage() {
211 notImplemented();
212 }
213
dispatchWillClose()214 void FrameLoaderClientAndroid::dispatchWillClose() {
215 notImplemented();
216 }
217
dispatchDidReceiveIcon()218 void FrameLoaderClientAndroid::dispatchDidReceiveIcon() {
219 ASSERT(m_frame);
220 if (m_frame->tree() && m_frame->tree()->parent())
221 return;
222 WebCore::String url(m_frame->loader()->url().string());
223 // Try to obtain the icon image.
224 WebCore::Image* icon = WebCore::iconDatabase()->iconForPageURL(
225 url, WebCore::IntSize(16, 16));
226 // If the request fails, try the original request url.
227 if (!icon) {
228 DocumentLoader* docLoader = m_frame->loader()->activeDocumentLoader();
229 KURL originalURL = docLoader->originalRequest().url();
230 icon = WebCore::iconDatabase()->iconForPageURL(
231 originalURL, WebCore::IntSize(16, 16));
232 }
233 // There is a bug in webkit where cancelling an icon load is treated as a
234 // failure. When this is fixed, we can ASSERT again that we have an icon.
235 if (icon) {
236 LOGV("Received icon (%p) for %s", icon,
237 url.utf8().data());
238 m_webFrame->didReceiveIcon(icon);
239 } else {
240 LOGV("Icon data for %s unavailable, registering for notification...",
241 url.utf8().data());
242 registerForIconNotification();
243 }
244 }
245
dispatchDidReceiveTouchIconURL(const String & url,bool precomposed)246 void FrameLoaderClientAndroid::dispatchDidReceiveTouchIconURL(const String& url, bool precomposed) {
247 ASSERT(m_frame);
248 // Do not report sub frame touch icons
249 if (m_frame->tree() && m_frame->tree()->parent())
250 return;
251 m_webFrame->didReceiveTouchIconURL(url, precomposed);
252 }
253
dispatchDidStartProvisionalLoad()254 void FrameLoaderClientAndroid::dispatchDidStartProvisionalLoad() {
255 notImplemented();
256 }
257
dispatchDidReceiveTitle(const String & title)258 void FrameLoaderClientAndroid::dispatchDidReceiveTitle(const String& title) {
259 ASSERT(m_frame);
260 // Used to check for FrameLoadTypeStandard but we only want to send the title for
261 // the top frame and not sub-frames.
262 if (!m_frame->tree() || !m_frame->tree()->parent()) {
263 m_webFrame->setTitle(title);
264 }
265 }
266
dispatchDidCommitLoad()267 void FrameLoaderClientAndroid::dispatchDidCommitLoad() {
268 verifiedOk();
269 }
270
loadDataIntoFrame(Frame * frame,KURL baseUrl,const String & url,const String & data)271 static void loadDataIntoFrame(Frame* frame, KURL baseUrl, const String& url,
272 const String& data) {
273 if (baseUrl.isEmpty()) {
274 baseUrl = blankURL();
275 }
276 ResourceRequest request(baseUrl);
277 CString cstr = data.utf8();
278 RefPtr<WebCore::SharedBuffer> buf = WebCore::SharedBuffer::create(cstr.data(), cstr.length());
279 SubstituteData subData(buf, String("text/html"), String("utf-8"),
280 KURL(KURL(), url));
281 frame->loader()->load(request, subData, false);
282 }
283
dispatchDidFailProvisionalLoad(const ResourceError & error)284 void FrameLoaderClientAndroid::dispatchDidFailProvisionalLoad(const ResourceError& error) {
285 ASSERT(m_frame);
286 // Ignore ErrorInterrupted since it is due to a policy interruption. This
287 // is caused by a decision to download the main resource rather than
288 // display it.
289 if (error.errorCode() == InternalErrorInterrupted
290 || error.errorCode() == InternalErrorCancelled) {
291 // If we decided to download the main resource or if the user cancelled
292 // it, make sure we report that the load is done.
293 didFinishLoad();
294 return;
295 }
296
297 AssetManager* am = globalAssetManager();
298
299 // Check to see if the error code was not generated internally
300 WebFrame::RAW_RES_ID id = WebFrame::NODOMAIN;
301 if ((error.errorCode() == ErrorFile ||
302 error.errorCode() == ErrorFileNotFound) &&
303 (!error.localizedDescription().isEmpty())) {
304 id = WebFrame::LOADERROR;
305 }
306 String filename = m_webFrame->getRawResourceFilename(id);
307 if (filename.isEmpty())
308 return;
309
310 // Grab the error page from the asset manager
311 Asset* a = am->openNonAsset(
312 filename.utf8().data(), Asset::ACCESS_BUFFER);
313 if (!a)
314 return;
315
316 // Take the failing url and encode html entities so javascript urls are not
317 // executed.
318 CString failingUrl = error.failingURL().utf8();
319 WTF::Vector<char> url;
320 int len = failingUrl.length();
321 const char* data = failingUrl.data();
322 for (int i = 0; i < len; i++) {
323 char c = data[i];
324 if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
325 || (c >= '0' && c <= '9'))
326 url.append(c);
327 else {
328 char buf[16];
329 int res = sprintf(buf, "&#%d;", c);
330 buf[res] = 0;
331 url.append(buf, res);
332 }
333 }
334
335 // Replace all occurances of %s with the failing url.
336 String s = UTF8Encoding().decode((const char*)a->getBuffer(false), a->getLength());
337 s = s.replace("%s", String(url.data(), url.size()));
338
339 // Replace all occurances of %e with the error text
340 s = s.replace("%e", error.localizedDescription());
341
342 // Create the request and the substitute data and tell the FrameLoader to
343 // load with the replacement data.
344 // use KURL(const char*) as KURL(const String& url) can trigger ASSERT for
345 // invalidate URL string.
346 loadDataIntoFrame(m_frame, KURL(data), error.failingURL(), s);
347
348 // Delete the asset.
349 delete a;
350 }
351
dispatchDidFailLoad(const ResourceError &)352 void FrameLoaderClientAndroid::dispatchDidFailLoad(const ResourceError&) {
353 // called when page is completed with error
354 didFinishLoad();
355 }
356
dispatchDidFinishDocumentLoad()357 void FrameLoaderClientAndroid::dispatchDidFinishDocumentLoad() {
358 // called when finishedParsing
359 lowPriority_notImplemented();
360 }
361
dispatchDidFinishLoad()362 void FrameLoaderClientAndroid::dispatchDidFinishLoad() {
363 didFinishLoad();
364 }
365
dispatchDidFirstLayout()366 void FrameLoaderClientAndroid::dispatchDidFirstLayout() {
367 ASSERT(m_frame);
368 m_frame->document()->setExtraLayoutDelay(EXTRA_LAYOUT_DELAY);
369 // we need to do this here instead of dispatchDidFirstVisuallyNonEmptyLayout
370 // so that about:blank will update the screen.
371 if (!m_frame->tree()->parent()) {
372 // Only need to notify Java side for the top frame
373 WebViewCore::getWebViewCore(m_frame->view())->didFirstLayout();
374 }
375 }
376
dispatchDidFirstVisuallyNonEmptyLayout()377 void FrameLoaderClientAndroid::dispatchDidFirstVisuallyNonEmptyLayout()
378 {
379 notImplemented();
380 }
381
dispatchCreatePage()382 Frame* FrameLoaderClientAndroid::dispatchCreatePage() {
383 ASSERT(m_frame);
384 #ifdef ANDROID_MULTIPLE_WINDOWS
385 if (m_frame->settings() && m_frame->settings()->supportMultipleWindows())
386 // Always a user gesture since window.open maps to
387 // ChromeClientAndroid::createWindow
388 return m_webFrame->createWindow(false, true);
389 else
390 #endif
391 // If the client doesn't support multiple windows, just replace the
392 // current frame's contents.
393 return m_frame;
394 }
395
dispatchShow()396 void FrameLoaderClientAndroid::dispatchShow() {
397 ASSERT(m_frame);
398 m_frame->view()->invalidate();
399 }
400
401
TreatAsAttachment(const String & content_disposition)402 static bool TreatAsAttachment(const String& content_disposition) {
403 // Some broken sites just send
404 // Content-Disposition: ; filename="file"
405 // screen those out here.
406 if (content_disposition.startsWith(";"))
407 return false;
408
409 if (content_disposition.startsWith("inline", false))
410 return false;
411
412 // Some broken sites just send
413 // Content-Disposition: filename="file"
414 // without a disposition token... screen those out.
415 if (content_disposition.startsWith("filename", false))
416 return false;
417
418 // Also in use is Content-Disposition: name="file"
419 if (content_disposition.startsWith("name", false))
420 return false;
421
422 // We have a content-disposition of "attachment" or unknown.
423 // RFC 2183, section 2.8 says that an unknown disposition
424 // value should be treated as "attachment"
425 return true;
426 }
427
dispatchDecidePolicyForMIMEType(FramePolicyFunction func,const String & MIMEType,const ResourceRequest & request)428 void FrameLoaderClientAndroid::dispatchDecidePolicyForMIMEType(FramePolicyFunction func,
429 const String& MIMEType, const ResourceRequest& request) {
430 ASSERT(m_frame);
431 ASSERT(func);
432 if (!func)
433 return;
434 if (request.isNull()) {
435 (m_frame->loader()->*func)(PolicyIgnore);
436 return;
437 }
438 // Default to Use (display internally).
439 PolicyAction action = PolicyUse;
440 // Check if we should Download instead.
441 const ResourceResponse& response = m_frame->loader()->activeDocumentLoader()->response();
442 const String& content_disposition = response.httpHeaderField("Content-Disposition");
443 if (!content_disposition.isEmpty()) {
444 // Server wants to override our normal policy.
445 if (TreatAsAttachment(content_disposition)) {
446 // Check to see if we are a sub frame (main frame has no owner element)
447 if (m_frame->ownerElement() != 0)
448 action = PolicyIgnore;
449 else
450 action = PolicyDownload;
451 }
452 } else {
453 // Ask if it can be handled internally.
454 if (!canShowMIMEType(MIMEType)) {
455 // Check to see if we are a sub frame (main frame has no owner element)
456 if (m_frame->ownerElement() != 0)
457 action = PolicyIgnore;
458 else
459 action = PolicyDownload;
460 }
461 }
462 // A status code of 204 indicates no content change. Ignore the result.
463 WebCore::DocumentLoader* docLoader = m_frame->loader()->activeDocumentLoader();
464 if (docLoader->response().httpStatusCode() == 204)
465 action = PolicyIgnore;
466 (m_frame->loader()->*func)(action);
467 }
468
dispatchDecidePolicyForNewWindowAction(FramePolicyFunction func,const NavigationAction & action,const ResourceRequest & request,PassRefPtr<FormState> formState,const String & frameName)469 void FrameLoaderClientAndroid::dispatchDecidePolicyForNewWindowAction(FramePolicyFunction func,
470 const NavigationAction& action, const ResourceRequest& request,
471 PassRefPtr<FormState> formState, const String& frameName) {
472 ASSERT(m_frame);
473 ASSERT(func);
474 if (!func)
475 return;
476
477 if (request.isNull()) {
478 (m_frame->loader()->*func)(PolicyIgnore);
479 return;
480 }
481
482 if (action.type() == NavigationTypeFormSubmitted || action.type() == NavigationTypeFormResubmitted)
483 m_frame->loader()->resetMultipleFormSubmissionProtection();
484
485 // If we get to this point it means that a link has a target that was not
486 // found by the frame tree. Instead of creating a new frame, return the
487 // current frame in dispatchCreatePage.
488 if (canHandleRequest(request))
489 (m_frame->loader()->*func)(PolicyUse);
490 else
491 (m_frame->loader()->*func)(PolicyIgnore);
492 }
493
cancelPolicyCheck()494 void FrameLoaderClientAndroid::cancelPolicyCheck() {
495 lowPriority_notImplemented();
496 }
497
dispatchUnableToImplementPolicy(const ResourceError &)498 void FrameLoaderClientAndroid::dispatchUnableToImplementPolicy(const ResourceError&) {
499 notImplemented();
500 }
501
dispatchDecidePolicyForNavigationAction(FramePolicyFunction func,const NavigationAction & action,const ResourceRequest & request,PassRefPtr<FormState> formState)502 void FrameLoaderClientAndroid::dispatchDecidePolicyForNavigationAction(FramePolicyFunction func,
503 const NavigationAction& action, const ResourceRequest& request,
504 PassRefPtr<FormState> formState) {
505 ASSERT(m_frame);
506 ASSERT(func);
507 if (!func)
508 return;
509 if (request.isNull()) {
510 (m_frame->loader()->*func)(PolicyIgnore);
511 return;
512 }
513
514 // Reset multiple form submission protection. If this is a resubmission, we check with the
515 // user and reset the protection if they choose to resubmit the form (see WebCoreFrameBridge.cpp)
516 if (action.type() == NavigationTypeFormSubmitted)
517 m_frame->loader()->resetMultipleFormSubmissionProtection();
518
519 if (action.type() == NavigationTypeFormResubmitted) {
520 m_webFrame->decidePolicyForFormResubmission(func);
521 return;
522 } else {
523 (m_frame->loader()->*func)(PolicyUse);
524 }
525 }
526
dispatchWillSubmitForm(FramePolicyFunction func,PassRefPtr<FormState>)527 void FrameLoaderClientAndroid::dispatchWillSubmitForm(FramePolicyFunction func, PassRefPtr<FormState>) {
528 ASSERT(m_frame);
529 ASSERT(func);
530 (m_frame->loader()->*func)(PolicyUse);
531 }
532
dispatchDidLoadMainResource(DocumentLoader *)533 void FrameLoaderClientAndroid::dispatchDidLoadMainResource(DocumentLoader*) {
534 notImplemented();
535 }
536
revertToProvisionalState(DocumentLoader *)537 void FrameLoaderClientAndroid::revertToProvisionalState(DocumentLoader*) {
538 notImplemented();
539 }
540
setMainDocumentError(DocumentLoader * docLoader,const ResourceError & error)541 void FrameLoaderClientAndroid::setMainDocumentError(DocumentLoader* docLoader, const ResourceError& error) {
542 ASSERT(m_frame);
543 if (!error.isNull() && error.errorCode() >= InternalErrorLast)
544 m_webFrame->reportError(error.errorCode(),
545 error.localizedDescription(), error.failingURL());
546 }
547
548 // This function is called right before the progress is updated.
willChangeEstimatedProgress()549 void FrameLoaderClientAndroid::willChangeEstimatedProgress() {
550 verifiedOk();
551 }
552
553 // This function is called after the progress has been updated. The bad part
554 // about this is that when a page is completed, this function is called after
555 // the progress has been reset to 0.
didChangeEstimatedProgress()556 void FrameLoaderClientAndroid::didChangeEstimatedProgress() {
557 verifiedOk();
558 }
559
560 // This will give us the initial estimate when the page first starts to load.
postProgressStartedNotification()561 void FrameLoaderClientAndroid::postProgressStartedNotification() {
562 ASSERT(m_frame);
563 if (m_frame->page())
564 m_webFrame->setProgress(m_frame->page()->progress()->estimatedProgress());
565 }
566
567 // This will give us any updated progress including the final progress.
postProgressEstimateChangedNotification()568 void FrameLoaderClientAndroid::postProgressEstimateChangedNotification() {
569 ASSERT(m_frame);
570 if (m_frame->page())
571 m_webFrame->setProgress(m_frame->page()->progress()->estimatedProgress());
572 }
573
574 // This is just a notification that the progress has finished. Don't call
575 // setProgress(1) because postProgressEstimateChangedNotification will do so.
postProgressFinishedNotification()576 void FrameLoaderClientAndroid::postProgressFinishedNotification() {
577 WebViewCore* core = WebViewCore::getWebViewCore(m_frame->view());
578 if (!m_frame->tree()->parent()) {
579 // only need to notify Java for the top frame
580 core->notifyProgressFinished();
581 }
582 // notify plugins that the frame has loaded
583 core->notifyPluginsOnFrameLoad(m_frame);
584 }
585
setMainFrameDocumentReady(bool)586 void FrameLoaderClientAndroid::setMainFrameDocumentReady(bool) {
587 // this is only interesting once we provide an external API for the DOM
588 notImplemented();
589 }
590
startDownload(const ResourceRequest &)591 void FrameLoaderClientAndroid::startDownload(const ResourceRequest&) {
592 notImplemented();
593 }
594
willChangeTitle(DocumentLoader *)595 void FrameLoaderClientAndroid::willChangeTitle(DocumentLoader*) {
596 verifiedOk();
597 }
598
didChangeTitle(DocumentLoader * loader)599 void FrameLoaderClientAndroid::didChangeTitle(DocumentLoader* loader) {
600 verifiedOk();
601 }
602
finishedLoading(DocumentLoader * docLoader)603 void FrameLoaderClientAndroid::finishedLoading(DocumentLoader* docLoader) {
604 // Telling the frame we received some data and passing 0 as the data is our
605 // way to get work done that is normally done when the first bit of data is
606 // received, even for the case of a document with no data (like about:blank)
607 committedLoad(docLoader, 0, 0);
608 }
609
updateGlobalHistory()610 void FrameLoaderClientAndroid::updateGlobalHistory() {
611 ASSERT(m_frame);
612
613 DocumentLoader* docLoader = m_frame->loader()->documentLoader();
614 ASSERT(docLoader);
615
616 // Code copied from FrameLoader.cpp:createHistoryItem
617 // Only add this URL to the database if it is a valid page
618 if (docLoader->unreachableURL().isEmpty()
619 && docLoader->response().httpStatusCode() < 400) {
620 m_webFrame->updateVisitedHistory(docLoader->urlForHistory(), false);
621 if (!docLoader->serverRedirectSourceForHistory().isNull())
622 m_webFrame->updateVisitedHistory(KURL(docLoader->serverRedirectDestinationForHistory()), false);
623 }
624 }
625
updateGlobalHistoryRedirectLinks()626 void FrameLoaderClientAndroid::updateGlobalHistoryRedirectLinks() {
627 // Note, do we need to do anything where there is no HistoryItem? If we call
628 // updateGlobalHistory(), we will add bunch of "data:xxx" urls for gmail.com
629 // which is not what we want. Opt to do nothing now.
630 }
631
shouldGoToHistoryItem(HistoryItem * item) const632 bool FrameLoaderClientAndroid::shouldGoToHistoryItem(HistoryItem* item) const {
633 // hmmm, seems like we might do a more thoughtful check
634 ASSERT(m_frame);
635 return item != NULL;
636 }
637
committedLoad(DocumentLoader * loader,const char * data,int length)638 void FrameLoaderClientAndroid::committedLoad(DocumentLoader* loader, const char* data, int length) {
639 ASSERT(m_frame);
640 String encoding = loader->overrideEncoding();
641 bool userChosen = !encoding.isNull();
642 if (encoding.isNull())
643 encoding = loader->response().textEncodingName();
644 loader->frameLoader()->setEncoding(encoding, userChosen);
645 Document *doc = m_frame->document();
646 if (doc) {
647 loader->frameLoader()->addData(data, length);
648 }
649 }
650
cancelledError(const ResourceRequest & request)651 ResourceError FrameLoaderClientAndroid::cancelledError(const ResourceRequest& request) {
652 return ResourceError(String(), InternalErrorCancelled, request.url(), String());
653 }
654
cannotShowURLError(const ResourceRequest & request)655 ResourceError FrameLoaderClientAndroid::cannotShowURLError(const ResourceRequest& request) {
656 return ResourceError(String(), InternalErrorCannotShowUrl, request.url(), String());
657 }
658
interruptForPolicyChangeError(const ResourceRequest & request)659 ResourceError FrameLoaderClientAndroid::interruptForPolicyChangeError(const ResourceRequest& request) {
660 return ResourceError(String(), InternalErrorInterrupted, request.url(), String());
661 }
662
cannotShowMIMETypeError(const ResourceResponse & request)663 ResourceError FrameLoaderClientAndroid::cannotShowMIMETypeError(const ResourceResponse& request) {
664 return ResourceError(String(), InternalErrorCannotShowMimeType, request.url(), String());
665 }
666
fileDoesNotExistError(const ResourceResponse & request)667 ResourceError FrameLoaderClientAndroid::fileDoesNotExistError(const ResourceResponse& request) {
668 return ResourceError(String(), InternalErrorFileDoesNotExist, request.url(), String());
669 }
670
pluginWillHandleLoadError(const ResourceResponse & request)671 ResourceError FrameLoaderClientAndroid::pluginWillHandleLoadError(const ResourceResponse& request) {
672 return ResourceError(String(), InternalErrorPluginWillHandleLoadError, request.url(), String());
673 }
674
shouldFallBack(const ResourceError &)675 bool FrameLoaderClientAndroid::shouldFallBack(const ResourceError&) {
676 notImplemented();
677 return false;
678 }
679
canHandleRequest(const ResourceRequest & request) const680 bool FrameLoaderClientAndroid::canHandleRequest(const ResourceRequest& request) const {
681 ASSERT(m_frame);
682 // Don't allow hijacking of intrapage navigation
683 if (WebCore::equalIgnoringFragmentIdentifier(request.url(), m_frame->loader()->url()))
684 return true;
685
686 // Don't allow hijacking of iframe urls that are http or https
687 if (request.url().protocol().startsWith("http", false) &&
688 m_frame->tree() && m_frame->tree()->parent())
689 return true;
690
691 return m_webFrame->canHandleRequest(request);
692 }
693
canShowMIMEType(const String & mimeType) const694 bool FrameLoaderClientAndroid::canShowMIMEType(const String& mimeType) const {
695 // FIXME: This looks like it has to do with whether or not a type can be
696 // shown "internally" (i.e. inside the browser) regardless of whether
697 // or not the browser is doing the rendering, e.g. a full page plugin.
698 if (MIMETypeRegistry::isSupportedImageResourceMIMEType(mimeType) ||
699 MIMETypeRegistry::isSupportedNonImageMIMEType(mimeType) ||
700 MIMETypeRegistry::isSupportedJavaScriptMIMEType(mimeType) ||
701 PluginDatabase::installedPlugins()->isMIMETypeRegistered(mimeType) ||
702 DOMImplementation::isTextMIMEType(mimeType) ||
703 DOMImplementation::isXMLMIMEType(mimeType))
704 return true;
705 return false;
706 }
707
representationExistsForURLScheme(const String &) const708 bool FrameLoaderClientAndroid::representationExistsForURLScheme(const String&) const {
709 // don't use representation
710 verifiedOk();
711 return false;
712 }
713
generatedMIMETypeForURLScheme(const String & URLScheme) const714 String FrameLoaderClientAndroid::generatedMIMETypeForURLScheme(const String& URLScheme) const {
715 // FIXME, copy from Apple's port
716 String mimetype("x-apple-web-kit/");
717 mimetype.append(URLScheme.lower());
718 return mimetype;
719 }
720
frameLoadCompleted()721 void FrameLoaderClientAndroid::frameLoadCompleted() {
722 // copied from Apple port, without this back with sub-frame will trigger ASSERT
723 ASSERT(m_frame);
724 }
725
saveViewStateToItem(HistoryItem * item)726 void FrameLoaderClientAndroid::saveViewStateToItem(HistoryItem* item) {
727 #ifdef ANDROID_HISTORY_CLIENT
728 ASSERT(m_frame);
729 ASSERT(item);
730 // We should have added a bridge when the child item was added to its
731 // parent.
732 WebHistoryItem* bridge = item->bridge();
733 ASSERT(bridge);
734 // store the current scale (only) for the top frame
735 if (!m_frame->tree()->parent()) {
736 WebViewCore* webViewCore = WebViewCore::getWebViewCore(m_frame->view());
737 bridge->setScale((int)(webViewCore->scale() * 100));
738 bridge->setScreenWidthScale((int)(webViewCore->screenWidthScale() * 100));
739 }
740
741 WebCore::notifyHistoryItemChanged(item);
742 #endif
743 }
744
restoreViewState()745 void FrameLoaderClientAndroid::restoreViewState() {
746 #ifdef ANDROID_HISTORY_CLIENT
747 WebViewCore* webViewCore = WebViewCore::getWebViewCore(m_frame->view());
748 HistoryItem* item = m_frame->loader()->currentHistoryItem();
749 // restore the scale (only) for the top frame
750 if (!m_frame->tree()->parent()) {
751 int scale = item->bridge()->scale();
752 webViewCore->restoreScale(scale);
753 int screenWidthScale = item->bridge()->screenWidthScale();
754 if (screenWidthScale != scale)
755 webViewCore->restoreScreenWidthScale(screenWidthScale);
756 }
757 #endif
758 }
759
760 #ifdef ANDROID_HISTORY_CLIENT
dispatchDidAddHistoryItem(HistoryItem * item) const761 void FrameLoaderClientAndroid::dispatchDidAddHistoryItem(HistoryItem* item) const {
762 ASSERT(m_frame);
763 m_webFrame->addHistoryItem(item);
764 }
765
dispatchDidRemoveHistoryItem(HistoryItem * item,int index) const766 void FrameLoaderClientAndroid::dispatchDidRemoveHistoryItem(HistoryItem* item, int index) const {
767 ASSERT(m_frame);
768 m_webFrame->removeHistoryItem(index);
769 }
770
dispatchDidChangeHistoryIndex(BackForwardList * list) const771 void FrameLoaderClientAndroid::dispatchDidChangeHistoryIndex(
772 BackForwardList* list) const {
773 ASSERT(m_frame);
774 m_webFrame->updateHistoryIndex(list->backListCount());
775 }
776 #endif
777
provisionalLoadStarted()778 void FrameLoaderClientAndroid::provisionalLoadStarted() {
779 ASSERT(m_frame);
780 m_webFrame->loadStarted(m_frame);
781 }
782
didFinishLoad()783 void FrameLoaderClientAndroid::didFinishLoad() {
784 ASSERT(m_frame);
785 m_frame->document()->setExtraLayoutDelay(0);
786 m_webFrame->didFinishLoad(m_frame);
787 }
788
prepareForDataSourceReplacement()789 void FrameLoaderClientAndroid::prepareForDataSourceReplacement() {
790 verifiedOk();
791 }
792
createDocumentLoader(const ResourceRequest & request,const SubstituteData & data)793 PassRefPtr<DocumentLoader> FrameLoaderClientAndroid::createDocumentLoader(
794 const ResourceRequest& request, const SubstituteData& data) {
795 RefPtr<DocumentLoader> loader = DocumentLoader::create(request, data);
796 return loader.release();
797 }
798
setTitle(const String & title,const KURL & url)799 void FrameLoaderClientAndroid::setTitle(const String& title, const KURL& url) {
800 // Not needed. dispatchDidReceiveTitle is called immediately after this.
801 // url is used to update the Apple port history items.
802 verifiedOk();
803 }
804
userAgent(const KURL & u)805 String FrameLoaderClientAndroid::userAgent(const KURL& u) {
806 return m_webFrame->userAgentForURL(&u);
807 }
808
savePlatformDataToCachedFrame(WebCore::CachedFrame *)809 void FrameLoaderClientAndroid::savePlatformDataToCachedFrame(WebCore::CachedFrame*) {
810 notImplemented();
811 }
812
transitionToCommittedFromCachedFrame(WebCore::CachedFrame *)813 void FrameLoaderClientAndroid::transitionToCommittedFromCachedFrame(WebCore::CachedFrame*) {
814 notImplemented();
815 }
816
transitionToCommittedForNewPage()817 void FrameLoaderClientAndroid::transitionToCommittedForNewPage() {
818 ASSERT(m_frame);
819
820 #ifdef ANDROID_META_SUPPORT
821 // reset metadata settings for the main frame as they are not preserved cross page
822 if (m_frame == m_frame->page()->mainFrame() && m_frame->settings())
823 m_frame->settings()->resetMetadataSettings();
824 #endif
825
826 if (m_frame->settings() && !m_frame->settings()->usesPageCache()) {
827 m_webFrame->transitionToCommitted(m_frame);
828 return;
829 }
830
831 // Remember the old WebFrameView
832 WebFrameView* webFrameView = static_cast<WebFrameView*> (
833 m_frame->view()->platformWidget());
834 Retain(webFrameView);
835
836 // Remove the old FrameView
837 m_frame->setView(NULL);
838
839 // Create a new FrameView and associate it with the saved webFrameView
840 RefPtr<FrameView> view = FrameView::create(m_frame);
841 webFrameView->setView(view.get());
842
843 Release(webFrameView);
844
845 // Give the new FrameView to the Frame
846 m_frame->setView(view);
847
848 if (m_frame->ownerRenderer())
849 m_frame->ownerRenderer()->setWidget(view.get());
850
851 m_frame->view()->initScrollbars();
852
853 m_webFrame->transitionToCommitted(m_frame);
854 }
855
canCachePage() const856 bool FrameLoaderClientAndroid::canCachePage() const {
857 return true;
858 }
859
download(ResourceHandle * handle,const ResourceRequest &,const ResourceRequest &,const ResourceResponse &)860 void FrameLoaderClientAndroid::download(ResourceHandle* handle, const ResourceRequest&,
861 const ResourceRequest&, const ResourceResponse&) {
862 // Get the C++ side of the load listener and tell it to handle the download
863 WebCoreResourceLoader* loader = handle->getInternal()->m_loader;
864 loader->downloadFile();
865 }
866
createFrame(const KURL & url,const String & name,HTMLFrameOwnerElement * ownerElement,const String & referrer,bool allowsScrolling,int marginWidth,int marginHeight)867 WTF::PassRefPtr<WebCore::Frame> FrameLoaderClientAndroid::createFrame(const KURL& url, const String& name,
868 HTMLFrameOwnerElement* ownerElement, const String& referrer,
869 bool allowsScrolling, int marginWidth, int marginHeight)
870 {
871 Frame* parent = ownerElement->document()->frame();
872 FrameLoaderClientAndroid* loaderC = new FrameLoaderClientAndroid(m_webFrame);
873 RefPtr<Frame> pFrame = Frame::create(parent->page(), ownerElement, loaderC);
874 Frame* newFrame = pFrame.get();
875 loaderC->setFrame(newFrame);
876 // Append the subframe to the parent and set the name of the subframe. The name must be set after
877 // appending the child so that the name becomes unique.
878 parent->tree()->appendChild(newFrame);
879 newFrame->tree()->setName(name);
880 // Create a new FrameView and WebFrameView for the child frame to draw into.
881 RefPtr<FrameView> frameView = FrameView::create(newFrame);
882 WebFrameView* webFrameView = new WebFrameView(frameView.get(),
883 WebViewCore::getWebViewCore(parent->view()));
884 // frameView Retains webFrameView, so call Release for webFrameView
885 Release(webFrameView);
886 // Attach the frameView to the newFrame.
887 newFrame->setView(frameView);
888 newFrame->init();
889 newFrame->selection()->setFocused(true);
890 LOGV("::WebCore:: createSubFrame returning %p", newFrame);
891
892 // The creation of the frame may have run arbitrary JavaScript that removed it from the page already.
893 if (!pFrame->page())
894 return 0;
895
896 parent->loader()->loadURLIntoChildFrame(url, referrer, pFrame.get());
897
898 // onLoad may cuase the frame to be removed from the document. Allow the RefPtr to delete the child frame.
899 if (!pFrame->tree()->parent())
900 return NULL;
901
902 return pFrame.release();
903 }
904
905 // YouTube flash url path starts with /v/
906 static const char slash_v_slash[] = { '/', 'v', '/' };
907
isValidYouTubeVideo(const String & path)908 static bool isValidYouTubeVideo(const String& path)
909 {
910 if (!charactersAreAllASCII(path.characters(), path.length()))
911 return false;
912 unsigned int len = path.length();
913 if (len <= sizeof(slash_v_slash)) // check for more than just /v/
914 return false;
915 CString str = path.lower().utf8();
916 const char* data = str.data();
917 if (memcmp(data, slash_v_slash, sizeof(slash_v_slash)) != 0)
918 return false;
919 // Start after /v/
920 for (unsigned int i = sizeof(slash_v_slash); i < len; i++) {
921 char c = data[i];
922 // Check for alpha-numeric characters only.
923 if (WTF::isASCIIAlphanumeric(c) || c == '_' || c == '-')
924 continue;
925 // The url can have more parameters such as &hl=en after the video id.
926 // Once we start seeing extra parameters we can return true.
927 return c == '&' && i > sizeof(slash_v_slash);
928 }
929 return true;
930 }
931
isYouTubeUrl(const KURL & url,const String & mimeType)932 static bool isYouTubeUrl(const KURL& url, const String& mimeType)
933 {
934 String host = url.host();
935 bool youtube = host.endsWith("youtube.com")
936 || host.endsWith("youtube-nocookie.com");
937 return youtube && isValidYouTubeVideo(url.path())
938 && equalIgnoringCase(mimeType, "application/x-shockwave-flash");
939 }
940
createPlugin(const IntSize & size,HTMLPlugInElement * element,const KURL & url,const WTF::Vector<String> & names,const WTF::Vector<String> & values,const String & mimeType,bool loadManually)941 WTF::PassRefPtr<Widget> FrameLoaderClientAndroid::createPlugin(
942 const IntSize& size,
943 HTMLPlugInElement* element,
944 const KURL& url,
945 const WTF::Vector<String>& names,
946 const WTF::Vector<String>& values,
947 const String& mimeType,
948 bool loadManually) {
949 // Create an iframe for youtube urls.
950 if (isYouTubeUrl(url, mimeType)) {
951 WTF::RefPtr<Frame> frame = createFrame(blankURL(), String(), element,
952 String(), false, 0, 0);
953 if (frame) {
954 // grab everything after /v/
955 String videoId = url.path().substring(sizeof(slash_v_slash));
956 // Extract just the video id
957 unsigned videoIdEnd = 0;
958 for (; videoIdEnd < videoId.length(); videoIdEnd++) {
959 if (videoId[videoIdEnd] == '&') {
960 videoId = videoId.left(videoIdEnd);
961 break;
962 }
963 }
964 AssetManager* am = globalAssetManager();
965 Asset* a = am->open("webkit/youtube.html",
966 Asset::ACCESS_BUFFER);
967 if (!a)
968 return NULL;
969 String s = String((const char*)a->getBuffer(false), a->getLength());
970 s = s.replace("VIDEO_ID", videoId);
971 delete a;
972 loadDataIntoFrame(frame.get(),
973 KURL("file:///android_asset/webkit/"), String(), s);
974 // Transfer ownership to a local refptr.
975 WTF::RefPtr<Widget> widget(frame->view());
976 return widget.release();
977 }
978 return NULL;
979 }
980 #ifdef ANDROID_PLUGINS
981 return PluginView::create(m_frame,
982 size,
983 element,
984 url,
985 names,
986 values,
987 mimeType,
988 loadManually);
989 #else
990 return NULL;
991 #endif
992 }
993
redirectDataToPlugin(Widget * pluginWidget)994 void FrameLoaderClientAndroid::redirectDataToPlugin(Widget* pluginWidget) {
995 // don't support plugin yet
996 notImplemented();
997 }
998
createJavaAppletWidget(const IntSize &,HTMLAppletElement *,const KURL & baseURL,const WTF::Vector<String> & paramNames,const WTF::Vector<String> & paramValues)999 WTF::PassRefPtr<Widget> FrameLoaderClientAndroid::createJavaAppletWidget(const IntSize&, HTMLAppletElement*,
1000 const KURL& baseURL, const WTF::Vector<String>& paramNames,
1001 const WTF::Vector<String>& paramValues) {
1002 // don't support widget yet
1003 notImplemented();
1004 return 0;
1005 }
1006
1007 // This function is used by the <OBJECT> element to determine the type of
1008 // the contents and work out if it can render it.
objectContentType(const KURL & url,const String & mimeType)1009 ObjectContentType FrameLoaderClientAndroid::objectContentType(const KURL& url,
1010 const String& mimeType) {
1011 if (mimeType.length() == 0)
1012 {
1013 // Guess the mimeType from the extension
1014 if (url.hasPath())
1015 {
1016 String path = url.path();
1017 int lastIndex = path.reverseFind('.');
1018 static const String image("image/");
1019 if (lastIndex >= 0)
1020 {
1021 String mime(path.substring(lastIndex + 1));
1022 mime.insert(image, 0);
1023 if (Image::supportsType(mime))
1024 return ObjectContentImage;
1025 }
1026 }
1027 return ObjectContentFrame;
1028 }
1029
1030 if (Image::supportsType(mimeType))
1031 return ObjectContentImage;
1032
1033 if (PluginDatabase::installedPlugins()->isMIMETypeRegistered(mimeType))
1034 return ObjectContentOtherPlugin;
1035
1036 if (MIMETypeRegistry::isSupportedNonImageMIMEType(mimeType))
1037 return ObjectContentFrame;
1038
1039 return ObjectContentNone;
1040 }
1041
1042 // This function allows the application to set the correct CSS media
1043 // style. Android could use it to set the media style 'handheld'. Safari
1044 // may use it to set the media style to 'print' when the user wants to print
1045 // a particular web page.
overrideMediaType() const1046 String FrameLoaderClientAndroid::overrideMediaType() const {
1047 lowPriority_notImplemented();
1048 return String();
1049 }
1050
1051 // This function is used to re-attach Javascript<->native code classes.
windowObjectCleared()1052 void FrameLoaderClientAndroid::windowObjectCleared() {
1053 ASSERT(m_frame);
1054 LOGV("::WebCore:: windowObjectCleared called on frame %p for %s\n",
1055 m_frame, m_frame->loader()->url().string().ascii().data());
1056 m_webFrame->windowObjectCleared(m_frame);
1057 }
1058
documentElementAvailable()1059 void FrameLoaderClientAndroid::documentElementAvailable() {
1060 }
1061
1062 // functions new to Jun-07 tip of tree merge:
blockedError(ResourceRequest const & request)1063 ResourceError FrameLoaderClientAndroid::blockedError(ResourceRequest const& request) {
1064 return ResourceError(String(), InternalErrorFileDoesNotExist, String(), String());
1065 }
1066
1067 // functions new to Nov-07 tip of tree merge:
didPerformFirstNavigation() const1068 void FrameLoaderClientAndroid::didPerformFirstNavigation() const {
1069 // This seems to be just a notification that the UI can listen to, to
1070 // know if the user has performed first navigation action.
1071 // It is called from
1072 // void FrameLoader::addBackForwardItemClippedAtTarget(bool doClip)
1073 // "Navigation" here means a transition from one page to another that
1074 // ends up in the back/forward list.
1075 }
1076
registerForIconNotification(bool listen)1077 void FrameLoaderClientAndroid::registerForIconNotification(bool listen) {
1078 if (listen)
1079 WebIconDatabase::RegisterForIconNotification(this);
1080 else
1081 WebIconDatabase::UnregisterForIconNotification(this);
1082 }
1083
1084 // This is the WebIconDatabaseClient method for receiving a notification when we
1085 // get the icon for the page.
didAddIconForPageUrl(const String & pageUrl)1086 void FrameLoaderClientAndroid::didAddIconForPageUrl(const String& pageUrl) {
1087 // This call must happen before dispatchDidReceiveIcon since that method
1088 // may register for icon notifications again since the icon data may have
1089 // to be read from disk.
1090 registerForIconNotification(false);
1091 KURL u(pageUrl);
1092 if (equalIgnoringFragmentIdentifier(u, m_frame->loader()->url())) {
1093 dispatchDidReceiveIcon();
1094 }
1095 }
1096
1097 }
1098