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 * Copyright (C) 2008 Google Inc.
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Library General Public
16 * License as published by the Free Software Foundation; either
17 * version 2 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Library General Public License for more details.
24 * You should have received a copy of the GNU Library General Public License
25 * along with this library; see the file COPYING.LIB. If not, write to
26 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
27 * Boston, MA 02110-1301, USA.
33 #include "AnimationController.h"
34 #include "ApplyStyleCommand.h"
35 #include "BackForwardController.h"
36 #include "CSSComputedStyleDeclaration.h"
37 #include "CSSPropertyNames.h"
38 #include "CachedCSSStyleSheet.h"
39 #include "CachedResourceLoader.h"
41 #include "ChromeClient.h"
42 #include "DOMWindow.h"
43 #include "DocumentType.h"
45 #include "EditorClient.h"
47 #include "EventHandler.h"
48 #include "EventNames.h"
49 #include "FloatQuad.h"
50 #include "FocusController.h"
51 #include "FrameDestructionObserver.h"
52 #include "FrameLoader.h"
53 #include "FrameLoaderClient.h"
54 #include "FrameSelection.h"
55 #include "FrameView.h"
56 #include "GraphicsContext.h"
57 #include "GraphicsLayer.h"
58 #include "HTMLDocument.h"
59 #include "HTMLFormControlElement.h"
60 #include "HTMLFormElement.h"
61 #include "HTMLFrameElementBase.h"
62 #include "HTMLNames.h"
63 #include "HTMLTableCellElement.h"
64 #include "HitTestResult.h"
65 #include "ImageBuffer.h"
66 #include "InspectorInstrumentation.h"
67 #include "JSDOMWindowShell.h"
69 #include "MathMLNames.h"
70 #include "MediaFeatureNames.h"
71 #include "Navigator.h"
73 #include "NodeTraversal.h"
75 #include "PageCache.h"
76 #include "PageGroup.h"
77 #include "RegularExpression.h"
78 #include "RenderPart.h"
79 #include "RenderTableCell.h"
80 #include "RenderTextControl.h"
81 #include "RenderTheme.h"
82 #include "RenderView.h"
83 #include "RuntimeEnabledFeatures.h"
85 #include "ScriptController.h"
86 #include "ScriptSourceCode.h"
87 #include "ScriptValue.h"
88 #include "ScrollingCoordinator.h"
90 #include "StylePropertySet.h"
91 #include "TextIterator.h"
92 #include "TextNodeTraversal.h"
93 #include "TextResourceDecoder.h"
94 #include "UserContentURLPattern.h"
95 #include "UserTypingGestureIndicator.h"
96 #include "VisibleUnits.h"
97 #include "WebKitFontFamilyNames.h"
98 #include "XLinkNames.h"
99 #include "XMLNSNames.h"
100 #include "XMLNames.h"
101 #include "htmlediting.h"
103 #include "npruntime_impl.h"
104 #include "runtime_root.h"
105 #include <wtf/PassOwnPtr.h>
106 #include <wtf/RefCountedLeakCounter.h>
107 #include <wtf/StdLibExtras.h>
109 #if USE(ACCELERATED_COMPOSITING)
110 #include "RenderLayerCompositor.h"
114 #include "SVGDocument.h"
115 #include "SVGDocumentExtensions.h"
118 #if USE(TILED_BACKING_STORE)
119 #include "TiledBackingStore.h"
126 using namespace HTMLNames;
128 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, frameCounter, ("Frame"));
130 static inline Frame* parentFromOwnerElement(HTMLFrameOwnerElement* ownerElement)
134 return ownerElement->document().frame();
137 static inline float parentPageZoomFactor(Frame* frame)
139 Frame* parent = frame->tree().parent();
142 return parent->pageZoomFactor();
145 static inline float parentTextZoomFactor(Frame* frame)
147 Frame* parent = frame->tree().parent();
150 return parent->textZoomFactor();
153 inline Frame::Frame(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* frameLoaderClient)
155 , m_settings(&page->settings())
156 , m_treeNode(this, parentFromOwnerElement(ownerElement))
157 , m_loader(*this, *frameLoaderClient)
158 , m_navigationScheduler(this)
159 , m_ownerElement(ownerElement)
160 , m_script(createOwned<ScriptController>(*this))
161 , m_editor(Editor::create(*this))
162 , m_selection(adoptPtr(new FrameSelection(this)))
163 , m_eventHandler(adoptPtr(new EventHandler(*this)))
164 , m_animationController(createOwned<AnimationController>(*this))
165 , m_pageZoomFactor(parentPageZoomFactor(this))
166 , m_textZoomFactor(parentTextZoomFactor(this))
167 #if ENABLE(ORIENTATION_EVENTS)
170 , m_inViewSourceMode(false)
171 , m_activeDOMObjectsAndAnimationsSuspendedCount(0)
174 AtomicString::init();
176 QualifiedName::init();
177 MediaFeatureNames::init();
183 WebKitFontFamilyNames::init();
186 #if USE(TILED_BACKING_STORE)
187 // Top level frame only for now.
188 setTiledBackingStoreEnabled(settings().tiledBackingStoreEnabled());
191 page->incrementSubframeCount();
192 ownerElement->setContentFrame(this);
196 frameCounter.increment();
199 // Pause future ActiveDOMObjects if this frame is being created while the page is in a paused state.
200 Frame* parent = parentFromOwnerElement(ownerElement);
201 if (parent && parent->activeDOMObjectsAndAnimationsSuspended())
202 suspendActiveDOMObjectsAndAnimations();
205 PassRefPtr<Frame> Frame::create(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* client)
207 return adoptRef(new Frame(page, ownerElement, client));
213 loader().cancelAndClear();
215 // FIXME: We should not be doing all this work inside the destructor
218 frameCounter.decrement();
221 disconnectOwnerElement();
223 HashSet<FrameDestructionObserver*>::iterator stop = m_destructionObservers.end();
224 for (HashSet<FrameDestructionObserver*>::iterator it = m_destructionObservers.begin(); it != stop; ++it)
225 (*it)->frameDestroyed();
228 void Frame::addDestructionObserver(FrameDestructionObserver* observer)
230 m_destructionObservers.add(observer);
233 void Frame::removeDestructionObserver(FrameDestructionObserver* observer)
235 m_destructionObservers.remove(observer);
238 void Frame::setView(PassRefPtr<FrameView> view)
240 // We the custom scroll bars as early as possible to prevent m_doc->detach()
241 // from messing with the view such that its scroll bars won't be torn down.
242 // FIXME: We should revisit this.
244 m_view->prepareForDetach();
246 // Prepare for destruction now, so any unload event handlers get run and the DOMWindow is
247 // notified. If we wait until the view is destroyed, then things won't be hooked up enough for
248 // these calls to work.
249 if (!view && m_doc && m_doc->attached() && !m_doc->inPageCache()) {
250 // FIXME: We don't call willRemove here. Why is that OK?
251 m_doc->prepareForDestruction();
255 m_view->unscheduleRelayout();
257 eventHandler().clear();
261 // Only one form submission is allowed per view of a part.
262 // Since this part may be getting reused as a result of being
263 // pulled from the back/forward cache, reset this flag.
264 loader().resetMultipleFormSubmissionProtection();
266 #if USE(TILED_BACKING_STORE)
267 if (m_view && tiledBackingStore())
268 m_view->setPaintsEntireContents(true);
272 void Frame::setDocument(PassRefPtr<Document> newDocument)
274 ASSERT(!newDocument || newDocument->frame() == this);
276 if (m_doc && m_doc->attached() && !m_doc->inPageCache()) {
277 // FIXME: We don't call willRemove here. Why is that OK?
281 m_doc = newDocument.get();
282 ASSERT(!m_doc || m_doc->domWindow());
283 ASSERT(!m_doc || m_doc->domWindow()->frame() == this);
285 // Don't use m_doc because it can be overwritten and we want to guarantee
286 // that the document is not destroyed during this function call.
288 newDocument->didBecomeCurrentDocumentInFrame();
291 #if ENABLE(ORIENTATION_EVENTS)
292 void Frame::sendOrientationChangeEvent(int orientation)
294 m_orientation = orientation;
295 if (Document* doc = document())
296 doc->dispatchWindowEvent(Event::create(eventNames().orientationchangeEvent, false, false));
298 #endif // ENABLE(ORIENTATION_EVENTS)
300 static PassOwnPtr<RegularExpression> createRegExpForLabels(const Vector<String>& labels)
302 // REVIEW- version of this call in FrameMac.mm caches based on the NSArray ptrs being
303 // the same across calls. We can't do that.
305 DEFINE_STATIC_LOCAL(RegularExpression, wordRegExp, ("\\w", TextCaseSensitive));
307 unsigned int numLabels = labels.size();
309 for (i = 0; i < numLabels; i++) {
310 String label = labels[i];
312 bool startsWithWordChar = false;
313 bool endsWithWordChar = false;
314 if (label.length()) {
315 startsWithWordChar = wordRegExp.match(label.substring(0, 1)) >= 0;
316 endsWithWordChar = wordRegExp.match(label.substring(label.length() - 1, 1)) >= 0;
321 // Search for word boundaries only if label starts/ends with "word characters".
322 // If we always searched for word boundaries, this wouldn't work for languages
324 if (startsWithWordChar)
325 pattern.append("\\b");
326 pattern.append(label);
327 if (endsWithWordChar)
328 pattern.append("\\b");
331 return adoptPtr(new RegularExpression(pattern, TextCaseInsensitive));
334 String Frame::searchForLabelsAboveCell(RegularExpression* regExp, HTMLTableCellElement* cell, size_t* resultDistanceFromStartOfCell)
336 HTMLTableCellElement* aboveCell = cell->cellAbove();
338 // search within the above cell we found for a match
339 size_t lengthSearched = 0;
340 for (Text* textNode = TextNodeTraversal::firstWithin(aboveCell); textNode; textNode = TextNodeTraversal::next(textNode, aboveCell)) {
341 if (!textNode->renderer() || textNode->renderer()->style()->visibility() != VISIBLE)
343 // For each text chunk, run the regexp
344 String nodeString = textNode->data();
345 int pos = regExp->searchRev(nodeString);
347 if (resultDistanceFromStartOfCell)
348 *resultDistanceFromStartOfCell = lengthSearched;
349 return nodeString.substring(pos, regExp->matchedLength());
351 lengthSearched += nodeString.length();
355 // Any reason in practice to search all cells in that are above cell?
356 if (resultDistanceFromStartOfCell)
357 *resultDistanceFromStartOfCell = notFound;
361 String Frame::searchForLabelsBeforeElement(const Vector<String>& labels, Element* element, size_t* resultDistance, bool* resultIsInCellAbove)
363 OwnPtr<RegularExpression> regExp(createRegExpForLabels(labels));
364 // We stop searching after we've seen this many chars
365 const unsigned int charsSearchedThreshold = 500;
366 // This is the absolute max we search. We allow a little more slop than
367 // charsSearchedThreshold, to make it more likely that we'll search whole nodes.
368 const unsigned int maxCharsSearched = 600;
369 // If the starting element is within a table, the cell that contains it
370 HTMLTableCellElement* startingTableCell = 0;
371 bool searchedCellAbove = false;
374 *resultDistance = notFound;
375 if (resultIsInCellAbove)
376 *resultIsInCellAbove = false;
378 // walk backwards in the node tree, until another element, or form, or end of tree
379 int unsigned lengthSearched = 0;
381 for (n = NodeTraversal::previous(element); n && lengthSearched < charsSearchedThreshold; n = NodeTraversal::previous(n)) {
382 // We hit another form element or the start of the form - bail out
383 if (isHTMLFormElement(n) || (n->isHTMLElement() && toElement(n)->isFormControlElement()))
386 if (n->hasTagName(tdTag) && !startingTableCell) {
387 startingTableCell = static_cast<HTMLTableCellElement*>(n);
388 } else if (n->hasTagName(trTag) && startingTableCell) {
389 String result = searchForLabelsAboveCell(regExp.get(), startingTableCell, resultDistance);
390 if (!result.isEmpty()) {
391 if (resultIsInCellAbove)
392 *resultIsInCellAbove = true;
395 searchedCellAbove = true;
396 } else if (n->isTextNode() && n->renderer() && n->renderer()->style()->visibility() == VISIBLE) {
397 // For each text chunk, run the regexp
398 String nodeString = n->nodeValue();
399 // add 100 for slop, to make it more likely that we'll search whole nodes
400 if (lengthSearched + nodeString.length() > maxCharsSearched)
401 nodeString = nodeString.right(charsSearchedThreshold - lengthSearched);
402 int pos = regExp->searchRev(nodeString);
405 *resultDistance = lengthSearched;
406 return nodeString.substring(pos, regExp->matchedLength());
408 lengthSearched += nodeString.length();
412 // If we started in a cell, but bailed because we found the start of the form or the
413 // previous element, we still might need to search the row above us for a label.
414 if (startingTableCell && !searchedCellAbove) {
415 String result = searchForLabelsAboveCell(regExp.get(), startingTableCell, resultDistance);
416 if (!result.isEmpty()) {
417 if (resultIsInCellAbove)
418 *resultIsInCellAbove = true;
425 static String matchLabelsAgainstString(const Vector<String>& labels, const String& stringToMatch)
427 if (stringToMatch.isEmpty())
430 String mutableStringToMatch = stringToMatch;
432 // Make numbers and _'s in field names behave like word boundaries, e.g., "address2"
433 replace(mutableStringToMatch, RegularExpression("\\d", TextCaseSensitive), " ");
434 mutableStringToMatch.replace('_', ' ');
436 OwnPtr<RegularExpression> regExp(createRegExpForLabels(labels));
437 // Use the largest match we can find in the whole string
444 pos = regExp->match(mutableStringToMatch, start);
446 length = regExp->matchedLength();
447 if (length >= bestLength) {
456 return mutableStringToMatch.substring(bestPos, bestLength);
460 String Frame::matchLabelsAgainstElement(const Vector<String>& labels, Element* element)
462 // Match against the name element, then against the id element if no match is found for the name element.
463 // See 7538330 for one popular site that benefits from the id element check.
464 // FIXME: This code is mirrored in FrameMac.mm. It would be nice to make the Mac code call the platform-agnostic
465 // code, which would require converting the NSArray of NSStrings to a Vector of Strings somewhere along the way.
466 String resultFromNameAttribute = matchLabelsAgainstString(labels, element->getNameAttribute());
467 if (!resultFromNameAttribute.isEmpty())
468 return resultFromNameAttribute;
470 return matchLabelsAgainstString(labels, element->getAttribute(idAttr));
473 void Frame::setPrinting(bool printing, const FloatSize& pageSize, const FloatSize& originalPageSize, float maximumShrinkRatio, AdjustViewSizeOrNot shouldAdjustViewSize)
475 // In setting printing, we should not validate resources already cached for the document.
476 // See https://bugs.webkit.org/show_bug.cgi?id=43704
477 ResourceCacheValidationSuppressor validationSuppressor(m_doc->cachedResourceLoader());
479 m_doc->setPrinting(printing);
480 view()->adjustMediaTypeForPrinting(printing);
482 m_doc->styleResolverChanged(RecalcStyleImmediately);
483 if (shouldUsePrintingLayout()) {
484 view()->forceLayoutForPagination(pageSize, originalPageSize, maximumShrinkRatio, shouldAdjustViewSize);
486 view()->forceLayout();
487 if (shouldAdjustViewSize == AdjustViewSize)
488 view()->adjustViewSize();
491 // Subframes of the one we're printing don't lay out to the page size.
492 for (RefPtr<Frame> child = tree().firstChild(); child; child = child->tree().nextSibling())
493 child->setPrinting(printing, FloatSize(), FloatSize(), 0, shouldAdjustViewSize);
496 bool Frame::shouldUsePrintingLayout() const
498 // Only top frame being printed should be fit to page size.
499 // Subframes should be constrained by parents only.
500 return m_doc->printing() && (!tree().parent() || !tree().parent()->m_doc->printing());
503 FloatSize Frame::resizePageRectsKeepingRatio(const FloatSize& originalSize, const FloatSize& expectedSize)
505 FloatSize resultSize;
506 if (!contentRenderer())
509 if (contentRenderer()->style()->isHorizontalWritingMode()) {
510 ASSERT(fabs(originalSize.width()) > numeric_limits<float>::epsilon());
511 float ratio = originalSize.height() / originalSize.width();
512 resultSize.setWidth(floorf(expectedSize.width()));
513 resultSize.setHeight(floorf(resultSize.width() * ratio));
515 ASSERT(fabs(originalSize.height()) > numeric_limits<float>::epsilon());
516 float ratio = originalSize.width() / originalSize.height();
517 resultSize.setHeight(floorf(expectedSize.height()));
518 resultSize.setWidth(floorf(resultSize.height() * ratio));
523 void Frame::injectUserScripts(UserScriptInjectionTime injectionTime)
528 if (loader().stateMachine()->creatingInitialEmptyDocument() && !settings().shouldInjectUserScriptsInInitialEmptyDocument())
531 // Walk the hashtable. Inject by world.
532 const UserScriptMap* userScripts = m_page->group().userScripts();
535 UserScriptMap::const_iterator end = userScripts->end();
536 for (UserScriptMap::const_iterator it = userScripts->begin(); it != end; ++it)
537 injectUserScriptsForWorld(it->key.get(), *it->value, injectionTime);
540 void Frame::injectUserScriptsForWorld(DOMWrapperWorld* world, const UserScriptVector& userScripts, UserScriptInjectionTime injectionTime)
542 if (userScripts.isEmpty())
545 Document* doc = document();
549 Vector<ScriptSourceCode> sourceCode;
550 unsigned count = userScripts.size();
551 for (unsigned i = 0; i < count; ++i) {
552 UserScript* script = userScripts[i].get();
553 if (script->injectedFrames() == InjectInTopFrameOnly && ownerElement())
556 if (script->injectionTime() == injectionTime && UserContentURLPattern::matchesPatterns(doc->url(), script->whitelist(), script->blacklist()))
557 m_script->evaluateInWorld(ScriptSourceCode(script->source(), script->url()), world);
561 RenderView* Frame::contentRenderer() const
563 return document() ? document()->renderView() : 0;
566 RenderPart* Frame::ownerRenderer() const
568 HTMLFrameOwnerElement* ownerElement = m_ownerElement;
571 RenderObject* object = ownerElement->renderer();
574 // FIXME: If <object> is ever fixed to disassociate itself from frames
575 // that it has started but canceled, then this can turn into an ASSERT
576 // since m_ownerElement would be 0 when the load is canceled.
577 // https://bugs.webkit.org/show_bug.cgi?id=18585
578 if (!object->isRenderPart())
580 return toRenderPart(object);
583 Frame* Frame::frameForWidget(const Widget* widget)
585 ASSERT_ARG(widget, widget);
587 if (RenderWidget* renderer = RenderWidget::find(widget))
588 if (Element* element = renderer->element())
589 return element->document().frame();
591 // Assume all widgets are either a FrameView or owned by a RenderWidget.
592 // FIXME: That assumption is not right for scroll bars!
593 ASSERT_WITH_SECURITY_IMPLICATION(widget->isFrameView());
594 return &toFrameView(widget)->frame();
597 void Frame::clearTimers(FrameView *view, Document *document)
600 view->unscheduleRelayout();
601 view->frame().animation().suspendAnimationsForDocument(document);
602 view->frame().eventHandler().stopAutoscrollTimer();
606 void Frame::clearTimers()
608 clearTimers(m_view.get(), document());
611 void Frame::willDetachPage()
613 if (Frame* parent = tree().parent())
614 parent->loader().checkLoadComplete();
616 HashSet<FrameDestructionObserver*>::iterator stop = m_destructionObservers.end();
617 for (HashSet<FrameDestructionObserver*>::iterator it = m_destructionObservers.begin(); it != stop; ++it)
618 (*it)->willDetachPage();
620 // FIXME: It's unclear as to why this is called more than once, but it is,
621 // so page() could be NULL.
622 if (page() && page()->focusController().focusedFrame() == this)
623 page()->focusController().setFocusedFrame(0);
625 if (page() && page()->scrollingCoordinator() && m_view)
626 page()->scrollingCoordinator()->willDestroyScrollableArea(m_view.get());
628 script().clearScriptObjects();
629 script().updatePlatformScriptObjects();
632 void Frame::disconnectOwnerElement()
634 if (m_ownerElement) {
635 // We use the ownerElement's document to retrieve the cache, because the contentDocument for this
636 // frame is already detached (and can't access the top level AX cache).
637 // However, we pass in the current document to clearTextMarkerNodesInUse so we can identify the
638 // nodes inside this document that need to be removed from the cache.
640 // We don't clear the AXObjectCache here because we don't want to clear the top level cache
641 // when a sub-frame is removed.
642 #if HAVE(ACCESSIBILITY)
643 if (AXObjectCache* cache = m_ownerElement->document().existingAXObjectCache())
644 cache->clearTextMarkerNodesInUse(document());
647 m_ownerElement->clearContentFrame();
649 m_page->decrementSubframeCount();
654 String Frame::displayStringModifiedByEncoding(const String& str) const
656 return document() ? document()->displayStringModifiedByEncoding(str) : str;
659 VisiblePosition Frame::visiblePositionForPoint(const IntPoint& framePoint)
661 HitTestResult result = eventHandler().hitTestResultAtPoint(framePoint, HitTestRequest::ReadOnly | HitTestRequest::Active);
662 Node* node = result.innerNonSharedNode();
664 return VisiblePosition();
665 RenderObject* renderer = node->renderer();
667 return VisiblePosition();
668 VisiblePosition visiblePos = renderer->positionForPoint(result.localPoint());
669 if (visiblePos.isNull())
670 visiblePos = firstPositionInOrBeforeNode(node);
674 Document* Frame::documentAtPoint(const IntPoint& point)
679 IntPoint pt = view()->windowToContents(point);
680 HitTestResult result = HitTestResult(pt);
682 if (contentRenderer())
683 result = eventHandler().hitTestResultAtPoint(pt);
684 return result.innerNode() ? &result.innerNode()->document() : 0;
687 PassRefPtr<Range> Frame::rangeForPoint(const IntPoint& framePoint)
689 VisiblePosition position = visiblePositionForPoint(framePoint);
690 if (position.isNull())
693 VisiblePosition previous = position.previous();
694 if (previous.isNotNull()) {
695 RefPtr<Range> previousCharacterRange = makeRange(previous, position);
696 LayoutRect rect = editor().firstRectForRange(previousCharacterRange.get());
697 if (rect.contains(framePoint))
698 return previousCharacterRange.release();
701 VisiblePosition next = position.next();
702 if (RefPtr<Range> nextCharacterRange = makeRange(position, next)) {
703 LayoutRect rect = editor().firstRectForRange(nextCharacterRange.get());
704 if (rect.contains(framePoint))
705 return nextCharacterRange.release();
711 void Frame::createView(const IntSize& viewportSize, const Color& backgroundColor, bool transparent,
712 const IntSize& fixedLayoutSize, const IntRect& fixedVisibleContentRect ,
713 bool useFixedLayout, ScrollbarMode horizontalScrollbarMode, bool horizontalLock,
714 ScrollbarMode verticalScrollbarMode, bool verticalLock)
719 bool isMainFrame = m_page->frameIsMainFrame(this);
721 if (isMainFrame && view())
722 view()->setParentVisible(false);
726 RefPtr<FrameView> frameView;
728 frameView = FrameView::create(*this, viewportSize);
729 frameView->setFixedLayoutSize(fixedLayoutSize);
730 frameView->setFixedVisibleContentRect(fixedVisibleContentRect);
731 frameView->setUseFixedLayout(useFixedLayout);
733 frameView = FrameView::create(*this);
735 frameView->setScrollbarModes(horizontalScrollbarMode, verticalScrollbarMode, horizontalLock, verticalLock);
739 if (backgroundColor.isValid())
740 frameView->updateBackgroundRecursively(backgroundColor, transparent);
743 frameView->setParentVisible(true);
746 ownerRenderer()->setWidget(frameView);
748 if (HTMLFrameOwnerElement* owner = ownerElement())
749 view()->setCanHaveScrollbars(owner->scrollingMode() != ScrollbarAlwaysOff);
752 #if USE(TILED_BACKING_STORE)
753 void Frame::setTiledBackingStoreEnabled(bool enabled)
756 m_tiledBackingStore.clear();
759 if (m_tiledBackingStore)
761 m_tiledBackingStore = adoptPtr(new TiledBackingStore(this));
762 m_tiledBackingStore->setCommitTileUpdatesOnIdleEventLoop(true);
764 m_view->setPaintsEntireContents(true);
767 void Frame::tiledBackingStorePaintBegin()
771 m_view->updateLayoutAndStyleIfNeededRecursive();
772 m_view->flushDeferredRepaints();
775 void Frame::tiledBackingStorePaint(GraphicsContext* context, const IntRect& rect)
779 m_view->paintContents(context, rect);
782 void Frame::tiledBackingStorePaintEnd(const Vector<IntRect>& paintedArea)
784 if (!m_page || !m_view)
786 unsigned size = paintedArea.size();
787 // Request repaint from the system
788 for (unsigned n = 0; n < size; ++n)
789 m_page->chrome().invalidateContentsAndRootView(m_view->contentsToRootView(paintedArea[n]), false);
792 IntRect Frame::tiledBackingStoreContentsRect()
796 return IntRect(IntPoint(), m_view->contentsSize());
799 IntRect Frame::tiledBackingStoreVisibleRect()
803 return m_page->chrome().client().visibleRectForTiledBackingStore();
806 Color Frame::tiledBackingStoreBackgroundColor() const
810 return m_view->baseBackgroundColor();
814 String Frame::layerTreeAsText(LayerTreeFlags flags) const
816 #if USE(ACCELERATED_COMPOSITING)
817 document()->updateLayout();
819 if (!contentRenderer())
822 return contentRenderer()->compositor().layerTreeAsText(flags);
829 String Frame::trackedRepaintRectsAsText() const
833 return m_view->trackedRepaintRectsAsText();
836 void Frame::setPageZoomFactor(float factor)
838 setPageAndTextZoomFactors(factor, m_textZoomFactor);
841 void Frame::setTextZoomFactor(float factor)
843 setPageAndTextZoomFactors(m_pageZoomFactor, factor);
846 void Frame::setPageAndTextZoomFactors(float pageZoomFactor, float textZoomFactor)
848 if (m_pageZoomFactor == pageZoomFactor && m_textZoomFactor == textZoomFactor)
851 Page* page = this->page();
855 Document* document = this->document();
859 m_editor->dismissCorrectionPanelAsIgnored();
862 // Respect SVGs zoomAndPan="disabled" property in standalone SVG documents.
863 // FIXME: How to handle compound documents + zoomAndPan="disabled"? Needs SVG WG clarification.
864 if (document->isSVGDocument()) {
865 if (!toSVGDocument(document)->zoomAndPanEnabled())
870 if (m_pageZoomFactor != pageZoomFactor) {
871 if (FrameView* view = this->view()) {
872 // Update the scroll position when doing a full page zoom, so the content stays in relatively the same position.
873 LayoutPoint scrollPosition = view->scrollPosition();
874 float percentDifference = (pageZoomFactor / m_pageZoomFactor);
875 view->setScrollPosition(IntPoint(scrollPosition.x() * percentDifference, scrollPosition.y() * percentDifference));
879 m_pageZoomFactor = pageZoomFactor;
880 m_textZoomFactor = textZoomFactor;
882 document->recalcStyle(Style::Force);
884 for (RefPtr<Frame> child = tree().firstChild(); child; child = child->tree().nextSibling())
885 child->setPageAndTextZoomFactors(m_pageZoomFactor, m_textZoomFactor);
887 if (FrameView* view = this->view()) {
888 if (document->renderView() && document->renderView()->needsLayout() && view->didFirstLayout())
892 if (page->frameIsMainFrame(this))
893 pageCache()->markPagesForFullStyleRecalc(page);
896 float Frame::frameScaleFactor() const
898 Page* page = this->page();
900 // Main frame is scaled with respect to he container but inner frames are not scaled with respect to the main frame.
901 if (!page || &page->mainFrame() != this || settings().applyPageScaleFactorInCompositor())
904 return page->pageScaleFactor();
907 void Frame::suspendActiveDOMObjectsAndAnimations()
909 bool wasSuspended = activeDOMObjectsAndAnimationsSuspended();
911 m_activeDOMObjectsAndAnimationsSuspendedCount++;
916 // FIXME: Suspend/resume calls will not match if the frame is navigated, and gets a new document.
918 document()->suspendScriptedAnimationControllerCallbacks();
919 animation().suspendAnimationsForDocument(document());
920 document()->suspendActiveDOMObjects(ActiveDOMObject::PageWillBeSuspended);
924 void Frame::resumeActiveDOMObjectsAndAnimations()
926 ASSERT(activeDOMObjectsAndAnimationsSuspended());
928 m_activeDOMObjectsAndAnimationsSuspendedCount--;
930 if (activeDOMObjectsAndAnimationsSuspended())
934 document()->resumeActiveDOMObjects(ActiveDOMObject::PageWillBeSuspended);
935 animation().resumeAnimationsForDocument(document());
936 document()->resumeScriptedAnimationControllerCallbacks();
940 m_view->resumeAnimatingImages();
943 #if USE(ACCELERATED_COMPOSITING)
944 void Frame::deviceOrPageScaleFactorChanged()
946 for (RefPtr<Frame> child = tree().firstChild(); child; child = child->tree().nextSibling())
947 child->deviceOrPageScaleFactorChanged();
949 if (RenderView* root = contentRenderer())
950 root->compositor().deviceOrPageScaleFactorChanged();
954 bool Frame::isURLAllowed(const KURL& url) const
956 // We allow one level of self-reference because some sites depend on that,
957 // but we don't allow more than one.
958 if (m_page->subframeCount() >= Page::maxNumberOfFrames)
960 bool foundSelfReference = false;
961 for (const Frame* frame = this; frame; frame = frame->tree().parent()) {
962 if (equalIgnoringFragmentIdentifier(frame->document()->url(), url)) {
963 if (foundSelfReference)
965 foundSelfReference = true;
971 #if !PLATFORM(MAC) && !PLATFORM(WIN)
972 struct ScopedFramePaintingState {
973 ScopedFramePaintingState(Frame* frame, Node* node)
976 , paintBehavior(frame->view()->paintBehavior())
977 , backgroundColor(frame->view()->baseBackgroundColor())
979 ASSERT(!node || node->renderer());
981 node->renderer()->updateDragState(true);
984 ~ScopedFramePaintingState()
986 if (node && node->renderer())
987 node->renderer()->updateDragState(false);
988 frame->view()->setPaintBehavior(paintBehavior);
989 frame->view()->setBaseBackgroundColor(backgroundColor);
990 frame->view()->setNodeToDraw(0);
995 PaintBehavior paintBehavior;
996 Color backgroundColor;
999 DragImageRef Frame::nodeImage(Node* node)
1001 if (!node->renderer())
1004 const ScopedFramePaintingState state(this, node);
1006 m_view->setPaintBehavior(state.paintBehavior | PaintBehaviorFlattenCompositingLayers);
1008 // When generating the drag image for an element, ignore the document background.
1009 m_view->setBaseBackgroundColor(Color::transparent);
1010 m_doc->updateLayout();
1011 m_view->setNodeToDraw(node); // Enable special sub-tree drawing mode.
1013 // Document::updateLayout may have blown away the original RenderObject.
1014 RenderObject* renderer = node->renderer();
1018 LayoutRect topLevelRect;
1019 IntRect paintingRect = pixelSnappedIntRect(renderer->paintingRootRect(topLevelRect));
1021 float deviceScaleFactor = 1;
1023 deviceScaleFactor = m_page->deviceScaleFactor();
1024 paintingRect.setWidth(paintingRect.width() * deviceScaleFactor);
1025 paintingRect.setHeight(paintingRect.height() * deviceScaleFactor);
1027 OwnPtr<ImageBuffer> buffer(ImageBuffer::create(paintingRect.size(), deviceScaleFactor, ColorSpaceDeviceRGB));
1030 buffer->context()->translate(-paintingRect.x(), -paintingRect.y());
1031 buffer->context()->clip(FloatRect(0, 0, paintingRect.maxX(), paintingRect.maxY()));
1033 m_view->paintContents(buffer->context(), paintingRect);
1035 RefPtr<Image> image = buffer->copyImage();
1036 return createDragImageFromImage(image.get(), ImageOrientationDescription(renderer->shouldRespectImageOrientation()));
1039 DragImageRef Frame::dragImageForSelection()
1041 if (!selection().isRange())
1044 const ScopedFramePaintingState state(this, 0);
1045 m_view->setPaintBehavior(PaintBehaviorSelectionOnly);
1046 m_doc->updateLayout();
1048 IntRect paintingRect = enclosingIntRect(selection().bounds());
1050 float deviceScaleFactor = 1;
1052 deviceScaleFactor = m_page->deviceScaleFactor();
1053 paintingRect.setWidth(paintingRect.width() * deviceScaleFactor);
1054 paintingRect.setHeight(paintingRect.height() * deviceScaleFactor);
1056 OwnPtr<ImageBuffer> buffer(ImageBuffer::create(paintingRect.size(), deviceScaleFactor, ColorSpaceDeviceRGB));
1059 buffer->context()->translate(-paintingRect.x(), -paintingRect.y());
1060 buffer->context()->clip(FloatRect(0, 0, paintingRect.maxX(), paintingRect.maxY()));
1062 m_view->paintContents(buffer->context(), paintingRect);
1064 RefPtr<Image> image = buffer->copyImage();
1065 return createDragImageFromImage(image.get(), ImageOrientationDescription());
1070 } // namespace WebCore