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