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