91d31e3bfd147a890f76a739000d3b002534f8b4
[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 "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 "FrameDestructionObserver.h"
50 #include "FrameLoader.h"
51 #include "FrameLoaderClient.h"
52 #include "FrameView.h"
53 #include "GraphicsContext.h"
54 #include "GraphicsLayer.h"
55 #include "HTMLDocument.h"
56 #include "HTMLFormControlElement.h"
57 #include "HTMLFormElement.h"
58 #include "HTMLFrameElementBase.h"
59 #include "HTMLNames.h"
60 #include "HTMLTableCellElement.h"
61 #include "HitTestResult.h"
62 #include "ImageBuffer.h"
63 #include "InspectorInstrumentation.h"
64 #include "Logging.h"
65 #include "MediaFeatureNames.h"
66 #include "Navigator.h"
67 #include "NodeList.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 "Settings.h"
82 #include "StylePropertySet.h"
83 #include "TextIterator.h"
84 #include "TextResourceDecoder.h"
85 #include "UserContentURLPattern.h"
86 #include "UserTypingGestureIndicator.h"
87 #include "WebKitFontFamilyNames.h"
88 #include "XMLNSNames.h"
89 #include "XMLNames.h"
90 #include "htmlediting.h"
91 #include "markup.h"
92 #include "npruntime_impl.h"
93 #include "visible_units.h"
94 #include <wtf/RefCountedLeakCounter.h>
95 #include <wtf/StdLibExtras.h>
96
97 #if USE(ACCELERATED_COMPOSITING)
98 #include "RenderLayerCompositor.h"
99 #endif
100
101 #if USE(JSC)
102 #include "JSDOMWindowShell.h"
103 #include "runtime_root.h"
104 #endif
105
106 #include "MathMLNames.h"
107 #include "SVGNames.h"
108 #include "XLinkNames.h"
109
110 #if ENABLE(SVG)
111 #include "SVGDocument.h"
112 #include "SVGDocumentExtensions.h"
113 #endif
114
115 #if USE(TILED_BACKING_STORE)
116 #include "TiledBackingStore.h"
117 #endif
118
119 using namespace std;
120
121 namespace WebCore {
122
123 using namespace HTMLNames;
124
125 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, frameCounter, ("Frame"));
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_selection(this)
159     , m_eventHandler(this)
160     , m_animationController(this)
161     , m_pageZoomFactor(parentPageZoomFactor(this))
162     , m_textZoomFactor(parentTextZoomFactor(this))
163 #if ENABLE(ORIENTATION_EVENTS)
164     , m_orientation(0)
165 #endif
166     , m_inViewSourceMode(false)
167     , m_activeDOMObjectsAndAnimationsSuspendedCount(0)
168 {
169     ASSERT(page);
170     AtomicString::init();
171     HTMLNames::init();
172     QualifiedName::init();
173     MediaFeatureNames::init();
174     SVGNames::init();
175     XLinkNames::init();
176     MathMLNames::init();
177     XMLNSNames::init();
178     XMLNames::init();
179     WebKitFontFamilyNames::init();
180
181     if (!ownerElement) {
182 #if USE(TILED_BACKING_STORE)
183         // Top level frame only for now.
184         setTiledBackingStoreEnabled(page->settings()->tiledBackingStoreEnabled());
185 #endif
186     } else {
187         page->incrementFrameCount();
188
189         // Make sure we will not end up with two frames referencing the same owner element.
190         Frame*& contentFrameSlot = ownerElement->m_contentFrame;
191         ASSERT(!contentFrameSlot || contentFrameSlot->ownerElement() != ownerElement);
192         contentFrameSlot = this;
193     }
194
195 #ifndef NDEBUG
196     frameCounter.increment();
197 #endif
198
199     // Pause future ActiveDOMObjects if this frame is being created while the page is in a paused state.
200     Frame* parent = parentFromOwnerElement(ownerElement);
201     if (parent && parent->activeDOMObjectsAndAnimationsSuspended())
202         suspendActiveDOMObjectsAndAnimations();
203 }
204
205 PassRefPtr<Frame> Frame::create(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* client)
206 {
207     RefPtr<Frame> frame = adoptRef(new Frame(page, ownerElement, client));
208     if (!ownerElement)
209         page->setMainFrame(frame);
210     return frame.release();
211 }
212
213 Frame::~Frame()
214 {
215     setView(0);
216     loader()->cancelAndClear();
217
218     // FIXME: We should not be doing all this work inside the destructor
219
220 #ifndef NDEBUG
221     frameCounter.decrement();
222 #endif
223
224     disconnectOwnerElement();
225
226     HashSet<FrameDestructionObserver*>::iterator stop = m_destructionObservers.end();
227     for (HashSet<FrameDestructionObserver*>::iterator it = m_destructionObservers.begin(); it != stop; ++it)
228         (*it)->frameDestroyed();
229
230     if (m_view) {
231         m_view->hide();
232         m_view->clearFrame();
233     }
234 }
235
236 bool Frame::inScope(TreeScope* scope) const
237 {
238     ASSERT(scope);
239     HTMLFrameOwnerElement* owner = document()->ownerElement();
240     // Scoping test should be done only for child frames.
241     ASSERT(owner);
242     return owner->treeScope() == scope;
243 }
244
245 void Frame::addDestructionObserver(FrameDestructionObserver* observer)
246 {
247     m_destructionObservers.add(observer);
248 }
249
250 void Frame::removeDestructionObserver(FrameDestructionObserver* observer)
251 {
252     m_destructionObservers.remove(observer);
253 }
254
255 void Frame::setView(PassRefPtr<FrameView> view)
256 {
257     // We the custom scroll bars as early as possible to prevent m_doc->detach()
258     // from messing with the view such that its scroll bars won't be torn down.
259     // FIXME: We should revisit this.
260     if (m_view)
261         m_view->detachCustomScrollbars();
262
263     // Prepare for destruction now, so any unload event handlers get run and the DOMWindow is
264     // notified. If we wait until the view is destroyed, then things won't be hooked up enough for
265     // these calls to work.
266     if (!view && m_doc && m_doc->attached() && !m_doc->inPageCache()) {
267         // FIXME: We don't call willRemove here. Why is that OK?
268         m_doc->prepareForDestruction();
269     }
270     
271     if (m_view)
272         m_view->unscheduleRelayout();
273     
274     eventHandler()->clear();
275
276     m_view = view;
277
278     // Only one form submission is allowed per view of a part.
279     // Since this part may be getting reused as a result of being
280     // pulled from the back/forward cache, reset this flag.
281     loader()->resetMultipleFormSubmissionProtection();
282     
283 #if USE(TILED_BACKING_STORE)
284     if (m_view && tiledBackingStore())
285         m_view->setPaintsEntireContents(true);
286 #endif
287 }
288
289 void Frame::setDocument(PassRefPtr<Document> newDoc)
290 {
291     ASSERT(!newDoc || newDoc->frame());
292     if (m_doc && m_doc->attached() && !m_doc->inPageCache()) {
293         // FIXME: We don't call willRemove here. Why is that OK?
294         m_doc->detach();
295     }
296
297     m_doc = newDoc;
298     selection()->updateSecureKeyboardEntryIfActive();
299
300     if (m_doc && !m_doc->attached())
301         m_doc->attach();
302
303     // Update the cached 'document' property, which is now stale.
304     m_script.updateDocument();
305
306     if (m_doc)
307         m_doc->updateViewportArguments();
308
309     if (m_page && m_page->mainFrame() == this) {
310         notifyChromeClientWheelEventHandlerCountChanged();
311         notifyChromeClientTouchEventHandlerCountChanged();
312     }
313
314     // Suspend document if this frame was created in suspended state.
315     if (m_doc && activeDOMObjectsAndAnimationsSuspended()) {
316         m_doc->suspendScriptedAnimationControllerCallbacks();
317         m_animationController.suspendAnimationsForDocument(m_doc.get());
318         m_doc->suspendActiveDOMObjects(ActiveDOMObject::PageWillBeSuspended);
319     }
320 }
321
322 #if ENABLE(ORIENTATION_EVENTS)
323 void Frame::sendOrientationChangeEvent(int orientation)
324 {
325     m_orientation = orientation;
326     if (Document* doc = document())
327         doc->dispatchWindowEvent(Event::create(eventNames().orientationchangeEvent, false, false));
328 }
329 #endif // ENABLE(ORIENTATION_EVENTS)
330     
331 Settings* Frame::settings() const
332 {
333     return m_page ? m_page->settings() : 0;
334 }
335
336 static PassOwnPtr<RegularExpression> createRegExpForLabels(const Vector<String>& labels)
337 {
338     // REVIEW- version of this call in FrameMac.mm caches based on the NSArray ptrs being
339     // the same across calls.  We can't do that.
340
341     DEFINE_STATIC_LOCAL(RegularExpression, wordRegExp, ("\\w", TextCaseSensitive));
342     String pattern("(");
343     unsigned int numLabels = labels.size();
344     unsigned int i;
345     for (i = 0; i < numLabels; i++) {
346         String label = labels[i];
347
348         bool startsWithWordChar = false;
349         bool endsWithWordChar = false;
350         if (label.length()) {
351             startsWithWordChar = wordRegExp.match(label.substring(0, 1)) >= 0;
352             endsWithWordChar = wordRegExp.match(label.substring(label.length() - 1, 1)) >= 0;
353         }
354
355         if (i)
356             pattern.append("|");
357         // Search for word boundaries only if label starts/ends with "word characters".
358         // If we always searched for word boundaries, this wouldn't work for languages
359         // such as Japanese.
360         if (startsWithWordChar)
361             pattern.append("\\b");
362         pattern.append(label);
363         if (endsWithWordChar)
364             pattern.append("\\b");
365     }
366     pattern.append(")");
367     return adoptPtr(new RegularExpression(pattern, TextCaseInsensitive));
368 }
369
370 String Frame::searchForLabelsAboveCell(RegularExpression* regExp, HTMLTableCellElement* cell, size_t* resultDistanceFromStartOfCell)
371 {
372     HTMLTableCellElement* aboveCell = cell->cellAbove();
373     if (aboveCell) {
374         // search within the above cell we found for a match
375         size_t lengthSearched = 0;    
376         for (Node* n = aboveCell->firstChild(); n; n = n->traverseNextNode(aboveCell)) {
377             if (n->isTextNode() && n->renderer() && n->renderer()->style()->visibility() == VISIBLE) {
378                 // For each text chunk, run the regexp
379                 String nodeString = n->nodeValue();
380                 int pos = regExp->searchRev(nodeString);
381                 if (pos >= 0) {
382                     if (resultDistanceFromStartOfCell)
383                         *resultDistanceFromStartOfCell = lengthSearched;
384                     return nodeString.substring(pos, regExp->matchedLength());
385                 }
386                 lengthSearched += nodeString.length();
387             }
388         }
389     }
390
391     // Any reason in practice to search all cells in that are above cell?
392     if (resultDistanceFromStartOfCell)
393         *resultDistanceFromStartOfCell = notFound;
394     return String();
395 }
396
397 String Frame::searchForLabelsBeforeElement(const Vector<String>& labels, Element* element, size_t* resultDistance, bool* resultIsInCellAbove)
398 {
399     OwnPtr<RegularExpression> regExp(createRegExpForLabels(labels));
400     // We stop searching after we've seen this many chars
401     const unsigned int charsSearchedThreshold = 500;
402     // This is the absolute max we search.  We allow a little more slop than
403     // charsSearchedThreshold, to make it more likely that we'll search whole nodes.
404     const unsigned int maxCharsSearched = 600;
405     // If the starting element is within a table, the cell that contains it
406     HTMLTableCellElement* startingTableCell = 0;
407     bool searchedCellAbove = false;
408
409     if (resultDistance)
410         *resultDistance = notFound;
411     if (resultIsInCellAbove)
412         *resultIsInCellAbove = false;
413     
414     // walk backwards in the node tree, until another element, or form, or end of tree
415     int unsigned lengthSearched = 0;
416     Node* n;
417     for (n = element->traversePreviousNode();
418          n && lengthSearched < charsSearchedThreshold;
419          n = n->traversePreviousNode())
420     {
421         if (n->hasTagName(formTag)
422             || (n->isHTMLElement() && static_cast<Element*>(n)->isFormControlElement()))
423         {
424             // We hit another form element or the start of the form - bail out
425             break;
426         } else if (n->hasTagName(tdTag) && !startingTableCell) {
427             startingTableCell = static_cast<HTMLTableCellElement*>(n);
428         } else if (n->hasTagName(trTag) && startingTableCell) {
429             String result = searchForLabelsAboveCell(regExp.get(), startingTableCell, resultDistance);
430             if (!result.isEmpty()) {
431                 if (resultIsInCellAbove)
432                     *resultIsInCellAbove = true;
433                 return result;
434             }
435             searchedCellAbove = true;
436         } else if (n->isTextNode() && n->renderer() && n->renderer()->style()->visibility() == VISIBLE) {
437             // For each text chunk, run the regexp
438             String nodeString = n->nodeValue();
439             // add 100 for slop, to make it more likely that we'll search whole nodes
440             if (lengthSearched + nodeString.length() > maxCharsSearched)
441                 nodeString = nodeString.right(charsSearchedThreshold - lengthSearched);
442             int pos = regExp->searchRev(nodeString);
443             if (pos >= 0) {
444                 if (resultDistance)
445                     *resultDistance = lengthSearched;
446                 return nodeString.substring(pos, regExp->matchedLength());
447             }
448             lengthSearched += nodeString.length();
449         }
450     }
451
452     // If we started in a cell, but bailed because we found the start of the form or the
453     // previous element, we still might need to search the row above us for a label.
454     if (startingTableCell && !searchedCellAbove) {
455          String result = searchForLabelsAboveCell(regExp.get(), startingTableCell, resultDistance);
456         if (!result.isEmpty()) {
457             if (resultIsInCellAbove)
458                 *resultIsInCellAbove = true;
459             return result;
460         }
461     }
462     return String();
463 }
464
465 static String matchLabelsAgainstString(const Vector<String>& labels, const String& stringToMatch)
466 {
467     if (stringToMatch.isEmpty())
468         return String();
469
470     String mutableStringToMatch = stringToMatch;
471
472     // Make numbers and _'s in field names behave like word boundaries, e.g., "address2"
473     replace(mutableStringToMatch, RegularExpression("\\d", TextCaseSensitive), " ");
474     mutableStringToMatch.replace('_', ' ');
475     
476     OwnPtr<RegularExpression> regExp(createRegExpForLabels(labels));
477     // Use the largest match we can find in the whole string
478     int pos;
479     int length;
480     int bestPos = -1;
481     int bestLength = -1;
482     int start = 0;
483     do {
484         pos = regExp->match(mutableStringToMatch, start);
485         if (pos != -1) {
486             length = regExp->matchedLength();
487             if (length >= bestLength) {
488                 bestPos = pos;
489                 bestLength = length;
490             }
491             start = pos + 1;
492         }
493     } while (pos != -1);
494     
495     if (bestPos != -1)
496         return mutableStringToMatch.substring(bestPos, bestLength);
497     return String();
498 }
499     
500 String Frame::matchLabelsAgainstElement(const Vector<String>& labels, Element* element)
501 {
502     // Match against the name element, then against the id element if no match is found for the name element.
503     // See 7538330 for one popular site that benefits from the id element check.
504     // FIXME: This code is mirrored in FrameMac.mm. It would be nice to make the Mac code call the platform-agnostic
505     // code, which would require converting the NSArray of NSStrings to a Vector of Strings somewhere along the way.
506     String resultFromNameAttribute = matchLabelsAgainstString(labels, element->getNameAttribute());
507     if (!resultFromNameAttribute.isEmpty())
508         return resultFromNameAttribute;
509     
510     return matchLabelsAgainstString(labels, element->getAttribute(idAttr));
511 }
512
513 void Frame::setPrinting(bool printing, const FloatSize& pageSize, const FloatSize& originalPageSize, float maximumShrinkRatio, AdjustViewSizeOrNot shouldAdjustViewSize)
514 {
515     // In setting printing, we should not validate resources already cached for the document.
516     // See https://bugs.webkit.org/show_bug.cgi?id=43704
517     ResourceCacheValidationSuppressor validationSuppressor(m_doc->cachedResourceLoader());
518
519     m_doc->setPrinting(printing);
520     view()->adjustMediaTypeForPrinting(printing);
521
522     m_doc->styleResolverChanged(RecalcStyleImmediately);
523     if (shouldUsePrintingLayout()) {
524         view()->forceLayoutForPagination(pageSize, originalPageSize, maximumShrinkRatio, shouldAdjustViewSize);
525     } else {
526         view()->forceLayout();
527         if (shouldAdjustViewSize == AdjustViewSize)
528             view()->adjustViewSize();
529     }
530
531     // Subframes of the one we're printing don't lay out to the page size.
532     for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
533         child->setPrinting(printing, FloatSize(), FloatSize(), 0, shouldAdjustViewSize);
534 }
535
536 bool Frame::shouldUsePrintingLayout() const
537 {
538     // Only top frame being printed should be fit to page size.
539     // Subframes should be constrained by parents only.
540     return m_doc->printing() && (!tree()->parent() || !tree()->parent()->m_doc->printing());
541 }
542
543 FloatSize Frame::resizePageRectsKeepingRatio(const FloatSize& originalSize, const FloatSize& expectedSize)
544 {
545     FloatSize resultSize;
546     if (!contentRenderer())
547         return FloatSize();
548
549     if (contentRenderer()->style()->isHorizontalWritingMode()) {
550         ASSERT(fabs(originalSize.width()) > numeric_limits<float>::epsilon());
551         float ratio = originalSize.height() / originalSize.width();
552         resultSize.setWidth(floorf(expectedSize.width()));
553         resultSize.setHeight(floorf(resultSize.width() * ratio));
554     } else {
555         ASSERT(fabs(originalSize.height()) > numeric_limits<float>::epsilon());
556         float ratio = originalSize.width() / originalSize.height();
557         resultSize.setHeight(floorf(expectedSize.height()));
558         resultSize.setWidth(floorf(resultSize.height() * ratio));
559     }
560     return resultSize;
561 }
562
563 void Frame::injectUserScripts(UserScriptInjectionTime injectionTime)
564 {
565     if (!m_page)
566         return;
567
568     if (loader()->stateMachine()->creatingInitialEmptyDocument() && !settings()->shouldInjectUserScriptsInInitialEmptyDocument())
569         return;
570
571     // Walk the hashtable. Inject by world.
572     const UserScriptMap* userScripts = m_page->group().userScripts();
573     if (!userScripts)
574         return;
575     UserScriptMap::const_iterator end = userScripts->end();
576     for (UserScriptMap::const_iterator it = userScripts->begin(); it != end; ++it)
577         injectUserScriptsForWorld(it->first.get(), *it->second, injectionTime);
578 }
579
580 void Frame::injectUserScriptsForWorld(DOMWrapperWorld* world, const UserScriptVector& userScripts, UserScriptInjectionTime injectionTime)
581 {
582     if (userScripts.isEmpty())
583         return;
584
585     Document* doc = document();
586     if (!doc)
587         return;
588
589     Vector<ScriptSourceCode> sourceCode;
590     unsigned count = userScripts.size();
591     for (unsigned i = 0; i < count; ++i) {
592         UserScript* script = userScripts[i].get();
593         if (script->injectedFrames() == InjectInTopFrameOnly && ownerElement())
594             continue;
595
596         if (script->injectionTime() == injectionTime && UserContentURLPattern::matchesPatterns(doc->url(), script->whitelist(), script->blacklist()))
597             m_script.evaluateInWorld(ScriptSourceCode(script->source(), script->url()), world);
598     }
599 }
600
601 void Frame::clearDOMWindow()
602 {
603     if (m_domWindow) {
604         InspectorInstrumentation::frameWindowDiscarded(this, 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         InspectorInstrumentation::frameWindowDiscarded(this, m_domWindow.get());
673         m_domWindow->clear();
674     }
675     m_domWindow = domWindow;
676 }
677
678 #if ENABLE(PAGE_VISIBILITY_API)
679 void Frame::dispatchVisibilityStateChangeEvent()
680 {
681     if (m_doc)
682         m_doc->dispatchVisibilityStateChangeEvent();
683     for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
684         child->dispatchVisibilityStateChangeEvent();
685 }
686 #endif
687
688 DOMWindow* Frame::domWindow() const
689 {
690     if (!m_domWindow)
691         m_domWindow = DOMWindow::create(const_cast<Frame*>(this));
692
693     return m_domWindow.get();
694 }
695
696 void Frame::willDetachPage()
697 {
698     if (Frame* parent = tree()->parent())
699         parent->loader()->checkLoadComplete();
700
701     HashSet<FrameDestructionObserver*>::iterator stop = m_destructionObservers.end();
702     for (HashSet<FrameDestructionObserver*>::iterator it = m_destructionObservers.begin(); it != stop; ++it)
703         (*it)->willDetachPage();
704
705     // FIXME: It's unclear as to why this is called more than once, but it is,
706     // so page() could be NULL.
707     if (page() && page()->focusController()->focusedFrame() == this)
708         page()->focusController()->setFocusedFrame(0);
709
710     script()->clearScriptObjects();
711     script()->updatePlatformScriptObjects();
712 }
713
714 void Frame::disconnectOwnerElement()
715 {
716     if (m_ownerElement) {
717         if (Document* doc = document())
718             doc->clearAXObjectCache();
719         m_ownerElement->m_contentFrame = 0;
720         if (m_page)
721             m_page->decrementFrameCount();
722     }
723     m_ownerElement = 0;
724 }
725
726 String Frame::documentTypeString() const
727 {
728     if (DocumentType* doctype = document()->doctype())
729         return createMarkup(doctype);
730
731     return String();
732 }
733
734 String Frame::displayStringModifiedByEncoding(const String& str) const
735 {
736     return document() ? document()->displayStringModifiedByEncoding(str) : str;
737 }
738
739 VisiblePosition Frame::visiblePositionForPoint(const IntPoint& framePoint)
740 {
741     HitTestResult result = eventHandler()->hitTestResultAtPoint(framePoint, true);
742     Node* node = result.innerNonSharedNode();
743     if (!node)
744         return VisiblePosition();
745     RenderObject* renderer = node->renderer();
746     if (!renderer)
747         return VisiblePosition();
748     VisiblePosition visiblePos = renderer->positionForPoint(result.localPoint());
749     if (visiblePos.isNull())
750         visiblePos = firstPositionInOrBeforeNode(node);
751     return visiblePos;
752 }
753
754 Document* Frame::documentAtPoint(const IntPoint& point)
755 {
756     if (!view())
757         return 0;
758
759     IntPoint pt = view()->windowToContents(point);
760     HitTestResult result = HitTestResult(pt);
761
762     if (contentRenderer())
763         result = eventHandler()->hitTestResultAtPoint(pt, false);
764     return result.innerNode() ? result.innerNode()->document() : 0;
765 }
766
767 PassRefPtr<Range> Frame::rangeForPoint(const IntPoint& framePoint)
768 {
769     VisiblePosition position = visiblePositionForPoint(framePoint);
770     if (position.isNull())
771         return 0;
772
773     VisiblePosition previous = position.previous();
774     if (previous.isNotNull()) {
775         RefPtr<Range> previousCharacterRange = makeRange(previous, position);
776         LayoutRect rect = editor()->firstRectForRange(previousCharacterRange.get());
777         if (rect.contains(framePoint))
778             return previousCharacterRange.release();
779     }
780
781     VisiblePosition next = position.next();
782     if (RefPtr<Range> nextCharacterRange = makeRange(position, next)) {
783         LayoutRect rect = editor()->firstRectForRange(nextCharacterRange.get());
784         if (rect.contains(framePoint))
785             return nextCharacterRange.release();
786     }
787
788     return 0;
789 }
790
791 void Frame::createView(const IntSize& viewportSize,
792                        const Color& backgroundColor, bool transparent,
793                        const IntSize& fixedLayoutSize, bool useFixedLayout,
794                        ScrollbarMode horizontalScrollbarMode, bool horizontalLock,
795                        ScrollbarMode verticalScrollbarMode, bool verticalLock)
796 {
797     ASSERT(this);
798     ASSERT(m_page);
799
800     bool isMainFrame = this == m_page->mainFrame();
801
802     if (isMainFrame && view())
803         view()->setParentVisible(false);
804
805     setView(0);
806
807     RefPtr<FrameView> frameView;
808     if (isMainFrame) {
809         frameView = FrameView::create(this, viewportSize);
810         frameView->setFixedLayoutSize(fixedLayoutSize);
811         frameView->setUseFixedLayout(useFixedLayout);
812     } else
813         frameView = FrameView::create(this);
814
815     frameView->setScrollbarModes(horizontalScrollbarMode, verticalScrollbarMode, horizontalLock, verticalLock);
816
817     setView(frameView);
818
819     if (backgroundColor.isValid())
820         frameView->updateBackgroundRecursively(backgroundColor, transparent);
821
822     if (isMainFrame)
823         frameView->setParentVisible(true);
824
825     if (ownerRenderer())
826         ownerRenderer()->setWidget(frameView);
827
828     if (HTMLFrameOwnerElement* owner = ownerElement())
829         view()->setCanHaveScrollbars(owner->scrollingMode() != ScrollbarAlwaysOff);
830 }
831
832 #if USE(TILED_BACKING_STORE)
833 void Frame::setTiledBackingStoreEnabled(bool enabled)
834 {
835     if (!enabled) {
836         m_tiledBackingStore.clear();
837         return;
838     }
839     if (m_tiledBackingStore)
840         return;
841     m_tiledBackingStore = adoptPtr(new TiledBackingStore(this));
842     if (m_view)
843         m_view->setPaintsEntireContents(true);
844 }
845
846 void Frame::tiledBackingStorePaintBegin()
847 {
848     if (!m_view)
849         return;
850     m_view->updateLayoutAndStyleIfNeededRecursive();
851     m_view->flushDeferredRepaints();
852 }
853
854 void Frame::tiledBackingStorePaint(GraphicsContext* context, const IntRect& rect)
855 {
856     if (!m_view)
857         return;
858     m_view->paintContents(context, rect);
859 }
860
861 void Frame::tiledBackingStorePaintEnd(const Vector<IntRect>& paintedArea)
862 {
863     if (!m_page || !m_view)
864         return;
865     unsigned size = paintedArea.size();
866     // Request repaint from the system
867     for (int n = 0; n < size; ++n)
868         m_page->chrome()->invalidateContentsAndRootView(m_view->contentsToRootView(paintedArea[n]), false);
869 }
870
871 IntRect Frame::tiledBackingStoreContentsRect()
872 {
873     if (!m_view)
874         return IntRect();
875     return IntRect(IntPoint(), m_view->contentsSize());
876 }
877
878 IntRect Frame::tiledBackingStoreVisibleRect()
879 {
880     if (!m_page)
881         return IntRect();
882     return m_page->chrome()->client()->visibleRectForTiledBackingStore();
883 }
884
885 Color Frame::tiledBackingStoreBackgroundColor() const
886 {
887     if (!m_view)
888         return Color();
889     return m_view->baseBackgroundColor();
890 }
891 #endif
892
893 String Frame::layerTreeAsText(bool showDebugInfo) const
894 {
895 #if USE(ACCELERATED_COMPOSITING)
896     document()->updateLayout();
897
898     if (!contentRenderer())
899         return String();
900
901     return contentRenderer()->compositor()->layerTreeAsText(showDebugInfo);
902 #else
903     return String();
904 #endif
905 }
906
907 void Frame::setPageZoomFactor(float factor)
908 {
909     setPageAndTextZoomFactors(factor, m_textZoomFactor);
910 }
911
912 void Frame::setTextZoomFactor(float factor)
913 {
914     setPageAndTextZoomFactors(m_pageZoomFactor, factor);
915 }
916
917 void Frame::setPageAndTextZoomFactors(float pageZoomFactor, float textZoomFactor)
918 {
919     if (m_pageZoomFactor == pageZoomFactor && m_textZoomFactor == textZoomFactor)
920         return;
921
922     Page* page = this->page();
923     if (!page)
924         return;
925
926     Document* document = this->document();
927     if (!document)
928         return;
929
930     m_editor.dismissCorrectionPanelAsIgnored();
931
932 #if ENABLE(SVG)
933     // Respect SVGs zoomAndPan="disabled" property in standalone SVG documents.
934     // FIXME: How to handle compound documents + zoomAndPan="disabled"? Needs SVG WG clarification.
935     if (document->isSVGDocument()) {
936         if (!static_cast<SVGDocument*>(document)->zoomAndPanEnabled())
937             return;
938     }
939 #endif
940
941     if (m_pageZoomFactor != pageZoomFactor) {
942         if (FrameView* view = this->view()) {
943             // Update the scroll position when doing a full page zoom, so the content stays in relatively the same position.
944             LayoutPoint scrollPosition = view->scrollPosition();
945             float percentDifference = (pageZoomFactor / m_pageZoomFactor);
946             view->setScrollPosition(IntPoint(scrollPosition.x() * percentDifference, scrollPosition.y() * percentDifference));
947         }
948     }
949
950     m_pageZoomFactor = pageZoomFactor;
951     m_textZoomFactor = textZoomFactor;
952
953     document->recalcStyle(Node::Force);
954
955     for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
956         child->setPageAndTextZoomFactors(m_pageZoomFactor, m_textZoomFactor);
957
958     if (FrameView* view = this->view()) {
959         if (document->renderer() && document->renderer()->needsLayout() && view->didFirstLayout())
960             view->layout();
961     }
962
963     if (page->mainFrame() == this)
964         pageCache()->markPagesForFullStyleRecalc(page);
965 }
966
967 float Frame::frameScaleFactor() const
968 {
969     Page* page = this->page();
970
971     // Main frame is scaled with respect to he container but inner frames are not scaled with respect to the main frame.
972     if (!page || page->mainFrame() != this)
973         return 1;
974     return page->pageScaleFactor();
975 }
976
977 void Frame::suspendActiveDOMObjectsAndAnimations()
978 {
979     bool wasSuspended = activeDOMObjectsAndAnimationsSuspended();
980
981     m_activeDOMObjectsAndAnimationsSuspendedCount++;
982
983     if (wasSuspended)
984         return;
985
986     if (document()) {
987         document()->suspendScriptedAnimationControllerCallbacks();
988         animation()->suspendAnimationsForDocument(document());
989         document()->suspendActiveDOMObjects(ActiveDOMObject::PageWillBeSuspended);
990     }
991 }
992
993 void Frame::resumeActiveDOMObjectsAndAnimations()
994 {
995     ASSERT(activeDOMObjectsAndAnimationsSuspended());
996
997     m_activeDOMObjectsAndAnimationsSuspendedCount--;
998
999     if (activeDOMObjectsAndAnimationsSuspended())
1000         return;
1001
1002     if (document()) {
1003         document()->resumeActiveDOMObjects();
1004         animation()->resumeAnimationsForDocument(document());
1005         document()->resumeScriptedAnimationControllerCallbacks();
1006     }
1007 }
1008
1009 #if USE(ACCELERATED_COMPOSITING)
1010 void Frame::deviceOrPageScaleFactorChanged()
1011 {
1012     for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
1013         child->deviceOrPageScaleFactorChanged();
1014
1015     RenderView* root = contentRenderer();
1016     if (root && root->compositor())
1017         root->compositor()->deviceOrPageScaleFactorChanged();
1018 }
1019 #endif
1020 void Frame::notifyChromeClientWheelEventHandlerCountChanged() const
1021 {
1022     // Ensure that this method is being called on the main frame of the page.
1023     ASSERT(m_page && m_page->mainFrame() == this);
1024
1025     unsigned count = 0;
1026     for (const Frame* frame = this; frame; frame = frame->tree()->traverseNext()) {
1027         if (frame->document())
1028             count += frame->document()->wheelEventHandlerCount();
1029     }
1030
1031     m_page->chrome()->client()->numWheelEventHandlersChanged(count);
1032 }
1033
1034 void Frame::notifyChromeClientTouchEventHandlerCountChanged() const
1035 {
1036     // Ensure that this method is being called on the main frame of the page.
1037     ASSERT(m_page && m_page->mainFrame() == this);
1038
1039     unsigned count = 0;
1040     for (const Frame* frame = this; frame; frame = frame->tree()->traverseNext()) {
1041         if (frame->document())
1042             count += frame->document()->touchEventHandlerCount();
1043     }
1044
1045     m_page->chrome()->client()->numTouchEventHandlersChanged(count);
1046 }
1047
1048 #if !PLATFORM(MAC) && !PLATFORM(WIN)
1049 struct ScopedFramePaintingState {
1050     ScopedFramePaintingState(Frame* theFrame, RenderObject* theRenderer)
1051         : frame(theFrame)
1052         , renderer(theRenderer)
1053         , paintBehavior(frame->view()->paintBehavior())
1054         , backgroundColor(frame->view()->baseBackgroundColor())
1055     {
1056     }
1057
1058     ~ScopedFramePaintingState()
1059     {
1060         if (renderer)
1061             renderer->updateDragState(false);
1062         frame->view()->setPaintBehavior(paintBehavior);
1063         frame->view()->setBaseBackgroundColor(backgroundColor);
1064         frame->view()->setNodeToDraw(0);
1065     }
1066
1067     Frame* frame;
1068     RenderObject* renderer;
1069     PaintBehavior paintBehavior;
1070     Color backgroundColor;
1071 };
1072
1073 DragImageRef Frame::nodeImage(Node* node)
1074 {
1075     RenderObject* renderer = node->renderer();
1076     if (!renderer)
1077         return 0;
1078
1079     const ScopedFramePaintingState state(this, renderer);
1080
1081     renderer->updateDragState(true);
1082     m_view->setPaintBehavior(state.paintBehavior | PaintBehaviorFlattenCompositingLayers);
1083
1084     // When generating the drag image for an element, ignore the document background.
1085     m_view->setBaseBackgroundColor(colorWithOverrideAlpha(Color::white, 1.0));
1086     m_doc->updateLayout();
1087     m_view->setNodeToDraw(node); // Enable special sub-tree drawing mode.
1088
1089     LayoutRect topLevelRect;
1090     IntRect paintingRect = pixelSnappedIntRect(renderer->paintingRootRect(topLevelRect));
1091
1092     OwnPtr<ImageBuffer> buffer(ImageBuffer::create(paintingRect.size(), 1, ColorSpaceDeviceRGB));
1093     if (!buffer)
1094         return 0;
1095     buffer->context()->translate(-paintingRect.x(), -paintingRect.y());
1096     buffer->context()->clip(FloatRect(0, 0, paintingRect.maxX(), paintingRect.maxY()));
1097
1098     m_view->paintContents(buffer->context(), paintingRect);
1099
1100     RefPtr<Image> image = buffer->copyImage();
1101     return createDragImageFromImage(image.get(), renderer->shouldRespectImageOrientation());
1102 }
1103
1104 DragImageRef Frame::dragImageForSelection()
1105 {
1106     if (!selection()->isRange())
1107         return 0;
1108
1109     const ScopedFramePaintingState state(this, 0);
1110     m_view->setPaintBehavior(PaintBehaviorSelectionOnly);
1111     m_doc->updateLayout();
1112
1113     IntRect paintingRect = enclosingIntRect(selection()->bounds());
1114
1115     OwnPtr<ImageBuffer> buffer(ImageBuffer::create(paintingRect.size(), 1, ColorSpaceDeviceRGB));
1116     if (!buffer)
1117         return 0;
1118     buffer->context()->translate(-paintingRect.x(), -paintingRect.y());
1119     buffer->context()->clip(FloatRect(0, 0, paintingRect.maxX(), paintingRect.maxY()));
1120
1121     m_view->paintContents(buffer->context(), paintingRect);
1122
1123     RefPtr<Image> image = buffer->copyImage();
1124     return createDragImageFromImage(image.get());
1125 }
1126
1127 #endif
1128
1129 } // namespace WebCore