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