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