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