• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
116 using namespace std;
117 
118 namespace WebCore {
119 
120 using namespace HTMLNames;
121 
122 #ifndef NDEBUG
123 static WTF::RefCountedLeakCounter frameCounter("Frame");
124 #endif
125 
parentFromOwnerElement(HTMLFrameOwnerElement * ownerElement)126 static inline Frame* parentFromOwnerElement(HTMLFrameOwnerElement* ownerElement)
127 {
128     if (!ownerElement)
129         return 0;
130     return ownerElement->document()->frame();
131 }
132 
parentPageZoomFactor(Frame * frame)133 static inline float parentPageZoomFactor(Frame* frame)
134 {
135     Frame* parent = frame->tree()->parent();
136     if (!parent)
137         return 1;
138     return parent->pageZoomFactor();
139 }
140 
parentTextZoomFactor(Frame * frame)141 static inline float parentTextZoomFactor(Frame* frame)
142 {
143     Frame* parent = frame->tree()->parent();
144     if (!parent)
145         return 1;
146     return parent->textZoomFactor();
147 }
148 
Frame(Page * page,HTMLFrameOwnerElement * ownerElement,FrameLoaderClient * frameLoaderClient)149 inline 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 
create(Page * page,HTMLFrameOwnerElement * ownerElement,FrameLoaderClient * client)209 PassRefPtr<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 
~Frame()217 Frame::~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 
addDestructionObserver(FrameDestructionObserver * observer)252 void Frame::addDestructionObserver(FrameDestructionObserver* observer)
253 {
254     m_destructionObservers.add(observer);
255 }
256 
removeDestructionObserver(FrameDestructionObserver * observer)257 void Frame::removeDestructionObserver(FrameDestructionObserver* observer)
258 {
259     m_destructionObservers.remove(observer);
260 }
261 
setView(PassRefPtr<FrameView> view)262 void 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 
setDocument(PassRefPtr<Document> newDoc)296 void 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)
sendOrientationChangeEvent(int orientation)322 void 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 
settings() const330 Settings* Frame::settings() const
331 {
332     return m_page ? m_page->settings() : 0;
333 }
334 
createRegExpForLabels(const Vector<String> & labels)335 static 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 
searchForLabelsAboveCell(RegularExpression * regExp,HTMLTableCellElement * cell,size_t * resultDistanceFromStartOfCell)369 String 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 
searchForLabelsBeforeElement(const Vector<String> & labels,Element * element,size_t * resultDistance,bool * resultIsInCellAbove)396 String 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 
matchLabelsAgainstString(const Vector<String> & labels,const String & stringToMatch)464 static 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 
matchLabelsAgainstElement(const Vector<String> & labels,Element * element)499 String 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 
setPrinting(bool printing,const FloatSize & pageSize,float maximumShrinkRatio,AdjustViewSizeOrNot shouldAdjustViewSize)512 void 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 
injectUserScripts(UserScriptInjectionTime injectionTime)525 void 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 
injectUserScriptsForWorld(DOMWrapperWorld * world,const UserScriptVector & userScripts,UserScriptInjectionTime injectionTime)542 void 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
keepAliveSet()564 static HashSet<Frame*>& keepAliveSet()
565 {
566     DEFINE_STATIC_LOCAL(HashSet<Frame*>, staticKeepAliveSet, ());
567     return staticKeepAliveSet;
568 }
569 #endif
570 
keepAlive()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
cancelAllKeepAlive()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 
lifeSupportTimerFired(Timer<Frame> *)595 void Frame::lifeSupportTimerFired(Timer<Frame>*)
596 {
597 #ifndef NDEBUG
598     keepAliveSet().remove(this);
599 #endif
600     deref();
601 }
602 
clearDOMWindow()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 
contentRenderer() const612 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 
ownerRenderer() const624 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 
frameForWidget(const Widget * widget)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 
clearTimers(FrameView * view,Document * document)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 
clearTimers()666 void Frame::clearTimers()
667 {
668     clearTimers(m_view.get(), document());
669 }
670 
setDOMWindow(DOMWindow * domWindow)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 
domWindow() const680 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 
clearFormerDOMWindow(DOMWindow * window)688 void Frame::clearFormerDOMWindow(DOMWindow* window)
689 {
690     m_liveFormerWindows.remove(window);
691 }
692 
pageDestroyed()693 void 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 
disconnectOwnerElement()715 void 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.
transferChildFrameToNewDocument()728 void 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 
documentTypeString() const780 String Frame::documentTypeString() const
781 {
782     if (DocumentType* doctype = document()->doctype())
783         return createMarkup(doctype);
784 
785     return String();
786 }
787 
visiblePositionForPoint(const IntPoint & framePoint)788 VisiblePosition 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 
documentAtPoint(const IntPoint & point)803 Document* 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 
rangeForPoint(const IntPoint & framePoint)816 PassRefPtr<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 
createView(const IntSize & viewportSize,const Color & backgroundColor,bool transparent,const IntSize & fixedLayoutSize,bool useFixedLayout,ScrollbarMode horizontalScrollbarMode,bool horizontalLock,ScrollbarMode verticalScrollbarMode,bool verticalLock)841 void 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)
setTiledBackingStoreEnabled(bool enabled)883 void 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 
tiledBackingStorePaintBegin()896 void Frame::tiledBackingStorePaintBegin()
897 {
898     if (!m_view)
899         return;
900     m_view->updateLayoutAndStyleIfNeededRecursive();
901     m_view->flushDeferredRepaints();
902 }
903 
tiledBackingStorePaint(GraphicsContext * context,const IntRect & rect)904 void Frame::tiledBackingStorePaint(GraphicsContext* context, const IntRect& rect)
905 {
906     if (!m_view)
907         return;
908     m_view->paintContents(context, rect);
909 }
910 
tiledBackingStorePaintEnd(const Vector<IntRect> & paintedArea)911 void 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 
tiledBackingStoreContentsRect()921 IntRect Frame::tiledBackingStoreContentsRect()
922 {
923     if (!m_view)
924         return IntRect();
925     return IntRect(IntPoint(), m_view->contentsSize());
926 }
927 
tiledBackingStoreVisibleRect()928 IntRect Frame::tiledBackingStoreVisibleRect()
929 {
930     if (!m_page)
931         return IntRect();
932     return m_page->chrome()->client()->visibleRectForTiledBackingStore();
933 }
934 
tiledBackingStoreBackgroundColor() const935 Color Frame::tiledBackingStoreBackgroundColor() const
936 {
937     if (!m_view)
938         return Color();
939     return m_view->baseBackgroundColor();
940 }
941 #endif
942 
layerTreeAsText(bool showDebugInfo) const943 String 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 
setPageZoomFactor(float factor)957 void Frame::setPageZoomFactor(float factor)
958 {
959     setPageAndTextZoomFactors(factor, m_textZoomFactor);
960 }
961 
setTextZoomFactor(float factor)962 void Frame::setTextZoomFactor(float factor)
963 {
964     setPageAndTextZoomFactors(m_pageZoomFactor, factor);
965 }
966 
setPageAndTextZoomFactors(float pageZoomFactor,float textZoomFactor)967 void 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)
updateContentsScale(float scale)1017 void 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 
scalePage(float scale,const IntPoint & origin)1028 void 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