Replace static_casts with to* functions for document types.
[WebKit-https.git] / Source / WebCore / page / Frame.cpp
1 /*
2  * Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
3  *                     1999 Lars Knoll <knoll@kde.org>
4  *                     1999 Antti Koivisto <koivisto@kde.org>
5  *                     2000 Simon Hausmann <hausmann@kde.org>
6  *                     2000 Stefan Schimanski <1Stein@gmx.de>
7  *                     2001 George Staikos <staikos@kde.org>
8  * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
9  * Copyright (C) 2005 Alexey Proskuryakov <ap@nypop.com>
10  * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
11  * Copyright (C) 2008 Eric Seidel <eric@webkit.org>
12  * Copyright (C) 2008 Google Inc.
13  *
14  * This library is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU Library General Public
16  * License as published by the Free Software Foundation; either
17  * version 2 of the License, or (at your option) any later version.
18  *
19  * This library is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22  * Library General Public License for more details.
23  *
24  * You should have received a copy of the GNU Library General Public License
25  * along with this library; see the file COPYING.LIB.  If not, write to
26  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
27  * Boston, MA 02110-1301, USA.
28  */
29
30 #include "config.h"
31 #include "Frame.h"
32
33 #include "ApplyStyleCommand.h"
34 #include "BackForwardController.h"
35 #include "CSSComputedStyleDeclaration.h"
36 #include "CSSPropertyNames.h"
37 #include "CachedCSSStyleSheet.h"
38 #include "Chrome.h"
39 #include "ChromeClient.h"
40 #include "DOMWindow.h"
41 #include "CachedResourceLoader.h"
42 #include "DocumentType.h"
43 #include "EditorClient.h"
44 #include "Event.h"
45 #include "EventNames.h"
46 #include "FloatQuad.h"
47 #include "FocusController.h"
48 #include "FrameDestructionObserver.h"
49 #include "FrameLoader.h"
50 #include "FrameLoaderClient.h"
51 #include "FrameView.h"
52 #include "GraphicsContext.h"
53 #include "GraphicsLayer.h"
54 #include "HTMLDocument.h"
55 #include "HTMLFormControlElement.h"
56 #include "HTMLFormElement.h"
57 #include "HTMLFrameElementBase.h"
58 #include "HTMLNames.h"
59 #include "HTMLTableCellElement.h"
60 #include "HitTestResult.h"
61 #include "ImageBuffer.h"
62 #include "InspectorInstrumentation.h"
63 #include "Logging.h"
64 #include "MediaFeatureNames.h"
65 #include "Navigator.h"
66 #include "NodeList.h"
67 #include "NodeTraversal.h"
68 #include "Page.h"
69 #include "PageCache.h"
70 #include "PageGroup.h"
71 #include "RegularExpression.h"
72 #include "RenderPart.h"
73 #include "RenderTableCell.h"
74 #include "RenderTextControl.h"
75 #include "RenderTheme.h"
76 #include "RenderView.h"
77 #include "RuntimeEnabledFeatures.h"
78 #include "ScriptController.h"
79 #include "ScriptSourceCode.h"
80 #include "ScriptValue.h"
81 #include "ScrollingCoordinator.h"
82 #include "Settings.h"
83 #include "StylePropertySet.h"
84 #include "TextIterator.h"
85 #include "TextResourceDecoder.h"
86 #include "UserContentURLPattern.h"
87 #include "UserTypingGestureIndicator.h"
88 #include "VisibleUnits.h"
89 #include "WebKitFontFamilyNames.h"
90 #include "XMLNSNames.h"
91 #include "XMLNames.h"
92 #include "htmlediting.h"
93 #include "markup.h"
94 #include "npruntime_impl.h"
95 #include <wtf/PassOwnPtr.h>
96 #include <wtf/RefCountedLeakCounter.h>
97 #include <wtf/StdLibExtras.h>
98
99 #if USE(ACCELERATED_COMPOSITING)
100 #include "RenderLayerCompositor.h"
101 #endif
102
103 #if USE(JSC)
104 #include "JSDOMWindowShell.h"
105 #include "runtime_root.h"
106 #endif
107
108 #include "MathMLNames.h"
109 #include "SVGNames.h"
110 #include "XLinkNames.h"
111
112 #if ENABLE(SVG)
113 #include "SVGDocument.h"
114 #include "SVGDocumentExtensions.h"
115 #endif
116
117 #if USE(TILED_BACKING_STORE)
118 #include "TiledBackingStore.h"
119 #endif
120
121 using namespace std;
122
123 namespace WebCore {
124
125 using namespace HTMLNames;
126
127 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, frameCounter, ("Frame"));
128
129 static inline Frame* parentFromOwnerElement(HTMLFrameOwnerElement* ownerElement)
130 {
131     if (!ownerElement)
132         return 0;
133     return ownerElement->document()->frame();
134 }
135
136 static inline float parentPageZoomFactor(Frame* frame)
137 {
138     Frame* parent = frame->tree()->parent();
139     if (!parent)
140         return 1;
141     return parent->pageZoomFactor();
142 }
143
144 static inline float parentTextZoomFactor(Frame* frame)
145 {
146     Frame* parent = frame->tree()->parent();
147     if (!parent)
148         return 1;
149     return parent->textZoomFactor();
150 }
151
152 inline Frame::Frame(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* frameLoaderClient)
153     : m_page(page)
154     , m_treeNode(this, parentFromOwnerElement(ownerElement))
155     , m_loader(this, frameLoaderClient)
156     , m_navigationScheduler(this)
157     , m_ownerElement(ownerElement)
158     , m_script(this)
159     , m_editor(this)
160     , m_selection(this)
161     , m_eventHandler(this)
162     , m_animationController(this)
163     , m_pageZoomFactor(parentPageZoomFactor(this))
164     , m_textZoomFactor(parentTextZoomFactor(this))
165 #if ENABLE(ORIENTATION_EVENTS)
166     , m_orientation(0)
167 #endif
168     , m_inViewSourceMode(false)
169     , m_activeDOMObjectsAndAnimationsSuspendedCount(0)
170 {
171     ASSERT(page);
172     AtomicString::init();
173     HTMLNames::init();
174     QualifiedName::init();
175     MediaFeatureNames::init();
176     SVGNames::init();
177     XLinkNames::init();
178     MathMLNames::init();
179     XMLNSNames::init();
180     XMLNames::init();
181     WebKitFontFamilyNames::init();
182
183     if (!ownerElement) {
184 #if USE(TILED_BACKING_STORE)
185         // Top level frame only for now.
186         setTiledBackingStoreEnabled(page->settings()->tiledBackingStoreEnabled());
187 #endif
188     } else {
189         page->incrementSubframeCount();
190         ownerElement->setContentFrame(this);
191     }
192
193 #ifndef NDEBUG
194     frameCounter.increment();
195 #endif
196
197     // Pause future ActiveDOMObjects if this frame is being created while the page is in a paused state.
198     Frame* parent = parentFromOwnerElement(ownerElement);
199     if (parent && parent->activeDOMObjectsAndAnimationsSuspended())
200         suspendActiveDOMObjectsAndAnimations();
201 }
202
203 PassRefPtr<Frame> Frame::create(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* client)
204 {
205     RefPtr<Frame> frame = adoptRef(new Frame(page, ownerElement, client));
206     if (!ownerElement)
207         page->setMainFrame(frame);
208     return frame.release();
209 }
210
211 Frame::~Frame()
212 {
213     setView(0);
214     loader()->cancelAndClear();
215
216     // FIXME: We should not be doing all this work inside the destructor
217
218 #ifndef NDEBUG
219     frameCounter.decrement();
220 #endif
221
222     disconnectOwnerElement();
223
224     HashSet<FrameDestructionObserver*>::iterator stop = m_destructionObservers.end();
225     for (HashSet<FrameDestructionObserver*>::iterator it = m_destructionObservers.begin(); it != stop; ++it)
226         (*it)->frameDestroyed();
227
228     if (m_view) {
229         m_view->hide();
230         m_view->clearFrame();
231     }
232 }
233
234 bool Frame::inScope(TreeScope* scope) const
235 {
236     ASSERT(scope);
237     Document* doc = document();
238     if (!doc)
239         return false;
240     HTMLFrameOwnerElement* owner = doc->ownerElement();
241     if (!owner)
242         return false;
243     return owner->treeScope() == scope;
244 }
245
246 void Frame::addDestructionObserver(FrameDestructionObserver* observer)
247 {
248     m_destructionObservers.add(observer);
249 }
250
251 void Frame::removeDestructionObserver(FrameDestructionObserver* observer)
252 {
253     m_destructionObservers.remove(observer);
254 }
255
256 void Frame::setView(PassRefPtr<FrameView> view)
257 {
258     // We the custom scroll bars as early as possible to prevent m_doc->detach()
259     // from messing with the view such that its scroll bars won't be torn down.
260     // FIXME: We should revisit this.
261     if (m_view)
262         m_view->prepareForDetach();
263
264     // Prepare for destruction now, so any unload event handlers get run and the DOMWindow is
265     // notified. If we wait until the view is destroyed, then things won't be hooked up enough for
266     // these calls to work.
267     if (!view && m_doc && m_doc->attached() && !m_doc->inPageCache()) {
268         // FIXME: We don't call willRemove here. Why is that OK?
269         m_doc->prepareForDestruction();
270     }
271     
272     if (m_view)
273         m_view->unscheduleRelayout();
274     
275     eventHandler()->clear();
276
277     m_view = view;
278
279     // Only one form submission is allowed per view of a part.
280     // Since this part may be getting reused as a result of being
281     // pulled from the back/forward cache, reset this flag.
282     loader()->resetMultipleFormSubmissionProtection();
283     
284 #if USE(TILED_BACKING_STORE)
285     if (m_view && tiledBackingStore())
286         m_view->setPaintsEntireContents(true);
287 #endif
288 }
289
290 void Frame::setDocument(PassRefPtr<Document> newDoc)
291 {
292     ASSERT(!newDoc || newDoc->frame() == this);
293     if (m_doc && m_doc->attached() && !m_doc->inPageCache()) {
294         // FIXME: We don't call willRemove here. Why is that OK?
295         m_doc->detach();
296     }
297
298     m_doc = newDoc;
299     ASSERT(!m_doc || m_doc->domWindow());
300     ASSERT(!m_doc || m_doc->domWindow()->frame() == this);
301
302     selection()->updateSecureKeyboardEntryIfActive();
303
304     if (m_doc && !m_doc->attached())
305         m_doc->attach();
306
307     if (m_doc) {
308         m_script.updateDocument();
309         m_doc->updateViewportArguments();
310     }
311
312     if (m_page && m_page->mainFrame() == this) {
313         notifyChromeClientWheelEventHandlerCountChanged();
314 #if ENABLE(TOUCH_EVENTS)
315         if (m_doc && m_doc->hasTouchEventHandlers())
316             m_page->chrome()->client()->needTouchEvents(true);
317 #endif
318     }
319
320     // Suspend document if this frame was created in suspended state.
321     if (m_doc && activeDOMObjectsAndAnimationsSuspended()) {
322         m_doc->suspendScriptedAnimationControllerCallbacks();
323         m_animationController.suspendAnimationsForDocument(m_doc.get());
324         m_doc->suspendActiveDOMObjects(ActiveDOMObject::PageWillBeSuspended);
325     }
326 }
327
328 #if ENABLE(ORIENTATION_EVENTS)
329 void Frame::sendOrientationChangeEvent(int orientation)
330 {
331     m_orientation = orientation;
332     if (Document* doc = document())
333         doc->dispatchWindowEvent(Event::create(eventNames().orientationchangeEvent, false, false));
334 }
335 #endif // ENABLE(ORIENTATION_EVENTS)
336     
337 Settings* Frame::settings() const
338 {
339     return m_page ? m_page->settings() : 0;
340 }
341
342 static PassOwnPtr<RegularExpression> createRegExpForLabels(const Vector<String>& labels)
343 {
344     // REVIEW- version of this call in FrameMac.mm caches based on the NSArray ptrs being
345     // the same across calls.  We can't do that.
346
347     DEFINE_STATIC_LOCAL(RegularExpression, wordRegExp, ("\\w", TextCaseSensitive));
348     String pattern("(");
349     unsigned int numLabels = labels.size();
350     unsigned int i;
351     for (i = 0; i < numLabels; i++) {
352         String label = labels[i];
353
354         bool startsWithWordChar = false;
355         bool endsWithWordChar = false;
356         if (label.length()) {
357             startsWithWordChar = wordRegExp.match(label.substring(0, 1)) >= 0;
358             endsWithWordChar = wordRegExp.match(label.substring(label.length() - 1, 1)) >= 0;
359         }
360
361         if (i)
362             pattern.append("|");
363         // Search for word boundaries only if label starts/ends with "word characters".
364         // If we always searched for word boundaries, this wouldn't work for languages
365         // such as Japanese.
366         if (startsWithWordChar)
367             pattern.append("\\b");
368         pattern.append(label);
369         if (endsWithWordChar)
370             pattern.append("\\b");
371     }
372     pattern.append(")");
373     return adoptPtr(new RegularExpression(pattern, TextCaseInsensitive));
374 }
375
376 String Frame::searchForLabelsAboveCell(RegularExpression* regExp, HTMLTableCellElement* cell, size_t* resultDistanceFromStartOfCell)
377 {
378     HTMLTableCellElement* aboveCell = cell->cellAbove();
379     if (aboveCell) {
380         // search within the above cell we found for a match
381         size_t lengthSearched = 0;    
382         for (Node* n = aboveCell->firstChild(); n; n = NodeTraversal::next(n, aboveCell)) {
383             if (n->isTextNode() && n->renderer() && n->renderer()->style()->visibility() == VISIBLE) {
384                 // For each text chunk, run the regexp
385                 String nodeString = n->nodeValue();
386                 int pos = regExp->searchRev(nodeString);
387                 if (pos >= 0) {
388                     if (resultDistanceFromStartOfCell)
389                         *resultDistanceFromStartOfCell = lengthSearched;
390                     return nodeString.substring(pos, regExp->matchedLength());
391                 }
392                 lengthSearched += nodeString.length();
393             }
394         }
395     }
396
397     // Any reason in practice to search all cells in that are above cell?
398     if (resultDistanceFromStartOfCell)
399         *resultDistanceFromStartOfCell = notFound;
400     return String();
401 }
402
403 String Frame::searchForLabelsBeforeElement(const Vector<String>& labels, Element* element, size_t* resultDistance, bool* resultIsInCellAbove)
404 {
405     OwnPtr<RegularExpression> regExp(createRegExpForLabels(labels));
406     // We stop searching after we've seen this many chars
407     const unsigned int charsSearchedThreshold = 500;
408     // This is the absolute max we search.  We allow a little more slop than
409     // charsSearchedThreshold, to make it more likely that we'll search whole nodes.
410     const unsigned int maxCharsSearched = 600;
411     // If the starting element is within a table, the cell that contains it
412     HTMLTableCellElement* startingTableCell = 0;
413     bool searchedCellAbove = false;
414
415     if (resultDistance)
416         *resultDistance = notFound;
417     if (resultIsInCellAbove)
418         *resultIsInCellAbove = false;
419     
420     // walk backwards in the node tree, until another element, or form, or end of tree
421     int unsigned lengthSearched = 0;
422     Node* n;
423     for (n = NodeTraversal::previous(element); n && lengthSearched < charsSearchedThreshold; n = NodeTraversal::previous(n)) {
424         if (n->hasTagName(formTag)
425             || (n->isHTMLElement() && static_cast<Element*>(n)->isFormControlElement()))
426         {
427             // We hit another form element or the start of the form - bail out
428             break;
429         } else if (n->hasTagName(tdTag) && !startingTableCell) {
430             startingTableCell = static_cast<HTMLTableCellElement*>(n);
431         } else if (n->hasTagName(trTag) && startingTableCell) {
432             String result = searchForLabelsAboveCell(regExp.get(), startingTableCell, resultDistance);
433             if (!result.isEmpty()) {
434                 if (resultIsInCellAbove)
435                     *resultIsInCellAbove = true;
436                 return result;
437             }
438             searchedCellAbove = true;
439         } else if (n->isTextNode() && n->renderer() && n->renderer()->style()->visibility() == VISIBLE) {
440             // For each text chunk, run the regexp
441             String nodeString = n->nodeValue();
442             // add 100 for slop, to make it more likely that we'll search whole nodes
443             if (lengthSearched + nodeString.length() > maxCharsSearched)
444                 nodeString = nodeString.right(charsSearchedThreshold - lengthSearched);
445             int pos = regExp->searchRev(nodeString);
446             if (pos >= 0) {
447                 if (resultDistance)
448                     *resultDistance = lengthSearched;
449                 return nodeString.substring(pos, regExp->matchedLength());
450             }
451             lengthSearched += nodeString.length();
452         }
453     }
454
455     // If we started in a cell, but bailed because we found the start of the form or the
456     // previous element, we still might need to search the row above us for a label.
457     if (startingTableCell && !searchedCellAbove) {
458          String result = searchForLabelsAboveCell(regExp.get(), startingTableCell, resultDistance);
459         if (!result.isEmpty()) {
460             if (resultIsInCellAbove)
461                 *resultIsInCellAbove = true;
462             return result;
463         }
464     }
465     return String();
466 }
467
468 static String matchLabelsAgainstString(const Vector<String>& labels, const String& stringToMatch)
469 {
470     if (stringToMatch.isEmpty())
471         return String();
472
473     String mutableStringToMatch = stringToMatch;
474
475     // Make numbers and _'s in field names behave like word boundaries, e.g., "address2"
476     replace(mutableStringToMatch, RegularExpression("\\d", TextCaseSensitive), " ");
477     mutableStringToMatch.replace('_', ' ');
478     
479     OwnPtr<RegularExpression> regExp(createRegExpForLabels(labels));
480     // Use the largest match we can find in the whole string
481     int pos;
482     int length;
483     int bestPos = -1;
484     int bestLength = -1;
485     int start = 0;
486     do {
487         pos = regExp->match(mutableStringToMatch, start);
488         if (pos != -1) {
489             length = regExp->matchedLength();
490             if (length >= bestLength) {
491                 bestPos = pos;
492                 bestLength = length;
493             }
494             start = pos + 1;
495         }
496     } while (pos != -1);
497     
498     if (bestPos != -1)
499         return mutableStringToMatch.substring(bestPos, bestLength);
500     return String();
501 }
502     
503 String Frame::matchLabelsAgainstElement(const Vector<String>& labels, Element* element)
504 {
505     // Match against the name element, then against the id element if no match is found for the name element.
506     // See 7538330 for one popular site that benefits from the id element check.
507     // FIXME: This code is mirrored in FrameMac.mm. It would be nice to make the Mac code call the platform-agnostic
508     // code, which would require converting the NSArray of NSStrings to a Vector of Strings somewhere along the way.
509     String resultFromNameAttribute = matchLabelsAgainstString(labels, element->getNameAttribute());
510     if (!resultFromNameAttribute.isEmpty())
511         return resultFromNameAttribute;
512     
513     return matchLabelsAgainstString(labels, element->getAttribute(idAttr));
514 }
515
516 void Frame::setPrinting(bool printing, const FloatSize& pageSize, const FloatSize& originalPageSize, float maximumShrinkRatio, AdjustViewSizeOrNot shouldAdjustViewSize)
517 {
518     // In setting printing, we should not validate resources already cached for the document.
519     // See https://bugs.webkit.org/show_bug.cgi?id=43704
520     ResourceCacheValidationSuppressor validationSuppressor(m_doc->cachedResourceLoader());
521
522     m_doc->setPrinting(printing);
523     view()->adjustMediaTypeForPrinting(printing);
524
525     m_doc->styleResolverChanged(RecalcStyleImmediately);
526     if (shouldUsePrintingLayout()) {
527         view()->forceLayoutForPagination(pageSize, originalPageSize, maximumShrinkRatio, shouldAdjustViewSize);
528     } else {
529         view()->forceLayout();
530         if (shouldAdjustViewSize == AdjustViewSize)
531             view()->adjustViewSize();
532     }
533
534     // Subframes of the one we're printing don't lay out to the page size.
535     for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
536         child->setPrinting(printing, FloatSize(), FloatSize(), 0, shouldAdjustViewSize);
537 }
538
539 bool Frame::shouldUsePrintingLayout() const
540 {
541     // Only top frame being printed should be fit to page size.
542     // Subframes should be constrained by parents only.
543     return m_doc->printing() && (!tree()->parent() || !tree()->parent()->m_doc->printing());
544 }
545
546 FloatSize Frame::resizePageRectsKeepingRatio(const FloatSize& originalSize, const FloatSize& expectedSize)
547 {
548     FloatSize resultSize;
549     if (!contentRenderer())
550         return FloatSize();
551
552     if (contentRenderer()->style()->isHorizontalWritingMode()) {
553         ASSERT(fabs(originalSize.width()) > numeric_limits<float>::epsilon());
554         float ratio = originalSize.height() / originalSize.width();
555         resultSize.setWidth(floorf(expectedSize.width()));
556         resultSize.setHeight(floorf(resultSize.width() * ratio));
557     } else {
558         ASSERT(fabs(originalSize.height()) > numeric_limits<float>::epsilon());
559         float ratio = originalSize.width() / originalSize.height();
560         resultSize.setHeight(floorf(expectedSize.height()));
561         resultSize.setWidth(floorf(resultSize.height() * ratio));
562     }
563     return resultSize;
564 }
565
566 void Frame::injectUserScripts(UserScriptInjectionTime injectionTime)
567 {
568     if (!m_page)
569         return;
570
571     if (loader()->stateMachine()->creatingInitialEmptyDocument() && !settings()->shouldInjectUserScriptsInInitialEmptyDocument())
572         return;
573
574     // Walk the hashtable. Inject by world.
575     const UserScriptMap* userScripts = m_page->group().userScripts();
576     if (!userScripts)
577         return;
578     UserScriptMap::const_iterator end = userScripts->end();
579     for (UserScriptMap::const_iterator it = userScripts->begin(); it != end; ++it)
580         injectUserScriptsForWorld(it->key.get(), *it->value, injectionTime);
581 }
582
583 void Frame::injectUserScriptsForWorld(DOMWrapperWorld* world, const UserScriptVector& userScripts, UserScriptInjectionTime injectionTime)
584 {
585     if (userScripts.isEmpty())
586         return;
587
588     Document* doc = document();
589     if (!doc)
590         return;
591
592     Vector<ScriptSourceCode> sourceCode;
593     unsigned count = userScripts.size();
594     for (unsigned i = 0; i < count; ++i) {
595         UserScript* script = userScripts[i].get();
596         if (script->injectedFrames() == InjectInTopFrameOnly && ownerElement())
597             continue;
598
599         if (script->injectionTime() == injectionTime && UserContentURLPattern::matchesPatterns(doc->url(), script->whitelist(), script->blacklist()))
600             m_script.evaluateInWorld(ScriptSourceCode(script->source(), script->url()), world);
601     }
602 }
603
604 RenderView* Frame::contentRenderer() const
605 {
606     return document() ? document()->renderView() : 0;
607 }
608
609 RenderPart* Frame::ownerRenderer() const
610 {
611     HTMLFrameOwnerElement* ownerElement = m_ownerElement;
612     if (!ownerElement)
613         return 0;
614     RenderObject* object = ownerElement->renderer();
615     if (!object)
616         return 0;
617     // FIXME: If <object> is ever fixed to disassociate itself from frames
618     // that it has started but canceled, then this can turn into an ASSERT
619     // since m_ownerElement would be 0 when the load is canceled.
620     // https://bugs.webkit.org/show_bug.cgi?id=18585
621     if (!object->isRenderPart())
622         return 0;
623     return toRenderPart(object);
624 }
625
626 Frame* Frame::frameForWidget(const Widget* widget)
627 {
628     ASSERT_ARG(widget, widget);
629
630     if (RenderWidget* renderer = RenderWidget::find(widget))
631         if (Node* node = renderer->node())
632             return node->document()->frame();
633
634     // Assume all widgets are either a FrameView or owned by a RenderWidget.
635     // FIXME: That assumption is not right for scroll bars!
636     ASSERT_WITH_SECURITY_IMPLICATION(widget->isFrameView());
637     return static_cast<const FrameView*>(widget)->frame();
638 }
639
640 void Frame::clearTimers(FrameView *view, Document *document)
641 {
642     if (view) {
643         view->unscheduleRelayout();
644         if (view->frame()) {
645             view->frame()->animation()->suspendAnimationsForDocument(document);
646             view->frame()->eventHandler()->stopAutoscrollTimer();
647         }
648     }
649 }
650
651 void Frame::clearTimers()
652 {
653     clearTimers(m_view.get(), document());
654 }
655
656 #if ENABLE(PAGE_VISIBILITY_API)
657 void Frame::dispatchVisibilityStateChangeEvent()
658 {
659     if (m_doc)
660         m_doc->dispatchVisibilityStateChangeEvent();
661
662     Vector<RefPtr<Frame> > childFrames;
663     for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
664         childFrames.append(child);
665
666     for (size_t i = 0; i < childFrames.size(); ++i)
667         childFrames[i]->dispatchVisibilityStateChangeEvent();
668 }
669 #endif
670
671 void Frame::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
672 {
673     MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::DOM);
674     info.addMember(m_doc, "doc");
675     info.ignoreMember(m_view);
676     info.addMember(m_ownerElement, "ownerElement");
677     info.addMember(m_page, "page");
678     info.addMember(m_loader, "loader");
679     info.ignoreMember(m_destructionObservers);
680 }
681
682 void Frame::willDetachPage()
683 {
684     if (Frame* parent = tree()->parent())
685         parent->loader()->checkLoadComplete();
686
687     HashSet<FrameDestructionObserver*>::iterator stop = m_destructionObservers.end();
688     for (HashSet<FrameDestructionObserver*>::iterator it = m_destructionObservers.begin(); it != stop; ++it)
689         (*it)->willDetachPage();
690
691     // FIXME: It's unclear as to why this is called more than once, but it is,
692     // so page() could be NULL.
693     if (page() && page()->focusController()->focusedFrame() == this)
694         page()->focusController()->setFocusedFrame(0);
695
696     if (page() && page()->scrollingCoordinator() && m_view)
697         page()->scrollingCoordinator()->willDestroyScrollableArea(m_view.get());
698
699     script()->clearScriptObjects();
700     script()->updatePlatformScriptObjects();
701 }
702
703 void Frame::disconnectOwnerElement()
704 {
705     if (m_ownerElement) {
706         if (Document* doc = document())
707             doc->clearAXObjectCache();
708         m_ownerElement->clearContentFrame();
709         if (m_page)
710             m_page->decrementSubframeCount();
711     }
712     m_ownerElement = 0;
713 }
714
715 String Frame::documentTypeString() const
716 {
717     if (DocumentType* doctype = document()->doctype())
718         return createMarkup(doctype);
719
720     return String();
721 }
722
723 String Frame::displayStringModifiedByEncoding(const String& str) const
724 {
725     return document() ? document()->displayStringModifiedByEncoding(str) : str;
726 }
727
728 VisiblePosition Frame::visiblePositionForPoint(const IntPoint& framePoint)
729 {
730     HitTestResult result = eventHandler()->hitTestResultAtPoint(framePoint, HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::AllowShadowContent);
731     Node* node = result.innerNonSharedNode();
732     if (!node)
733         return VisiblePosition();
734     RenderObject* renderer = node->renderer();
735     if (!renderer)
736         return VisiblePosition();
737     VisiblePosition visiblePos = renderer->positionForPoint(result.localPoint());
738     if (visiblePos.isNull())
739         visiblePos = firstPositionInOrBeforeNode(node);
740     return visiblePos;
741 }
742
743 Document* Frame::documentAtPoint(const IntPoint& point)
744 {
745     if (!view())
746         return 0;
747
748     IntPoint pt = view()->windowToContents(point);
749     HitTestResult result = HitTestResult(pt);
750
751     if (contentRenderer())
752         result = eventHandler()->hitTestResultAtPoint(pt);
753     return result.innerNode() ? result.innerNode()->document() : 0;
754 }
755
756 PassRefPtr<Range> Frame::rangeForPoint(const IntPoint& framePoint)
757 {
758     VisiblePosition position = visiblePositionForPoint(framePoint);
759     if (position.isNull())
760         return 0;
761
762     VisiblePosition previous = position.previous();
763     if (previous.isNotNull()) {
764         RefPtr<Range> previousCharacterRange = makeRange(previous, position);
765         LayoutRect rect = editor()->firstRectForRange(previousCharacterRange.get());
766         if (rect.contains(framePoint))
767             return previousCharacterRange.release();
768     }
769
770     VisiblePosition next = position.next();
771     if (RefPtr<Range> nextCharacterRange = makeRange(position, next)) {
772         LayoutRect rect = editor()->firstRectForRange(nextCharacterRange.get());
773         if (rect.contains(framePoint))
774             return nextCharacterRange.release();
775     }
776
777     return 0;
778 }
779
780 void Frame::createView(const IntSize& viewportSize, const Color& backgroundColor, bool transparent,
781     const IntSize& fixedLayoutSize, const IntRect& fixedVisibleContentRect ,
782     bool useFixedLayout, ScrollbarMode horizontalScrollbarMode, bool horizontalLock,
783     ScrollbarMode verticalScrollbarMode, bool verticalLock)
784 {
785     ASSERT(this);
786     ASSERT(m_page);
787
788     bool isMainFrame = this == m_page->mainFrame();
789
790     if (isMainFrame && view())
791         view()->setParentVisible(false);
792
793     setView(0);
794
795     RefPtr<FrameView> frameView;
796     if (isMainFrame) {
797         frameView = FrameView::create(this, viewportSize);
798         frameView->setFixedLayoutSize(fixedLayoutSize);
799         frameView->setFixedVisibleContentRect(fixedVisibleContentRect);
800         frameView->setUseFixedLayout(useFixedLayout);
801     } else
802         frameView = FrameView::create(this);
803
804     frameView->setScrollbarModes(horizontalScrollbarMode, verticalScrollbarMode, horizontalLock, verticalLock);
805
806     setView(frameView);
807
808     if (backgroundColor.isValid())
809         frameView->updateBackgroundRecursively(backgroundColor, transparent);
810
811     if (isMainFrame)
812         frameView->setParentVisible(true);
813
814     if (ownerRenderer())
815         ownerRenderer()->setWidget(frameView);
816
817     if (HTMLFrameOwnerElement* owner = ownerElement())
818         view()->setCanHaveScrollbars(owner->scrollingMode() != ScrollbarAlwaysOff);
819 }
820
821 #if USE(TILED_BACKING_STORE)
822 void Frame::setTiledBackingStoreEnabled(bool enabled)
823 {
824     if (!enabled) {
825         m_tiledBackingStore.clear();
826         return;
827     }
828     if (m_tiledBackingStore)
829         return;
830     m_tiledBackingStore = adoptPtr(new TiledBackingStore(this));
831     m_tiledBackingStore->setCommitTileUpdatesOnIdleEventLoop(true);
832     if (m_view)
833         m_view->setPaintsEntireContents(true);
834 }
835
836 void Frame::tiledBackingStorePaintBegin()
837 {
838     if (!m_view)
839         return;
840     m_view->updateLayoutAndStyleIfNeededRecursive();
841     m_view->flushDeferredRepaints();
842 }
843
844 void Frame::tiledBackingStorePaint(GraphicsContext* context, const IntRect& rect)
845 {
846     if (!m_view)
847         return;
848     m_view->paintContents(context, rect);
849 }
850
851 void Frame::tiledBackingStorePaintEnd(const Vector<IntRect>& paintedArea)
852 {
853     if (!m_page || !m_view)
854         return;
855     unsigned size = paintedArea.size();
856     // Request repaint from the system
857     for (unsigned n = 0; n < size; ++n)
858         m_page->chrome()->invalidateContentsAndRootView(m_view->contentsToRootView(paintedArea[n]), false);
859 }
860
861 IntRect Frame::tiledBackingStoreContentsRect()
862 {
863     if (!m_view)
864         return IntRect();
865     return IntRect(IntPoint(), m_view->contentsSize());
866 }
867
868 IntRect Frame::tiledBackingStoreVisibleRect()
869 {
870     if (!m_page)
871         return IntRect();
872     return m_page->chrome()->client()->visibleRectForTiledBackingStore();
873 }
874
875 Color Frame::tiledBackingStoreBackgroundColor() const
876 {
877     if (!m_view)
878         return Color();
879     return m_view->baseBackgroundColor();
880 }
881 #endif
882
883 String Frame::layerTreeAsText(LayerTreeFlags flags) const
884 {
885 #if USE(ACCELERATED_COMPOSITING)
886     document()->updateLayout();
887
888     if (!contentRenderer())
889         return String();
890
891     return contentRenderer()->compositor()->layerTreeAsText(flags);
892 #else
893     UNUSED_PARAM(flags);
894     return String();
895 #endif
896 }
897
898 String Frame::trackedRepaintRectsAsText() const
899 {
900     if (!m_view)
901         return String();
902     return m_view->trackedRepaintRectsAsText();
903 }
904
905 void Frame::setPageZoomFactor(float factor)
906 {
907     setPageAndTextZoomFactors(factor, m_textZoomFactor);
908 }
909
910 void Frame::setTextZoomFactor(float factor)
911 {
912     setPageAndTextZoomFactors(m_pageZoomFactor, factor);
913 }
914
915 void Frame::setPageAndTextZoomFactors(float pageZoomFactor, float textZoomFactor)
916 {
917     if (m_pageZoomFactor == pageZoomFactor && m_textZoomFactor == textZoomFactor)
918         return;
919
920     Page* page = this->page();
921     if (!page)
922         return;
923
924     Document* document = this->document();
925     if (!document)
926         return;
927
928     m_editor.dismissCorrectionPanelAsIgnored();
929
930 #if ENABLE(SVG)
931     // Respect SVGs zoomAndPan="disabled" property in standalone SVG documents.
932     // FIXME: How to handle compound documents + zoomAndPan="disabled"? Needs SVG WG clarification.
933     if (document->isSVGDocument()) {
934         if (!toSVGDocument(document)->zoomAndPanEnabled())
935             return;
936     }
937 #endif
938
939     if (m_pageZoomFactor != pageZoomFactor) {
940         if (FrameView* view = this->view()) {
941             // Update the scroll position when doing a full page zoom, so the content stays in relatively the same position.
942             LayoutPoint scrollPosition = view->scrollPosition();
943             float percentDifference = (pageZoomFactor / m_pageZoomFactor);
944             view->setScrollPosition(IntPoint(scrollPosition.x() * percentDifference, scrollPosition.y() * percentDifference));
945         }
946     }
947
948     m_pageZoomFactor = pageZoomFactor;
949     m_textZoomFactor = textZoomFactor;
950
951     document->recalcStyle(Node::Force);
952
953     for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
954         child->setPageAndTextZoomFactors(m_pageZoomFactor, m_textZoomFactor);
955
956     if (FrameView* view = this->view()) {
957         if (document->renderer() && document->renderer()->needsLayout() && view->didFirstLayout())
958             view->layout();
959     }
960
961     if (page->mainFrame() == this)
962         pageCache()->markPagesForFullStyleRecalc(page);
963 }
964
965 float Frame::frameScaleFactor() const
966 {
967     Page* page = this->page();
968
969     // Main frame is scaled with respect to he container but inner frames are not scaled with respect to the main frame.
970     if (!page || page->mainFrame() != this || page->settings()->applyPageScaleFactorInCompositor())
971         return 1;
972
973     return page->pageScaleFactor();
974 }
975
976 void Frame::suspendActiveDOMObjectsAndAnimations()
977 {
978     bool wasSuspended = activeDOMObjectsAndAnimationsSuspended();
979
980     m_activeDOMObjectsAndAnimationsSuspendedCount++;
981
982     if (wasSuspended)
983         return;
984
985     if (document()) {
986         document()->suspendScriptedAnimationControllerCallbacks();
987         animation()->suspendAnimationsForDocument(document());
988         document()->suspendActiveDOMObjects(ActiveDOMObject::PageWillBeSuspended);
989     }
990 }
991
992 void Frame::resumeActiveDOMObjectsAndAnimations()
993 {
994     ASSERT(activeDOMObjectsAndAnimationsSuspended());
995
996     m_activeDOMObjectsAndAnimationsSuspendedCount--;
997
998     if (activeDOMObjectsAndAnimationsSuspended())
999         return;
1000
1001     if (document()) {
1002         document()->resumeActiveDOMObjects();
1003         animation()->resumeAnimationsForDocument(document());
1004         document()->resumeScriptedAnimationControllerCallbacks();
1005     }
1006 }
1007
1008 #if USE(ACCELERATED_COMPOSITING)
1009 void Frame::deviceOrPageScaleFactorChanged()
1010 {
1011     for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
1012         child->deviceOrPageScaleFactorChanged();
1013
1014     RenderView* root = contentRenderer();
1015     if (root && root->compositor())
1016         root->compositor()->deviceOrPageScaleFactorChanged();
1017 }
1018 #endif
1019 void Frame::notifyChromeClientWheelEventHandlerCountChanged() const
1020 {
1021     // Ensure that this method is being called on the main frame of the page.
1022     ASSERT(m_page && m_page->mainFrame() == this);
1023
1024     unsigned count = 0;
1025     for (const Frame* frame = this; frame; frame = frame->tree()->traverseNext()) {
1026         if (frame->document())
1027             count += frame->document()->wheelEventHandlerCount();
1028     }
1029
1030     m_page->chrome()->client()->numWheelEventHandlersChanged(count);
1031 }
1032
1033 bool Frame::isURLAllowed(const KURL& url) const
1034 {
1035     // We allow one level of self-reference because some sites depend on that,
1036     // but we don't allow more than one.
1037     if (m_page->subframeCount() >= Page::maxNumberOfFrames)
1038         return false;
1039     bool foundSelfReference = false;
1040     for (const Frame* frame = this; frame; frame = frame->tree()->parent()) {
1041         if (equalIgnoringFragmentIdentifier(frame->document()->url(), url)) {
1042             if (foundSelfReference)
1043                 return false;
1044             foundSelfReference = true;
1045         }
1046     }
1047     return true;
1048 }
1049
1050 #if !PLATFORM(MAC) && !PLATFORM(WIN)
1051 struct ScopedFramePaintingState {
1052     ScopedFramePaintingState(Frame* frame, Node* node)
1053         : frame(frame)
1054         , node(node)
1055         , paintBehavior(frame->view()->paintBehavior())
1056         , backgroundColor(frame->view()->baseBackgroundColor())
1057     {
1058         ASSERT(!node || node->renderer());
1059         if (node)
1060             node->renderer()->updateDragState(true);
1061     }
1062
1063     ~ScopedFramePaintingState()
1064     {
1065         if (node && node->renderer())
1066             node->renderer()->updateDragState(false);
1067         frame->view()->setPaintBehavior(paintBehavior);
1068         frame->view()->setBaseBackgroundColor(backgroundColor);
1069         frame->view()->setNodeToDraw(0);
1070     }
1071
1072     Frame* frame;
1073     Node* node;
1074     PaintBehavior paintBehavior;
1075     Color backgroundColor;
1076 };
1077
1078 DragImageRef Frame::nodeImage(Node* node)
1079 {
1080     if (!node->renderer())
1081         return 0;
1082
1083     const ScopedFramePaintingState state(this, node);
1084
1085     m_view->setPaintBehavior(state.paintBehavior | PaintBehaviorFlattenCompositingLayers);
1086
1087     // When generating the drag image for an element, ignore the document background.
1088     m_view->setBaseBackgroundColor(Color::transparent);
1089     m_doc->updateLayout();
1090     m_view->setNodeToDraw(node); // Enable special sub-tree drawing mode.
1091
1092     // Document::updateLayout may have blown away the original RenderObject.
1093     RenderObject* renderer = node->renderer();
1094     if (!renderer)
1095       return 0;
1096
1097     LayoutRect topLevelRect;
1098     IntRect paintingRect = pixelSnappedIntRect(renderer->paintingRootRect(topLevelRect));
1099
1100     float deviceScaleFactor = 1;
1101     if (m_page)
1102         deviceScaleFactor = m_page->deviceScaleFactor();
1103     paintingRect.setWidth(paintingRect.width() * deviceScaleFactor);
1104     paintingRect.setHeight(paintingRect.height() * deviceScaleFactor);
1105
1106     OwnPtr<ImageBuffer> buffer(ImageBuffer::create(paintingRect.size(), deviceScaleFactor, ColorSpaceDeviceRGB));
1107     if (!buffer)
1108         return 0;
1109     buffer->context()->translate(-paintingRect.x(), -paintingRect.y());
1110     buffer->context()->clip(FloatRect(0, 0, paintingRect.maxX(), paintingRect.maxY()));
1111
1112     m_view->paintContents(buffer->context(), paintingRect);
1113
1114     RefPtr<Image> image = buffer->copyImage();
1115     return createDragImageFromImage(image.get(), renderer->shouldRespectImageOrientation());
1116 }
1117
1118 DragImageRef Frame::dragImageForSelection()
1119 {
1120     if (!selection()->isRange())
1121         return 0;
1122
1123     const ScopedFramePaintingState state(this, 0);
1124     m_view->setPaintBehavior(PaintBehaviorSelectionOnly);
1125     m_doc->updateLayout();
1126
1127     IntRect paintingRect = enclosingIntRect(selection()->bounds());
1128
1129     float deviceScaleFactor = 1;
1130     if (m_page)
1131         deviceScaleFactor = m_page->deviceScaleFactor();
1132     paintingRect.setWidth(paintingRect.width() * deviceScaleFactor);
1133     paintingRect.setHeight(paintingRect.height() * deviceScaleFactor);
1134
1135     OwnPtr<ImageBuffer> buffer(ImageBuffer::create(paintingRect.size(), deviceScaleFactor, ColorSpaceDeviceRGB));
1136     if (!buffer)
1137         return 0;
1138     buffer->context()->translate(-paintingRect.x(), -paintingRect.y());
1139     buffer->context()->clip(FloatRect(0, 0, paintingRect.maxX(), paintingRect.maxY()));
1140
1141     m_view->paintContents(buffer->context(), paintingRect);
1142
1143     RefPtr<Image> image = buffer->copyImage();
1144     return createDragImageFromImage(image.get());
1145 }
1146
1147 #endif
1148
1149 } // namespace WebCore