2011-01-07 James Robinson <jamesr@chromium.org>
[WebKit-https.git] / 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 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  *
13  * This library is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU Library General Public
15  * License as published by the Free Software Foundation; either
16  * version 2 of the License, or (at your option) any later version.
17  *
18  * This library is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21  * Library General Public License for more details.
22  *
23  * You should have received a copy of the GNU Library General Public License
24  * along with this library; see the file COPYING.LIB.  If not, write to
25  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
26  * Boston, MA 02110-1301, USA.
27  */
28
29 #include "config.h"
30 #include "Frame.h"
31
32 #include "ApplyStyleCommand.h"
33 #include "CSSComputedStyleDeclaration.h"
34 #include "CSSMutableStyleDeclaration.h"
35 #include "CSSProperty.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 "EditingText.h"
44 #include "EditorClient.h"
45 #include "EventNames.h"
46 #include "FloatQuad.h"
47 #include "FocusController.h"
48 #include "FrameLoader.h"
49 #include "FrameLoaderClient.h"
50 #include "FrameView.h"
51 #include "GraphicsContext.h"
52 #include "GraphicsLayer.h"
53 #include "HTMLDocument.h"
54 #include "HTMLFormControlElement.h"
55 #include "HTMLFormElement.h"
56 #include "HTMLFrameElementBase.h"
57 #include "HTMLNames.h"
58 #include "HTMLTableCellElement.h"
59 #include "HitTestResult.h"
60 #include "Logging.h"
61 #include "MediaFeatureNames.h"
62 #include "Navigator.h"
63 #include "NodeList.h"
64 #include "Page.h"
65 #include "PageGroup.h"
66 #include "RegularExpression.h"
67 #include "RenderLayer.h"
68 #include "RenderPart.h"
69 #include "RenderTableCell.h"
70 #include "RenderTextControl.h"
71 #include "RenderTheme.h"
72 #include "RenderView.h"
73 #include "ScriptController.h"
74 #include "ScriptSourceCode.h"
75 #include "Settings.h"
76 #include "TextIterator.h"
77 #include "TextResourceDecoder.h"
78 #include "UserContentURLPattern.h"
79 #include "UserTypingGestureIndicator.h"
80 #include "XMLNSNames.h"
81 #include "XMLNames.h"
82 #include "htmlediting.h"
83 #include "markup.h"
84 #include "npruntime_impl.h"
85 #include "visible_units.h"
86 #include <wtf/RefCountedLeakCounter.h>
87 #include <wtf/StdLibExtras.h>
88
89 #if USE(ACCELERATED_COMPOSITING)
90 #include "RenderLayerCompositor.h"
91 #endif
92
93 #if USE(JSC)
94 #include "JSDOMWindowShell.h"
95 #include "runtime_root.h"
96 #endif
97
98 #include "MathMLNames.h"
99 #include "SVGNames.h"
100 #include "XLinkNames.h"
101
102 #if ENABLE(SVG)
103 #include "SVGDocument.h"
104 #include "SVGDocumentExtensions.h"
105 #endif
106
107 #if ENABLE(TILED_BACKING_STORE)
108 #include "TiledBackingStore.h"
109 #endif
110
111 #if ENABLE(WML)
112 #include "WMLNames.h"
113 #endif
114
115 using namespace std;
116
117 namespace WebCore {
118
119 using namespace HTMLNames;
120
121 #ifndef NDEBUG
122 static WTF::RefCountedLeakCounter frameCounter("Frame");
123 #endif
124
125 static inline Frame* parentFromOwnerElement(HTMLFrameOwnerElement* ownerElement)
126 {
127     if (!ownerElement)
128         return 0;
129     return ownerElement->document()->frame();
130 }
131
132 static inline float parentPageZoomFactor(Frame* frame)
133 {
134     Frame* parent = frame->tree()->parent();
135     if (!parent)
136         return 1;
137     return parent->pageZoomFactor();
138 }
139
140 static inline float parentTextZoomFactor(Frame* frame)
141 {
142     Frame* parent = frame->tree()->parent();
143     if (!parent)
144         return 1;
145     return parent->textZoomFactor();
146 }
147
148 inline Frame::Frame(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* frameLoaderClient)
149     : m_page(page)
150     , m_treeNode(this, parentFromOwnerElement(ownerElement))
151     , m_loader(this, frameLoaderClient)
152     , m_navigationScheduler(this)
153     , m_ownerElement(ownerElement)
154     , m_script(this)
155     , m_editor(this)
156     , m_selectionController(this)
157     , m_eventHandler(this)
158     , m_animationController(this)
159     , m_lifeSupportTimer(this, &Frame::lifeSupportTimerFired)
160     , m_pageZoomFactor(parentPageZoomFactor(this))
161     , m_textZoomFactor(parentTextZoomFactor(this))
162     , m_pageScaleFactor(1)
163 #if ENABLE(ORIENTATION_EVENTS)
164     , m_orientation(0)
165 #endif
166     , m_inViewSourceMode(false)
167     , m_isDisconnected(false)
168     , m_excludeFromTextSearch(false)
169 {
170     ASSERT(page);
171     AtomicString::init();
172     HTMLNames::init();
173     QualifiedName::init();
174     MediaFeatureNames::init();
175     SVGNames::init();
176     XLinkNames::init();
177     MathMLNames::init();
178     XMLNSNames::init();
179     XMLNames::init();
180
181 #if ENABLE(WML)
182     WMLNames::init();
183 #endif
184
185     if (!ownerElement) {
186 #if ENABLE(TILED_BACKING_STORE)
187         // Top level frame only for now.
188         setTiledBackingStoreEnabled(page->settings()->tiledBackingStoreEnabled());
189 #endif
190     } else {
191         page->incrementFrameCount();
192
193         // Make sure we will not end up with two frames referencing the same owner element.
194         Frame*& contentFrameSlot = ownerElement->m_contentFrame;
195         ASSERT(!contentFrameSlot || contentFrameSlot->ownerElement() != ownerElement);
196         contentFrameSlot = this;
197     }
198
199 #ifndef NDEBUG
200     frameCounter.increment();
201 #endif
202 }
203
204 PassRefPtr<Frame> Frame::create(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* client)
205 {
206     RefPtr<Frame> frame = adoptRef(new Frame(page, ownerElement, client));
207     if (!ownerElement)
208         page->setMainFrame(frame);
209     return frame.release();
210 }
211
212 Frame::~Frame()
213 {
214     setView(0);
215     loader()->cancelAndClear();
216
217     // FIXME: We should not be doing all this work inside the destructor
218
219     ASSERT(!m_lifeSupportTimer.isActive());
220
221 #ifndef NDEBUG
222     frameCounter.decrement();
223 #endif
224
225     disconnectOwnerElement();
226
227     if (m_domWindow)
228         m_domWindow->disconnectFrame();
229     script()->clearWindowShell();
230
231     HashSet<DOMWindow*>::iterator end = m_liveFormerWindows.end();
232     for (HashSet<DOMWindow*>::iterator it = m_liveFormerWindows.begin(); it != end; ++it)
233         (*it)->disconnectFrame();
234
235     HashSet<FrameDestructionObserver*>::iterator stop = m_destructionObservers.end();
236     for (HashSet<FrameDestructionObserver*>::iterator it = m_destructionObservers.begin(); it != stop; ++it)
237         (*it)->frameDestroyed();
238
239     if (m_view) {
240         m_view->hide();
241         m_view->clearFrame();
242     }
243
244     ASSERT(!m_lifeSupportTimer.isActive());
245 }
246
247 void Frame::addDestructionObserver(FrameDestructionObserver* observer)
248 {
249     m_destructionObservers.add(observer);
250 }
251
252 void Frame::removeDestructionObserver(FrameDestructionObserver* observer)
253 {
254     m_destructionObservers.remove(observer);
255 }
256
257 void Frame::setView(PassRefPtr<FrameView> view)
258 {
259     // We the custom scroll bars as early as possible to prevent m_doc->detach()
260     // from messing with the view such that its scroll bars won't be torn down.
261     // FIXME: We should revisit this.
262     if (m_view)
263         m_view->detachCustomScrollbars();
264
265     // Detach the document now, so any onUnload handlers get run - if
266     // we wait until the view is destroyed, then things won't be
267     // hooked up enough for some JavaScript calls to work.
268     if (!view && m_doc && m_doc->attached() && !m_doc->inPageCache()) {
269         // FIXME: We don't call willRemove here. Why is that OK?
270         m_doc->detach();
271     }
272     
273     if (m_view)
274         m_view->unscheduleRelayout();
275     
276     eventHandler()->clear();
277
278     m_view = view;
279
280     // Only one form submission is allowed per view of a part.
281     // Since this part may be getting reused as a result of being
282     // pulled from the back/forward cache, reset this flag.
283     loader()->resetMultipleFormSubmissionProtection();
284     
285 #if ENABLE(TILED_BACKING_STORE)
286     if (m_view && tiledBackingStore())
287         m_view->setPaintsEntireContents(true);
288 #endif
289 }
290
291 void Frame::setDocument(PassRefPtr<Document> newDoc)
292 {
293     ASSERT(!newDoc || newDoc->frame());
294     if (m_doc && m_doc->attached() && !m_doc->inPageCache()) {
295         // FIXME: We don't call willRemove here. Why is that OK?
296         m_doc->detach();
297     }
298
299     m_doc = newDoc;
300     selection()->updateSecureKeyboardEntryIfActive();
301
302     if (m_doc && !m_doc->attached())
303         m_doc->attach();
304
305     // Update the cached 'document' property, which is now stale.
306     m_script.updateDocument();
307
308     if (m_page)
309         m_page->updateViewportArguments();
310 }
311
312 #if ENABLE(ORIENTATION_EVENTS)
313 void Frame::sendOrientationChangeEvent(int orientation)
314 {
315     m_orientation = orientation;
316     if (Document* doc = document())
317         doc->dispatchWindowEvent(Event::create(eventNames().orientationchangeEvent, false, false));
318 }
319 #endif // ENABLE(ORIENTATION_EVENTS)
320     
321 Settings* Frame::settings() const
322 {
323     return m_page ? m_page->settings() : 0;
324 }
325
326 static RegularExpression* createRegExpForLabels(const Vector<String>& labels)
327 {
328     // REVIEW- version of this call in FrameMac.mm caches based on the NSArray ptrs being
329     // the same across calls.  We can't do that.
330
331     DEFINE_STATIC_LOCAL(RegularExpression, wordRegExp, ("\\w", TextCaseSensitive));
332     String pattern("(");
333     unsigned int numLabels = labels.size();
334     unsigned int i;
335     for (i = 0; i < numLabels; i++) {
336         String label = labels[i];
337
338         bool startsWithWordChar = false;
339         bool endsWithWordChar = false;
340         if (label.length()) {
341             startsWithWordChar = wordRegExp.match(label.substring(0, 1)) >= 0;
342             endsWithWordChar = wordRegExp.match(label.substring(label.length() - 1, 1)) >= 0;
343         }
344
345         if (i)
346             pattern.append("|");
347         // Search for word boundaries only if label starts/ends with "word characters".
348         // If we always searched for word boundaries, this wouldn't work for languages
349         // such as Japanese.
350         if (startsWithWordChar)
351             pattern.append("\\b");
352         pattern.append(label);
353         if (endsWithWordChar)
354             pattern.append("\\b");
355     }
356     pattern.append(")");
357     return new RegularExpression(pattern, TextCaseInsensitive);
358 }
359
360 String Frame::searchForLabelsAboveCell(RegularExpression* regExp, HTMLTableCellElement* cell, size_t* resultDistanceFromStartOfCell)
361 {
362     HTMLTableCellElement* aboveCell = cell->cellAbove();
363     if (aboveCell) {
364         // search within the above cell we found for a match
365         size_t lengthSearched = 0;    
366         for (Node* n = aboveCell->firstChild(); n; n = n->traverseNextNode(aboveCell)) {
367             if (n->isTextNode() && n->renderer() && n->renderer()->style()->visibility() == VISIBLE) {
368                 // For each text chunk, run the regexp
369                 String nodeString = n->nodeValue();
370                 int pos = regExp->searchRev(nodeString);
371                 if (pos >= 0) {
372                     if (resultDistanceFromStartOfCell)
373                         *resultDistanceFromStartOfCell = lengthSearched;
374                     return nodeString.substring(pos, regExp->matchedLength());
375                 }
376                 lengthSearched += nodeString.length();
377             }
378         }
379     }
380
381     // Any reason in practice to search all cells in that are above cell?
382     if (resultDistanceFromStartOfCell)
383         *resultDistanceFromStartOfCell = notFound;
384     return String();
385 }
386
387 String Frame::searchForLabelsBeforeElement(const Vector<String>& labels, Element* element, size_t* resultDistance, bool* resultIsInCellAbove)
388 {
389     OwnPtr<RegularExpression> regExp(createRegExpForLabels(labels));
390     // We stop searching after we've seen this many chars
391     const unsigned int charsSearchedThreshold = 500;
392     // This is the absolute max we search.  We allow a little more slop than
393     // charsSearchedThreshold, to make it more likely that we'll search whole nodes.
394     const unsigned int maxCharsSearched = 600;
395     // If the starting element is within a table, the cell that contains it
396     HTMLTableCellElement* startingTableCell = 0;
397     bool searchedCellAbove = false;
398
399     if (resultDistance)
400         *resultDistance = notFound;
401     if (resultIsInCellAbove)
402         *resultIsInCellAbove = false;
403     
404     // walk backwards in the node tree, until another element, or form, or end of tree
405     int unsigned lengthSearched = 0;
406     Node* n;
407     for (n = element->traversePreviousNode();
408          n && lengthSearched < charsSearchedThreshold;
409          n = n->traversePreviousNode())
410     {
411         if (n->hasTagName(formTag)
412             || (n->isHTMLElement() && static_cast<Element*>(n)->isFormControlElement()))
413         {
414             // We hit another form element or the start of the form - bail out
415             break;
416         } else if (n->hasTagName(tdTag) && !startingTableCell) {
417             startingTableCell = static_cast<HTMLTableCellElement*>(n);
418         } else if (n->hasTagName(trTag) && startingTableCell) {
419             String result = searchForLabelsAboveCell(regExp.get(), startingTableCell, resultDistance);
420             if (!result.isEmpty()) {
421                 if (resultIsInCellAbove)
422                     *resultIsInCellAbove = true;
423                 return result;
424             }
425             searchedCellAbove = true;
426         } else if (n->isTextNode() && n->renderer() && n->renderer()->style()->visibility() == VISIBLE) {
427             // For each text chunk, run the regexp
428             String nodeString = n->nodeValue();
429             // add 100 for slop, to make it more likely that we'll search whole nodes
430             if (lengthSearched + nodeString.length() > maxCharsSearched)
431                 nodeString = nodeString.right(charsSearchedThreshold - lengthSearched);
432             int pos = regExp->searchRev(nodeString);
433             if (pos >= 0) {
434                 if (resultDistance)
435                     *resultDistance = lengthSearched;
436                 return nodeString.substring(pos, regExp->matchedLength());
437             }
438             lengthSearched += nodeString.length();
439         }
440     }
441
442     // If we started in a cell, but bailed because we found the start of the form or the
443     // previous element, we still might need to search the row above us for a label.
444     if (startingTableCell && !searchedCellAbove) {
445          String result = searchForLabelsAboveCell(regExp.get(), startingTableCell, resultDistance);
446         if (!result.isEmpty()) {
447             if (resultIsInCellAbove)
448                 *resultIsInCellAbove = true;
449             return result;
450         }
451     }
452     return String();
453 }
454
455 static String matchLabelsAgainstString(const Vector<String>& labels, const String& stringToMatch)
456 {
457     if (stringToMatch.isEmpty())
458         return String();
459
460     String mutableStringToMatch = stringToMatch;
461
462     // Make numbers and _'s in field names behave like word boundaries, e.g., "address2"
463     replace(mutableStringToMatch, RegularExpression("\\d", TextCaseSensitive), " ");
464     mutableStringToMatch.replace('_', ' ');
465     
466     OwnPtr<RegularExpression> regExp(createRegExpForLabels(labels));
467     // Use the largest match we can find in the whole string
468     int pos;
469     int length;
470     int bestPos = -1;
471     int bestLength = -1;
472     int start = 0;
473     do {
474         pos = regExp->match(mutableStringToMatch, start);
475         if (pos != -1) {
476             length = regExp->matchedLength();
477             if (length >= bestLength) {
478                 bestPos = pos;
479                 bestLength = length;
480             }
481             start = pos + 1;
482         }
483     } while (pos != -1);
484     
485     if (bestPos != -1)
486         return mutableStringToMatch.substring(bestPos, bestLength);
487     return String();
488 }
489     
490 String Frame::matchLabelsAgainstElement(const Vector<String>& labels, Element* element)
491 {
492     // Match against the name element, then against the id element if no match is found for the name element.
493     // See 7538330 for one popular site that benefits from the id element check.
494     // FIXME: This code is mirrored in FrameMac.mm. It would be nice to make the Mac code call the platform-agnostic
495     // code, which would require converting the NSArray of NSStrings to a Vector of Strings somewhere along the way.
496     String resultFromNameAttribute = matchLabelsAgainstString(labels, element->getAttribute(nameAttr));
497     if (!resultFromNameAttribute.isEmpty())
498         return resultFromNameAttribute;
499     
500     return matchLabelsAgainstString(labels, element->getAttribute(idAttr));
501 }
502
503 void Frame::setPrinting(bool printing, const FloatSize& pageSize, float maximumShrinkRatio, AdjustViewSizeOrNot shouldAdjustViewSize)
504 {
505     m_doc->setPrinting(printing);
506     view()->adjustMediaTypeForPrinting(printing);
507
508     m_doc->styleSelectorChanged(RecalcStyleImmediately);
509     view()->forceLayoutForPagination(pageSize, maximumShrinkRatio, shouldAdjustViewSize);
510
511     // Subframes of the one we're printing don't lay out to the page size.
512     for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
513         child->setPrinting(printing, IntSize(), 0, shouldAdjustViewSize);
514 }
515
516 void Frame::injectUserScripts(UserScriptInjectionTime injectionTime)
517 {
518     if (!m_page)
519         return;
520
521     if (loader()->stateMachine()->creatingInitialEmptyDocument())
522         return;
523     
524     // Walk the hashtable. Inject by world.
525     const UserScriptMap* userScripts = m_page->group().userScripts();
526     if (!userScripts)
527         return;
528     UserScriptMap::const_iterator end = userScripts->end();
529     for (UserScriptMap::const_iterator it = userScripts->begin(); it != end; ++it)
530         injectUserScriptsForWorld(it->first.get(), *it->second, injectionTime);
531 }
532
533 void Frame::injectUserScriptsForWorld(DOMWrapperWorld* world, const UserScriptVector& userScripts, UserScriptInjectionTime injectionTime)
534 {
535     if (userScripts.isEmpty())
536         return;
537
538     Document* doc = document();
539     if (!doc)
540         return;
541
542     Vector<ScriptSourceCode> sourceCode;
543     unsigned count = userScripts.size();
544     for (unsigned i = 0; i < count; ++i) {
545         UserScript* script = userScripts[i].get();
546         if (script->injectedFrames() == InjectInTopFrameOnly && ownerElement())
547             continue;
548
549         if (script->injectionTime() == injectionTime && UserContentURLPattern::matchesPatterns(doc->url(), script->whitelist(), script->blacklist()))
550             m_script.evaluateInWorld(ScriptSourceCode(script->source(), script->url()), world);
551     }
552 }
553
554 bool Frame::isContentEditable() const
555 {
556     if (m_editor.clientIsEditable())
557         return true;
558     return m_doc->inDesignMode();
559 }
560
561 #ifndef NDEBUG
562 static HashSet<Frame*>& keepAliveSet()
563 {
564     DEFINE_STATIC_LOCAL(HashSet<Frame*>, staticKeepAliveSet, ());
565     return staticKeepAliveSet;
566 }
567 #endif
568
569 void Frame::keepAlive()
570 {
571     if (m_lifeSupportTimer.isActive())
572         return;
573 #ifndef NDEBUG
574     keepAliveSet().add(this);
575 #endif
576     ref();
577     m_lifeSupportTimer.startOneShot(0);
578 }
579
580 #ifndef NDEBUG
581 void Frame::cancelAllKeepAlive()
582 {
583     HashSet<Frame*>::iterator end = keepAliveSet().end();
584     for (HashSet<Frame*>::iterator it = keepAliveSet().begin(); it != end; ++it) {
585         Frame* frame = *it;
586         frame->m_lifeSupportTimer.stop();
587         frame->deref();
588     }
589     keepAliveSet().clear();
590 }
591 #endif
592
593 void Frame::lifeSupportTimerFired(Timer<Frame>*)
594 {
595 #ifndef NDEBUG
596     keepAliveSet().remove(this);
597 #endif
598     deref();
599 }
600
601 void Frame::clearDOMWindow()
602 {
603     if (m_domWindow) {
604         m_liveFormerWindows.add(m_domWindow.get());
605         m_domWindow->clear();
606     }
607     m_domWindow = 0;
608 }
609
610 RenderView* Frame::contentRenderer() const
611 {
612     Document* doc = document();
613     if (!doc)
614         return 0;
615     RenderObject* object = doc->renderer();
616     if (!object)
617         return 0;
618     ASSERT(object->isRenderView());
619     return toRenderView(object);
620 }
621
622 RenderPart* Frame::ownerRenderer() const
623 {
624     HTMLFrameOwnerElement* ownerElement = m_ownerElement;
625     if (!ownerElement)
626         return 0;
627     RenderObject* object = ownerElement->renderer();
628     if (!object)
629         return 0;
630     // FIXME: If <object> is ever fixed to disassociate itself from frames
631     // that it has started but canceled, then this can turn into an ASSERT
632     // since m_ownerElement would be 0 when the load is canceled.
633     // https://bugs.webkit.org/show_bug.cgi?id=18585
634     if (!object->isRenderPart())
635         return 0;
636     return toRenderPart(object);
637 }
638
639 Frame* Frame::frameForWidget(const Widget* widget)
640 {
641     ASSERT_ARG(widget, widget);
642
643     if (RenderWidget* renderer = RenderWidget::find(widget))
644         if (Node* node = renderer->node())
645             return node->document()->frame();
646
647     // Assume all widgets are either a FrameView or owned by a RenderWidget.
648     // FIXME: That assumption is not right for scroll bars!
649     ASSERT(widget->isFrameView());
650     return static_cast<const FrameView*>(widget)->frame();
651 }
652
653 void Frame::clearTimers(FrameView *view, Document *document)
654 {
655     if (view) {
656         view->unscheduleRelayout();
657         if (view->frame()) {
658             view->frame()->animation()->suspendAnimationsForDocument(document);
659             view->frame()->eventHandler()->stopAutoscrollTimer();
660         }
661     }
662 }
663
664 void Frame::clearTimers()
665 {
666     clearTimers(m_view.get(), document());
667 }
668
669 void Frame::setDOMWindow(DOMWindow* domWindow)
670 {
671     if (m_domWindow) {
672         m_liveFormerWindows.add(m_domWindow.get());
673         m_domWindow->clear();
674     }
675     m_domWindow = domWindow;
676 }
677
678 DOMWindow* Frame::domWindow() const
679 {
680     if (!m_domWindow)
681         m_domWindow = DOMWindow::create(const_cast<Frame*>(this));
682
683     return m_domWindow.get();
684 }
685
686 void Frame::clearFormerDOMWindow(DOMWindow* window)
687 {
688     m_liveFormerWindows.remove(window);
689 }
690
691 void Frame::pageDestroyed()
692 {
693     if (Frame* parent = tree()->parent())
694         parent->loader()->checkLoadComplete();
695
696     if (m_domWindow)
697         m_domWindow->pageDestroyed();
698
699     // FIXME: It's unclear as to why this is called more than once, but it is,
700     // so page() could be NULL.
701     if (page() && page()->focusController()->focusedFrame() == this)
702         page()->focusController()->setFocusedFrame(0);
703
704     script()->clearWindowShell();
705     script()->clearScriptObjects();
706     script()->updatePlatformScriptObjects();
707
708     detachFromPage();
709 }
710
711 void Frame::disconnectOwnerElement()
712 {
713     if (m_ownerElement) {
714         if (Document* doc = document())
715             doc->clearAXObjectCache();
716         m_ownerElement->m_contentFrame = 0;
717         if (m_page)
718             m_page->decrementFrameCount();
719     }
720     m_ownerElement = 0;
721 }
722
723 // The frame is moved in DOM, potentially to another page.
724 void Frame::transferChildFrameToNewDocument()
725 {
726     ASSERT(m_ownerElement);
727     Frame* newParent = m_ownerElement->document()->frame();
728     ASSERT(newParent);
729     bool didTransfer = false;
730
731     // Switch page.
732     Page* newPage = newParent->page();
733     Page* oldPage = m_page;
734     if (m_page != newPage) {
735         if (m_page) {
736             if (m_page->focusController()->focusedFrame() == this)
737                 m_page->focusController()->setFocusedFrame(0);
738
739              m_page->decrementFrameCount();
740         }
741
742         m_page = newPage;
743
744         if (newPage)
745             newPage->incrementFrameCount();
746
747         didTransfer = true;
748     }
749
750     // Update the frame tree.
751     didTransfer = newParent->tree()->transferChild(this) || didTransfer;
752
753     // Avoid unnecessary calls to client and frame subtree if the frame ended
754     // up on the same page and under the same parent frame.
755     if (didTransfer) {
756         // Let external clients update themselves.
757         loader()->client()->didTransferChildFrameToNewDocument(oldPage);
758
759         // Update resource tracking now that frame could be in a different page.
760         if (oldPage != newPage)
761             loader()->transferLoadingResourcesFromPage(oldPage);
762
763         // Do the same for all the children.
764         for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
765             child->transferChildFrameToNewDocument();
766     }
767 }
768
769 String Frame::documentTypeString() const
770 {
771     if (DocumentType* doctype = document()->doctype())
772         return createMarkup(doctype);
773
774     return String();
775 }
776
777 VisiblePosition Frame::visiblePositionForPoint(const IntPoint& framePoint)
778 {
779     HitTestResult result = eventHandler()->hitTestResultAtPoint(framePoint, true);
780     Node* node = result.innerNode();
781     if (!node)
782         return VisiblePosition();
783     RenderObject* renderer = node->renderer();
784     if (!renderer)
785         return VisiblePosition();
786     VisiblePosition visiblePos = renderer->positionForPoint(result.localPoint());
787     if (visiblePos.isNull())
788         visiblePos = VisiblePosition(Position(node, 0));
789     return visiblePos;
790 }
791
792 Document* Frame::documentAtPoint(const IntPoint& point)
793 {
794     if (!view())
795         return 0;
796
797     IntPoint pt = view()->windowToContents(point);
798     HitTestResult result = HitTestResult(pt);
799
800     if (contentRenderer())
801         result = eventHandler()->hitTestResultAtPoint(pt, false);
802     return result.innerNode() ? result.innerNode()->document() : 0;
803 }
804
805 void Frame::createView(const IntSize& viewportSize,
806                        const Color& backgroundColor, bool transparent,
807                        const IntSize& fixedLayoutSize, bool useFixedLayout,
808                        ScrollbarMode horizontalScrollbarMode, bool horizontalLock,
809                        ScrollbarMode verticalScrollbarMode, bool verticalLock)
810 {
811     ASSERT(this);
812     ASSERT(m_page);
813
814     bool isMainFrame = this == m_page->mainFrame();
815
816     if (isMainFrame && view())
817         view()->setParentVisible(false);
818
819     setView(0);
820
821     RefPtr<FrameView> frameView;
822     if (isMainFrame) {
823         frameView = FrameView::create(this, viewportSize);
824         frameView->setFixedLayoutSize(fixedLayoutSize);
825         frameView->setUseFixedLayout(useFixedLayout);
826     } else
827         frameView = FrameView::create(this);
828
829     frameView->setScrollbarModes(horizontalScrollbarMode, verticalScrollbarMode, horizontalLock, verticalLock);
830
831     setView(frameView);
832
833     if (backgroundColor.isValid())
834         frameView->updateBackgroundRecursively(backgroundColor, transparent);
835
836     if (isMainFrame)
837         frameView->setParentVisible(true);
838
839     if (ownerRenderer())
840         ownerRenderer()->setWidget(frameView);
841
842     if (HTMLFrameOwnerElement* owner = ownerElement())
843         view()->setCanHaveScrollbars(owner->scrollingMode() != ScrollbarAlwaysOff);
844 }
845
846 #if ENABLE(TILED_BACKING_STORE)
847 void Frame::setTiledBackingStoreEnabled(bool enabled)
848 {
849     if (!enabled) {
850         m_tiledBackingStore.clear();
851         return;
852     }
853     if (m_tiledBackingStore)
854         return;
855     m_tiledBackingStore.set(new TiledBackingStore(this));
856     if (m_view)
857         m_view->setPaintsEntireContents(true);
858 }
859
860 void Frame::tiledBackingStorePaintBegin()
861 {
862     if (!m_view)
863         return;
864     m_view->updateLayoutAndStyleIfNeededRecursive();
865     m_view->flushDeferredRepaints();
866 }
867
868 void Frame::tiledBackingStorePaint(GraphicsContext* context, const IntRect& rect)
869 {
870     if (!m_view)
871         return;
872     m_view->paintContents(context, rect);
873 }
874
875 void Frame::tiledBackingStorePaintEnd(const Vector<IntRect>& paintedArea)
876 {
877     if (!m_page || !m_view)
878         return;
879     unsigned size = paintedArea.size();
880     // Request repaint from the system
881     for (int n = 0; n < size; ++n)
882         m_page->chrome()->invalidateContentsAndWindow(m_view->contentsToWindow(paintedArea[n]), false);
883 }
884
885 IntRect Frame::tiledBackingStoreContentsRect()
886 {
887     if (!m_view)
888         return IntRect();
889     return IntRect(IntPoint(), m_view->contentsSize());
890 }
891
892 IntRect Frame::tiledBackingStoreVisibleRect()
893 {
894     if (!m_page)
895         return IntRect();
896     return m_page->chrome()->client()->visibleRectForTiledBackingStore();
897 }
898
899 Color Frame::tiledBackingStoreBackgroundColor() const
900 {
901     if (!m_view)
902         return Color();
903     return m_view->baseBackgroundColor();
904 }
905 #endif
906
907 String Frame::layerTreeAsText() const
908 {
909 #if USE(ACCELERATED_COMPOSITING)
910     document()->updateLayout();
911
912     if (!contentRenderer())
913         return String();
914
915     return contentRenderer()->compositor()->layerTreeAsText();
916 #else
917     return String();
918 #endif
919 }
920
921 void Frame::setPageZoomFactor(float factor)
922 {
923     setPageAndTextZoomFactors(factor, m_textZoomFactor);
924 }
925
926 void Frame::setTextZoomFactor(float factor)
927 {
928     setPageAndTextZoomFactors(m_pageZoomFactor, factor);
929 }
930
931 void Frame::setPageAndTextZoomFactors(float pageZoomFactor, float textZoomFactor)
932 {
933     if (m_pageZoomFactor == pageZoomFactor && m_textZoomFactor == textZoomFactor)
934         return;
935
936     Page* page = this->page();
937     if (!page)
938         return;
939
940     Document* document = this->document();
941     if (!document)
942         return;
943
944 #if ENABLE(SVG)
945     // Respect SVGs zoomAndPan="disabled" property in standalone SVG documents.
946     // FIXME: How to handle compound documents + zoomAndPan="disabled"? Needs SVG WG clarification.
947     if (document->isSVGDocument()) {
948         if (!static_cast<SVGDocument*>(document)->zoomAndPanEnabled())
949             return;
950         if (document->renderer())
951             document->renderer()->setNeedsLayout(true);
952     }
953 #endif
954
955     if (m_pageZoomFactor != pageZoomFactor) {
956         if (FrameView* view = this->view()) {
957             // Update the scroll position when doing a full page zoom, so the content stays in relatively the same position.
958             IntPoint scrollPosition = view->scrollPosition();
959             float percentDifference = (pageZoomFactor / m_pageZoomFactor);
960             view->setScrollPosition(IntPoint(scrollPosition.x() * percentDifference, scrollPosition.y() * percentDifference));
961         }
962     }
963
964     m_pageZoomFactor = pageZoomFactor;
965     m_textZoomFactor = textZoomFactor;
966
967     document->recalcStyle(Node::Force);
968
969     for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
970         child->setPageAndTextZoomFactors(m_pageZoomFactor, m_textZoomFactor);
971
972     if (FrameView* view = this->view()) {
973         if (document->renderer() && document->renderer()->needsLayout() && view->didFirstLayout())
974             view->layout();
975     }
976 }
977
978 void Frame::scalePage(float scale, const IntPoint& origin)
979 {
980     Document* document = this->document();
981     if (!document)
982         return;
983
984     m_pageScaleFactor = scale;
985
986     if (document->renderer())
987         document->renderer()->setNeedsLayout(true);
988
989     document->recalcStyle(Node::Force);
990
991     if (FrameView* view = this->view()) {
992         if (document->renderer() && document->renderer()->needsLayout() && view->didFirstLayout())
993             view->layout();
994         view->setScrollPosition(origin);
995     }
996 }
997
998 } // namespace WebCore