1 /*
2 * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21 #include "config.h"
22 #include "Chrome.h"
23
24 #include "ChromeClient.h"
25 #include "DNS.h"
26 #include "Document.h"
27 #include "FileList.h"
28 #include "FloatRect.h"
29 #include "Frame.h"
30 #include "FrameTree.h"
31 #include "HTMLFormElement.h"
32 #include "HTMLInputElement.h"
33 #include "HTMLNames.h"
34 #include "HitTestResult.h"
35 #include "InspectorController.h"
36 #include "Page.h"
37 #include "PageGroup.h"
38 #include "ResourceHandle.h"
39 #include "ScriptController.h"
40 #include "SecurityOrigin.h"
41 #include "Settings.h"
42 #include "WindowFeatures.h"
43 #include <wtf/PassRefPtr.h>
44 #include <wtf/RefPtr.h>
45 #include <wtf/Vector.h>
46
47 #if ENABLE(DOM_STORAGE)
48 #include "SessionStorage.h"
49 #endif
50
51 namespace WebCore {
52
53 using namespace HTMLNames;
54 using namespace std;
55
56 class PageGroupLoadDeferrer : Noncopyable {
57 public:
58 PageGroupLoadDeferrer(Page*, bool deferSelf);
59 ~PageGroupLoadDeferrer();
60 private:
61 Vector<RefPtr<Frame>, 16> m_deferredFrames;
62 };
63
Chrome(Page * page,ChromeClient * client)64 Chrome::Chrome(Page* page, ChromeClient* client)
65 : m_page(page)
66 , m_client(client)
67 {
68 ASSERT(m_client);
69 }
70
~Chrome()71 Chrome::~Chrome()
72 {
73 m_client->chromeDestroyed();
74 }
75
repaint(const IntRect & windowRect,bool contentChanged,bool immediate,bool repaintContentOnly)76 void Chrome::repaint(const IntRect& windowRect, bool contentChanged, bool immediate, bool repaintContentOnly)
77 {
78 m_client->repaint(windowRect, contentChanged, immediate, repaintContentOnly);
79 }
80
scroll(const IntSize & scrollDelta,const IntRect & rectToScroll,const IntRect & clipRect)81 void Chrome::scroll(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect)
82 {
83 m_client->scroll(scrollDelta, rectToScroll, clipRect);
84 }
85
screenToWindow(const IntPoint & point) const86 IntPoint Chrome::screenToWindow(const IntPoint& point) const
87 {
88 return m_client->screenToWindow(point);
89 }
90
windowToScreen(const IntRect & rect) const91 IntRect Chrome::windowToScreen(const IntRect& rect) const
92 {
93 return m_client->windowToScreen(rect);
94 }
95
platformWindow() const96 PlatformWidget Chrome::platformWindow() const
97 {
98 return m_client->platformWindow();
99 }
100
contentsSizeChanged(Frame * frame,const IntSize & size) const101 void Chrome::contentsSizeChanged(Frame* frame, const IntSize& size) const
102 {
103 m_client->contentsSizeChanged(frame, size);
104 }
105
scrollRectIntoView(const IntRect & rect,const ScrollView * scrollView) const106 void Chrome::scrollRectIntoView(const IntRect& rect, const ScrollView* scrollView) const
107 {
108 m_client->scrollRectIntoView(rect, scrollView);
109 }
110
setWindowRect(const FloatRect & rect) const111 void Chrome::setWindowRect(const FloatRect& rect) const
112 {
113 m_client->setWindowRect(rect);
114 }
115
windowRect() const116 FloatRect Chrome::windowRect() const
117 {
118 return m_client->windowRect();
119 }
120
pageRect() const121 FloatRect Chrome::pageRect() const
122 {
123 return m_client->pageRect();
124 }
125
scaleFactor()126 float Chrome::scaleFactor()
127 {
128 return m_client->scaleFactor();
129 }
130
focus() const131 void Chrome::focus() const
132 {
133 m_client->focus();
134 }
135
unfocus() const136 void Chrome::unfocus() const
137 {
138 m_client->unfocus();
139 }
140
canTakeFocus(FocusDirection direction) const141 bool Chrome::canTakeFocus(FocusDirection direction) const
142 {
143 return m_client->canTakeFocus(direction);
144 }
145
takeFocus(FocusDirection direction) const146 void Chrome::takeFocus(FocusDirection direction) const
147 {
148 m_client->takeFocus(direction);
149 }
150
createWindow(Frame * frame,const FrameLoadRequest & request,const WindowFeatures & features) const151 Page* Chrome::createWindow(Frame* frame, const FrameLoadRequest& request, const WindowFeatures& features) const
152 {
153 Page* newPage = m_client->createWindow(frame, request, features);
154 #if ENABLE(DOM_STORAGE)
155
156 if (newPage) {
157 if (SessionStorage* oldSessionStorage = m_page->sessionStorage(false))
158 newPage->setSessionStorage(oldSessionStorage->copy(newPage));
159 }
160 #endif
161 return newPage;
162 }
163
show() const164 void Chrome::show() const
165 {
166 m_client->show();
167 }
168
canRunModal() const169 bool Chrome::canRunModal() const
170 {
171 return m_client->canRunModal();
172 }
173
canRunModalNow() const174 bool Chrome::canRunModalNow() const
175 {
176 // If loads are blocked, we can't run modal because the contents
177 // of the modal dialog will never show up!
178 return canRunModal() && !ResourceHandle::loadsBlocked();
179 }
180
runModal() const181 void Chrome::runModal() const
182 {
183 // Defer callbacks in all the other pages in this group, so we don't try to run JavaScript
184 // in a way that could interact with this view.
185 PageGroupLoadDeferrer deferrer(m_page, false);
186
187 TimerBase::fireTimersInNestedEventLoop();
188 m_client->runModal();
189 }
190
setToolbarsVisible(bool b) const191 void Chrome::setToolbarsVisible(bool b) const
192 {
193 m_client->setToolbarsVisible(b);
194 }
195
toolbarsVisible() const196 bool Chrome::toolbarsVisible() const
197 {
198 return m_client->toolbarsVisible();
199 }
200
setStatusbarVisible(bool b) const201 void Chrome::setStatusbarVisible(bool b) const
202 {
203 m_client->setStatusbarVisible(b);
204 }
205
statusbarVisible() const206 bool Chrome::statusbarVisible() const
207 {
208 return m_client->statusbarVisible();
209 }
210
setScrollbarsVisible(bool b) const211 void Chrome::setScrollbarsVisible(bool b) const
212 {
213 m_client->setScrollbarsVisible(b);
214 }
215
scrollbarsVisible() const216 bool Chrome::scrollbarsVisible() const
217 {
218 return m_client->scrollbarsVisible();
219 }
220
setMenubarVisible(bool b) const221 void Chrome::setMenubarVisible(bool b) const
222 {
223 m_client->setMenubarVisible(b);
224 }
225
menubarVisible() const226 bool Chrome::menubarVisible() const
227 {
228 return m_client->menubarVisible();
229 }
230
setResizable(bool b) const231 void Chrome::setResizable(bool b) const
232 {
233 m_client->setResizable(b);
234 }
235
canRunBeforeUnloadConfirmPanel()236 bool Chrome::canRunBeforeUnloadConfirmPanel()
237 {
238 return m_client->canRunBeforeUnloadConfirmPanel();
239 }
240
runBeforeUnloadConfirmPanel(const String & message,Frame * frame)241 bool Chrome::runBeforeUnloadConfirmPanel(const String& message, Frame* frame)
242 {
243 // Defer loads in case the client method runs a new event loop that would
244 // otherwise cause the load to continue while we're in the middle of executing JavaScript.
245 PageGroupLoadDeferrer deferrer(m_page, true);
246
247 return m_client->runBeforeUnloadConfirmPanel(message, frame);
248 }
249
closeWindowSoon()250 void Chrome::closeWindowSoon()
251 {
252 m_client->closeWindowSoon();
253 }
254
runJavaScriptAlert(Frame * frame,const String & message)255 void Chrome::runJavaScriptAlert(Frame* frame, const String& message)
256 {
257 // Defer loads in case the client method runs a new event loop that would
258 // otherwise cause the load to continue while we're in the middle of executing JavaScript.
259 PageGroupLoadDeferrer deferrer(m_page, true);
260
261 ASSERT(frame);
262 m_client->runJavaScriptAlert(frame, frame->displayStringModifiedByEncoding(message));
263 }
264
runJavaScriptConfirm(Frame * frame,const String & message)265 bool Chrome::runJavaScriptConfirm(Frame* frame, const String& message)
266 {
267 // Defer loads in case the client method runs a new event loop that would
268 // otherwise cause the load to continue while we're in the middle of executing JavaScript.
269 PageGroupLoadDeferrer deferrer(m_page, true);
270
271 ASSERT(frame);
272 return m_client->runJavaScriptConfirm(frame, frame->displayStringModifiedByEncoding(message));
273 }
274
runJavaScriptPrompt(Frame * frame,const String & prompt,const String & defaultValue,String & result)275 bool Chrome::runJavaScriptPrompt(Frame* frame, const String& prompt, const String& defaultValue, String& result)
276 {
277 // Defer loads in case the client method runs a new event loop that would
278 // otherwise cause the load to continue while we're in the middle of executing JavaScript.
279 PageGroupLoadDeferrer deferrer(m_page, true);
280
281 ASSERT(frame);
282 bool ok = m_client->runJavaScriptPrompt(frame, frame->displayStringModifiedByEncoding(prompt), frame->displayStringModifiedByEncoding(defaultValue), result);
283
284 if (ok)
285 result = frame->displayStringModifiedByEncoding(result);
286
287 return ok;
288 }
289
setStatusbarText(Frame * frame,const String & status)290 void Chrome::setStatusbarText(Frame* frame, const String& status)
291 {
292 ASSERT(frame);
293 m_client->setStatusbarText(frame->displayStringModifiedByEncoding(status));
294 }
295
shouldInterruptJavaScript()296 bool Chrome::shouldInterruptJavaScript()
297 {
298 // Defer loads in case the client method runs a new event loop that would
299 // otherwise cause the load to continue while we're in the middle of executing JavaScript.
300 PageGroupLoadDeferrer deferrer(m_page, true);
301
302 return m_client->shouldInterruptJavaScript();
303 }
304
windowResizerRect() const305 IntRect Chrome::windowResizerRect() const
306 {
307 return m_client->windowResizerRect();
308 }
309
mouseDidMoveOverElement(const HitTestResult & result,unsigned modifierFlags)310 void Chrome::mouseDidMoveOverElement(const HitTestResult& result, unsigned modifierFlags)
311 {
312 if (result.innerNode()) {
313 Document* document = result.innerNode()->document();
314 if (document && document->isDNSPrefetchEnabled())
315 prefetchDNS(result.absoluteLinkURL().host());
316 }
317 m_client->mouseDidMoveOverElement(result, modifierFlags);
318
319 if (InspectorController* inspector = m_page->inspectorController())
320 inspector->mouseDidMoveOverElement(result, modifierFlags);
321 }
322
setToolTip(const HitTestResult & result)323 void Chrome::setToolTip(const HitTestResult& result)
324 {
325 // First priority is a potential toolTip representing a spelling or grammar error
326 String toolTip = result.spellingToolTip();
327
328 // Next priority is a toolTip from a URL beneath the mouse (if preference is set to show those).
329 if (toolTip.isEmpty() && m_page->settings()->showsURLsInToolTips()) {
330 if (Node* node = result.innerNonSharedNode()) {
331 // Get tooltip representing form action, if relevant
332 if (node->hasTagName(inputTag)) {
333 HTMLInputElement* input = static_cast<HTMLInputElement*>(node);
334 if (input->inputType() == HTMLInputElement::SUBMIT)
335 if (HTMLFormElement* form = input->form())
336 toolTip = form->action();
337 }
338 }
339
340 // Get tooltip representing link's URL
341 if (toolTip.isEmpty())
342 // FIXME: Need to pass this URL through userVisibleString once that's in WebCore
343 toolTip = result.absoluteLinkURL().string();
344 }
345
346 // Next we'll consider a tooltip for element with "title" attribute
347 if (toolTip.isEmpty())
348 toolTip = result.title();
349
350 // Lastly, for <input type="file"> that allow multiple files, we'll consider a tooltip for the selected filenames
351 if (toolTip.isEmpty()) {
352 if (Node* node = result.innerNonSharedNode()) {
353 if (node->hasTagName(inputTag)) {
354 HTMLInputElement* input = static_cast<HTMLInputElement*>(node);
355 if (input->inputType() == HTMLInputElement::FILE) {
356 FileList* files = input->files();
357 unsigned listSize = files->length();
358 if (files && listSize > 1) {
359 Vector<UChar> names;
360 for (size_t i = 0; i < listSize; ++i) {
361 append(names, files->item(i)->fileName());
362 if (i != listSize - 1)
363 names.append('\n');
364 }
365 toolTip = String::adopt(names);
366 }
367 }
368 }
369 }
370 }
371
372 m_client->setToolTip(toolTip);
373 }
374
print(Frame * frame)375 void Chrome::print(Frame* frame)
376 {
377 m_client->print(frame);
378 }
379
disableSuddenTermination()380 void Chrome::disableSuddenTermination()
381 {
382 m_client->disableSuddenTermination();
383 }
384
enableSuddenTermination()385 void Chrome::enableSuddenTermination()
386 {
387 m_client->enableSuddenTermination();
388 }
389
runOpenPanel(Frame * frame,PassRefPtr<FileChooser> fileChooser)390 void Chrome::runOpenPanel(Frame* frame, PassRefPtr<FileChooser> fileChooser)
391 {
392 m_client->runOpenPanel(frame, fileChooser);
393 }
394 // --------
395
396 #if ENABLE(DASHBOARD_SUPPORT)
dashboardRegionsChanged()397 void ChromeClient::dashboardRegionsChanged()
398 {
399 }
400 #endif
401
populateVisitedLinks()402 void ChromeClient::populateVisitedLinks()
403 {
404 }
405
customHighlightRect(Node *,const AtomicString &,const FloatRect &)406 FloatRect ChromeClient::customHighlightRect(Node*, const AtomicString&, const FloatRect&)
407 {
408 return FloatRect();
409 }
410
paintCustomHighlight(Node *,const AtomicString &,const FloatRect &,const FloatRect &,bool,bool)411 void ChromeClient::paintCustomHighlight(Node*, const AtomicString&, const FloatRect&, const FloatRect&, bool, bool)
412 {
413 }
414
shouldReplaceWithGeneratedFileForUpload(const String &,String &)415 bool ChromeClient::shouldReplaceWithGeneratedFileForUpload(const String&, String&)
416 {
417 return false;
418 }
419
generateReplacementFile(const String &)420 String ChromeClient::generateReplacementFile(const String&)
421 {
422 ASSERT_NOT_REACHED();
423 return String();
424 }
425
disableSuddenTermination()426 void ChromeClient::disableSuddenTermination()
427 {
428 }
429
enableSuddenTermination()430 void ChromeClient::enableSuddenTermination()
431 {
432 }
433
paintCustomScrollbar(GraphicsContext *,const FloatRect &,ScrollbarControlSize,ScrollbarControlState,ScrollbarPart,bool,float,float,ScrollbarControlPartMask)434 bool ChromeClient::paintCustomScrollbar(GraphicsContext*, const FloatRect&, ScrollbarControlSize,
435 ScrollbarControlState, ScrollbarPart, bool,
436 float, float, ScrollbarControlPartMask)
437 {
438 return false;
439 }
440
paintCustomScrollCorner(GraphicsContext *,const FloatRect &)441 bool ChromeClient::paintCustomScrollCorner(GraphicsContext*, const FloatRect&)
442 {
443 return false;
444 }
445
446 // --------
447
PageGroupLoadDeferrer(Page * page,bool deferSelf)448 PageGroupLoadDeferrer::PageGroupLoadDeferrer(Page* page, bool deferSelf)
449 {
450 const HashSet<Page*>& pages = page->group().pages();
451
452 HashSet<Page*>::const_iterator end = pages.end();
453 for (HashSet<Page*>::const_iterator it = pages.begin(); it != end; ++it) {
454 Page* otherPage = *it;
455 if ((deferSelf || otherPage != page)) {
456 if (!otherPage->defersLoading())
457 m_deferredFrames.append(otherPage->mainFrame());
458
459 #if !PLATFORM(MAC)
460 for (Frame* frame = otherPage->mainFrame(); frame; frame = frame->tree()->traverseNext()) {
461 if (Document* document = frame->document())
462 document->suspendActiveDOMObjects();
463 }
464 #endif
465 }
466 }
467
468 size_t count = m_deferredFrames.size();
469 for (size_t i = 0; i < count; ++i)
470 if (Page* page = m_deferredFrames[i]->page())
471 page->setDefersLoading(true);
472 }
473
~PageGroupLoadDeferrer()474 PageGroupLoadDeferrer::~PageGroupLoadDeferrer()
475 {
476 for (size_t i = 0; i < m_deferredFrames.size(); ++i) {
477 if (Page* page = m_deferredFrames[i]->page()) {
478 page->setDefersLoading(false);
479
480 #if !PLATFORM(MAC)
481 for (Frame* frame = page->mainFrame(); frame; frame = frame->tree()->traverseNext()) {
482 if (Document* document = frame->document())
483 document->resumeActiveDOMObjects();
484 }
485 #endif
486 }
487 }
488 }
489
490
491 } // namespace WebCore
492