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 "ApplyStyleCommand.h"
34 #include "BackForwardController.h"
35 #include "CSSComputedStyleDeclaration.h"
36 #include "CSSProperty.h"
37 #include "CSSPropertyNames.h"
38 #include "CachedCSSStyleSheet.h"
40 #include "ChromeClient.h"
41 #include "DOMWindow.h"
42 #include "CachedResourceLoader.h"
43 #include "DocumentType.h"
44 #include "EditingText.h"
45 #include "EditorClient.h"
46 #include "EventNames.h"
47 #include "FloatQuad.h"
48 #include "FocusController.h"
49 #include "FrameDestructionObserver.h"
50 #include "FrameLoader.h"
51 #include "FrameLoaderClient.h"
52 #include "FrameView.h"
53 #include "GraphicsContext.h"
54 #include "GraphicsLayer.h"
55 #include "HTMLDocument.h"
56 #include "HTMLFormControlElement.h"
57 #include "HTMLFormElement.h"
58 #include "HTMLFrameElementBase.h"
59 #include "HTMLNames.h"
60 #include "HTMLTableCellElement.h"
61 #include "HitTestResult.h"
62 #include "ImageBuffer.h"
63 #include "InspectorInstrumentation.h"
65 #include "MediaFeatureNames.h"
66 #include "Navigator.h"
69 #include "PageCache.h"
70 #include "PageGroup.h"
71 #include "RegularExpression.h"
72 #include "RenderPart.h"
73 #include "RenderTableCell.h"
74 #include "RenderTextControl.h"
75 #include "RenderTheme.h"
76 #include "RenderView.h"
77 #include "RuntimeEnabledFeatures.h"
79 #include "ScriptController.h"
80 #include "ScriptSourceCode.h"
81 #include "ScriptValue.h"
83 #include "StylePropertySet.h"
84 #include "TextIterator.h"
85 #include "TextResourceDecoder.h"
86 #include "UserContentURLPattern.h"
87 #include "UserTypingGestureIndicator.h"
88 #include "WebKitFontFamilyNames.h"
89 #include "XMLNSNames.h"
91 #include "htmlediting.h"
93 #include "npruntime_impl.h"
94 #include "visible_units.h"
95 #include <wtf/RefCountedLeakCounter.h>
96 #include <wtf/StdLibExtras.h>
98 #if USE(ACCELERATED_COMPOSITING)
99 #include "RenderLayerCompositor.h"
103 #include "JSDOMWindowShell.h"
104 #include "runtime_root.h"
107 #include "MathMLNames.h"
108 #include "SVGNames.h"
109 #include "XLinkNames.h"
112 #include "SVGDocument.h"
113 #include "SVGDocumentExtensions.h"
116 #if USE(TILED_BACKING_STORE)
117 #include "TiledBackingStore.h"
124 using namespace HTMLNames;
126 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, frameCounter, ("Frame"));
128 static inline Frame* parentFromOwnerElement(HTMLFrameOwnerElement* ownerElement)
132 return ownerElement->document()->frame();
135 static inline float parentPageZoomFactor(Frame* frame)
137 Frame* parent = frame->tree()->parent();
140 return parent->pageZoomFactor();
143 static inline float parentTextZoomFactor(Frame* frame)
145 Frame* parent = frame->tree()->parent();
148 return parent->textZoomFactor();
151 inline Frame::Frame(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* frameLoaderClient)
153 , m_treeNode(this, parentFromOwnerElement(ownerElement))
154 , m_loader(this, frameLoaderClient)
155 , m_navigationScheduler(this)
156 , m_ownerElement(ownerElement)
160 , m_eventHandler(this)
161 , m_animationController(this)
162 , m_pageZoomFactor(parentPageZoomFactor(this))
163 , m_textZoomFactor(parentTextZoomFactor(this))
164 #if ENABLE(ORIENTATION_EVENTS)
167 , m_inViewSourceMode(false)
168 , m_activeDOMObjectsAndAnimationsSuspendedCount(0)
171 AtomicString::init();
173 QualifiedName::init();
174 MediaFeatureNames::init();
180 WebKitFontFamilyNames::init();
183 #if USE(TILED_BACKING_STORE)
184 // Top level frame only for now.
185 setTiledBackingStoreEnabled(page->settings()->tiledBackingStoreEnabled());
188 page->incrementFrameCount();
190 // Make sure we will not end up with two frames referencing the same owner element.
191 Frame*& contentFrameSlot = ownerElement->m_contentFrame;
192 ASSERT(!contentFrameSlot || contentFrameSlot->ownerElement() != ownerElement);
193 contentFrameSlot = this;
197 frameCounter.increment();
200 // Pause future ActiveDOMObjects if this frame is being created while the page is in a paused state.
201 Frame* parent = parentFromOwnerElement(ownerElement);
202 if (parent && parent->activeDOMObjectsAndAnimationsSuspended())
203 suspendActiveDOMObjectsAndAnimations();
206 PassRefPtr<Frame> Frame::create(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* client)
208 RefPtr<Frame> frame = adoptRef(new Frame(page, ownerElement, client));
210 page->setMainFrame(frame);
211 return frame.release();
217 loader()->cancelAndClear();
219 // FIXME: We should not be doing all this work inside the destructor
222 frameCounter.decrement();
225 disconnectOwnerElement();
227 HashSet<FrameDestructionObserver*>::iterator stop = m_destructionObservers.end();
228 for (HashSet<FrameDestructionObserver*>::iterator it = m_destructionObservers.begin(); it != stop; ++it)
229 (*it)->frameDestroyed();
233 m_view->clearFrame();
237 bool Frame::inScope(TreeScope* scope) const
240 HTMLFrameOwnerElement* owner = document()->ownerElement();
241 // Scoping test should be done only for child frames.
243 return owner->treeScope() == scope;
246 void Frame::addDestructionObserver(FrameDestructionObserver* observer)
248 m_destructionObservers.add(observer);
251 void Frame::removeDestructionObserver(FrameDestructionObserver* observer)
253 m_destructionObservers.remove(observer);
256 void Frame::setView(PassRefPtr<FrameView> view)
258 // We the custom scroll bars as early as possible to prevent m_doc->detach()
259 // from messing with the view such that its scroll bars won't be torn down.
260 // FIXME: We should revisit this.
262 m_view->detachCustomScrollbars();
264 // Prepare for destruction now, so any unload event handlers get run and the DOMWindow is
265 // notified. If we wait until the view is destroyed, then things won't be hooked up enough for
266 // these calls to work.
267 if (!view && m_doc && m_doc->attached() && !m_doc->inPageCache()) {
268 // FIXME: We don't call willRemove here. Why is that OK?
269 m_doc->prepareForDestruction();
273 m_view->unscheduleRelayout();
275 eventHandler()->clear();
279 // Only one form submission is allowed per view of a part.
280 // Since this part may be getting reused as a result of being
281 // pulled from the back/forward cache, reset this flag.
282 loader()->resetMultipleFormSubmissionProtection();
284 #if USE(TILED_BACKING_STORE)
285 if (m_view && tiledBackingStore())
286 m_view->setPaintsEntireContents(true);
290 void Frame::setDocument(PassRefPtr<Document> newDoc)
292 ASSERT(!newDoc || newDoc->frame());
293 if (m_doc && m_doc->attached() && !m_doc->inPageCache()) {
294 // FIXME: We don't call willRemove here. Why is that OK?
299 selection()->updateSecureKeyboardEntryIfActive();
301 if (m_doc && !m_doc->attached())
304 // Update the cached 'document' property, which is now stale.
305 m_script.updateDocument();
308 m_doc->updateViewportArguments();
310 if (m_page && m_page->mainFrame() == this) {
311 notifyChromeClientWheelEventHandlerCountChanged();
312 #if ENABLE(TOUCH_EVENTS)
313 if (m_doc && m_doc->hasListenerType(Document::TOUCH_LISTENER))
314 m_page->chrome()->client()->needTouchEvents(true);
318 // Suspend document if this frame was created in suspended state.
319 if (m_doc && activeDOMObjectsAndAnimationsSuspended()) {
320 m_doc->suspendScriptedAnimationControllerCallbacks();
321 m_animationController.suspendAnimationsForDocument(m_doc.get());
322 m_doc->suspendActiveDOMObjects(ActiveDOMObject::PageWillBeSuspended);
326 #if ENABLE(ORIENTATION_EVENTS)
327 void Frame::sendOrientationChangeEvent(int orientation)
329 m_orientation = orientation;
330 if (Document* doc = document())
331 doc->dispatchWindowEvent(Event::create(eventNames().orientationchangeEvent, false, false));
333 #if ENABLE(SCREEN_ORIENTATION_SUPPORT) && ENABLE(TIZEN_SCREEN_ORIENTATION_SUPPORT)
334 if (Document* doc = document())
335 doc->domWindow()->screen()->sendOrientationChangeEvent(orientation);
338 #endif // ENABLE(ORIENTATION_EVENTS)
340 Settings* Frame::settings() const
342 return m_page ? m_page->settings() : 0;
345 static PassOwnPtr<RegularExpression> createRegExpForLabels(const Vector<String>& labels)
347 // REVIEW- version of this call in FrameMac.mm caches based on the NSArray ptrs being
348 // the same across calls. We can't do that.
350 DEFINE_STATIC_LOCAL(RegularExpression, wordRegExp, ("\\w", TextCaseSensitive));
352 unsigned int numLabels = labels.size();
354 for (i = 0; i < numLabels; i++) {
355 String label = labels[i];
357 bool startsWithWordChar = false;
358 bool endsWithWordChar = false;
359 if (label.length()) {
360 startsWithWordChar = wordRegExp.match(label.substring(0, 1)) >= 0;
361 endsWithWordChar = wordRegExp.match(label.substring(label.length() - 1, 1)) >= 0;
366 // Search for word boundaries only if label starts/ends with "word characters".
367 // If we always searched for word boundaries, this wouldn't work for languages
369 if (startsWithWordChar)
370 pattern.append("\\b");
371 pattern.append(label);
372 if (endsWithWordChar)
373 pattern.append("\\b");
376 return adoptPtr(new RegularExpression(pattern, TextCaseInsensitive));
379 String Frame::searchForLabelsAboveCell(RegularExpression* regExp, HTMLTableCellElement* cell, size_t* resultDistanceFromStartOfCell)
381 HTMLTableCellElement* aboveCell = cell->cellAbove();
383 // search within the above cell we found for a match
384 size_t lengthSearched = 0;
385 for (Node* n = aboveCell->firstChild(); n; n = n->traverseNextNode(aboveCell)) {
386 if (n->isTextNode() && n->renderer() && n->renderer()->style()->visibility() == VISIBLE) {
387 // For each text chunk, run the regexp
388 String nodeString = n->nodeValue();
389 int pos = regExp->searchRev(nodeString);
391 if (resultDistanceFromStartOfCell)
392 *resultDistanceFromStartOfCell = lengthSearched;
393 return nodeString.substring(pos, regExp->matchedLength());
395 lengthSearched += nodeString.length();
400 // Any reason in practice to search all cells in that are above cell?
401 if (resultDistanceFromStartOfCell)
402 *resultDistanceFromStartOfCell = notFound;
406 String Frame::searchForLabelsBeforeElement(const Vector<String>& labels, Element* element, size_t* resultDistance, bool* resultIsInCellAbove)
408 OwnPtr<RegularExpression> regExp(createRegExpForLabels(labels));
409 // We stop searching after we've seen this many chars
410 const unsigned int charsSearchedThreshold = 500;
411 // This is the absolute max we search. We allow a little more slop than
412 // charsSearchedThreshold, to make it more likely that we'll search whole nodes.
413 const unsigned int maxCharsSearched = 600;
414 // If the starting element is within a table, the cell that contains it
415 HTMLTableCellElement* startingTableCell = 0;
416 bool searchedCellAbove = false;
419 *resultDistance = notFound;
420 if (resultIsInCellAbove)
421 *resultIsInCellAbove = false;
423 // walk backwards in the node tree, until another element, or form, or end of tree
424 int unsigned lengthSearched = 0;
426 for (n = element->traversePreviousNode();
427 n && lengthSearched < charsSearchedThreshold;
428 n = n->traversePreviousNode())
430 if (n->hasTagName(formTag)
431 || (n->isHTMLElement() && static_cast<Element*>(n)->isFormControlElement()))
433 // We hit another form element or the start of the form - bail out
435 } else if (n->hasTagName(tdTag) && !startingTableCell) {
436 startingTableCell = static_cast<HTMLTableCellElement*>(n);
437 } else if (n->hasTagName(trTag) && startingTableCell) {
438 String result = searchForLabelsAboveCell(regExp.get(), startingTableCell, resultDistance);
439 if (!result.isEmpty()) {
440 if (resultIsInCellAbove)
441 *resultIsInCellAbove = true;
444 searchedCellAbove = true;
445 } else if (n->isTextNode() && n->renderer() && n->renderer()->style()->visibility() == VISIBLE) {
446 // For each text chunk, run the regexp
447 String nodeString = n->nodeValue();
448 // add 100 for slop, to make it more likely that we'll search whole nodes
449 if (lengthSearched + nodeString.length() > maxCharsSearched)
450 nodeString = nodeString.right(charsSearchedThreshold - lengthSearched);
451 int pos = regExp->searchRev(nodeString);
454 *resultDistance = lengthSearched;
455 return nodeString.substring(pos, regExp->matchedLength());
457 lengthSearched += nodeString.length();
461 // If we started in a cell, but bailed because we found the start of the form or the
462 // previous element, we still might need to search the row above us for a label.
463 if (startingTableCell && !searchedCellAbove) {
464 String result = searchForLabelsAboveCell(regExp.get(), startingTableCell, resultDistance);
465 if (!result.isEmpty()) {
466 if (resultIsInCellAbove)
467 *resultIsInCellAbove = true;
474 static String matchLabelsAgainstString(const Vector<String>& labels, const String& stringToMatch)
476 if (stringToMatch.isEmpty())
479 String mutableStringToMatch = stringToMatch;
481 // Make numbers and _'s in field names behave like word boundaries, e.g., "address2"
482 replace(mutableStringToMatch, RegularExpression("\\d", TextCaseSensitive), " ");
483 mutableStringToMatch.replace('_', ' ');
485 OwnPtr<RegularExpression> regExp(createRegExpForLabels(labels));
486 // Use the largest match we can find in the whole string
493 pos = regExp->match(mutableStringToMatch, start);
495 length = regExp->matchedLength();
496 if (length >= bestLength) {
505 return mutableStringToMatch.substring(bestPos, bestLength);
509 String Frame::matchLabelsAgainstElement(const Vector<String>& labels, Element* element)
511 // Match against the name element, then against the id element if no match is found for the name element.
512 // See 7538330 for one popular site that benefits from the id element check.
513 // FIXME: This code is mirrored in FrameMac.mm. It would be nice to make the Mac code call the platform-agnostic
514 // code, which would require converting the NSArray of NSStrings to a Vector of Strings somewhere along the way.
515 String resultFromNameAttribute = matchLabelsAgainstString(labels, element->getNameAttribute());
516 if (!resultFromNameAttribute.isEmpty())
517 return resultFromNameAttribute;
519 return matchLabelsAgainstString(labels, element->getAttribute(idAttr));
522 void Frame::setPrinting(bool printing, const FloatSize& pageSize, const FloatSize& originalPageSize, float maximumShrinkRatio, AdjustViewSizeOrNot shouldAdjustViewSize)
524 // In setting printing, we should not validate resources already cached for the document.
525 // See https://bugs.webkit.org/show_bug.cgi?id=43704
526 ResourceCacheValidationSuppressor validationSuppressor(m_doc->cachedResourceLoader());
528 m_doc->setPrinting(printing);
529 view()->adjustMediaTypeForPrinting(printing);
531 m_doc->styleResolverChanged(RecalcStyleImmediately);
532 if (shouldUsePrintingLayout()) {
533 view()->forceLayoutForPagination(pageSize, originalPageSize, maximumShrinkRatio, shouldAdjustViewSize);
535 view()->forceLayout();
536 if (shouldAdjustViewSize == AdjustViewSize)
537 view()->adjustViewSize();
540 // Subframes of the one we're printing don't lay out to the page size.
541 for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
542 child->setPrinting(printing, FloatSize(), FloatSize(), 0, shouldAdjustViewSize);
545 bool Frame::shouldUsePrintingLayout() const
547 // Only top frame being printed should be fit to page size.
548 // Subframes should be constrained by parents only.
549 return m_doc->printing() && (!tree()->parent() || !tree()->parent()->m_doc->printing());
552 FloatSize Frame::resizePageRectsKeepingRatio(const FloatSize& originalSize, const FloatSize& expectedSize)
554 FloatSize resultSize;
555 if (!contentRenderer())
558 if (contentRenderer()->style()->isHorizontalWritingMode()) {
559 ASSERT(fabs(originalSize.width()) > numeric_limits<float>::epsilon());
560 float ratio = originalSize.height() / originalSize.width();
561 resultSize.setWidth(floorf(expectedSize.width()));
562 resultSize.setHeight(floorf(resultSize.width() * ratio));
564 ASSERT(fabs(originalSize.height()) > numeric_limits<float>::epsilon());
565 float ratio = originalSize.width() / originalSize.height();
566 resultSize.setHeight(floorf(expectedSize.height()));
567 resultSize.setWidth(floorf(resultSize.height() * ratio));
572 void Frame::injectUserScripts(UserScriptInjectionTime injectionTime)
577 if (loader()->stateMachine()->creatingInitialEmptyDocument() && !settings()->shouldInjectUserScriptsInInitialEmptyDocument())
580 // Walk the hashtable. Inject by world.
581 const UserScriptMap* userScripts = m_page->group().userScripts();
584 UserScriptMap::const_iterator end = userScripts->end();
585 for (UserScriptMap::const_iterator it = userScripts->begin(); it != end; ++it)
586 injectUserScriptsForWorld(it->first.get(), *it->second, injectionTime);
589 void Frame::injectUserScriptsForWorld(DOMWrapperWorld* world, const UserScriptVector& userScripts, UserScriptInjectionTime injectionTime)
591 if (userScripts.isEmpty())
594 Document* doc = document();
598 Vector<ScriptSourceCode> sourceCode;
599 unsigned count = userScripts.size();
600 for (unsigned i = 0; i < count; ++i) {
601 UserScript* script = userScripts[i].get();
602 if (script->injectedFrames() == InjectInTopFrameOnly && ownerElement())
605 if (script->injectionTime() == injectionTime && UserContentURLPattern::matchesPatterns(doc->url(), script->whitelist(), script->blacklist()))
606 m_script.evaluateInWorld(ScriptSourceCode(script->source(), script->url()), world);
610 void Frame::clearDOMWindow()
613 InspectorInstrumentation::frameWindowDiscarded(this, m_domWindow.get());
614 m_domWindow->clear();
619 RenderView* Frame::contentRenderer() const
621 Document* doc = document();
624 RenderObject* object = doc->renderer();
627 ASSERT(object->isRenderView());
628 return toRenderView(object);
631 RenderPart* Frame::ownerRenderer() const
633 HTMLFrameOwnerElement* ownerElement = m_ownerElement;
636 RenderObject* object = ownerElement->renderer();
639 // FIXME: If <object> is ever fixed to disassociate itself from frames
640 // that it has started but canceled, then this can turn into an ASSERT
641 // since m_ownerElement would be 0 when the load is canceled.
642 // https://bugs.webkit.org/show_bug.cgi?id=18585
643 if (!object->isRenderPart())
645 return toRenderPart(object);
648 Frame* Frame::frameForWidget(const Widget* widget)
650 ASSERT_ARG(widget, widget);
652 if (RenderWidget* renderer = RenderWidget::find(widget))
653 if (Node* node = renderer->node())
654 return node->document()->frame();
656 // Assume all widgets are either a FrameView or owned by a RenderWidget.
657 // FIXME: That assumption is not right for scroll bars!
658 ASSERT(widget->isFrameView());
659 return static_cast<const FrameView*>(widget)->frame();
662 void Frame::clearTimers(FrameView *view, Document *document)
665 view->unscheduleRelayout();
667 view->frame()->animation()->suspendAnimationsForDocument(document);
668 view->frame()->eventHandler()->stopAutoscrollTimer();
673 void Frame::clearTimers()
675 clearTimers(m_view.get(), document());
678 void Frame::setDOMWindow(DOMWindow* domWindow)
681 InspectorInstrumentation::frameWindowDiscarded(this, m_domWindow.get());
682 m_domWindow->clear();
684 m_domWindow = domWindow;
687 #if ENABLE(PAGE_VISIBILITY_API)
688 void Frame::dispatchVisibilityStateChangeEvent()
691 m_doc->dispatchVisibilityStateChangeEvent();
692 for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
693 child->dispatchVisibilityStateChangeEvent();
697 void Frame::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
699 MemoryClassInfo<Frame> info(memoryObjectInfo, this, MemoryInstrumentation::DOM);
700 info.addInstrumentedMember(m_doc.get());
701 info.addInstrumentedMember(m_loader);
704 DOMWindow* Frame::domWindow() const
707 m_domWindow = DOMWindow::create(const_cast<Frame*>(this));
709 return m_domWindow.get();
712 void Frame::willDetachPage()
714 if (Frame* parent = tree()->parent())
715 parent->loader()->checkLoadComplete();
717 HashSet<FrameDestructionObserver*>::iterator stop = m_destructionObservers.end();
718 for (HashSet<FrameDestructionObserver*>::iterator it = m_destructionObservers.begin(); it != stop; ++it)
719 (*it)->willDetachPage();
721 // FIXME: It's unclear as to why this is called more than once, but it is,
722 // so page() could be NULL.
723 if (page() && page()->focusController()->focusedFrame() == this)
724 page()->focusController()->setFocusedFrame(0);
726 script()->clearScriptObjects();
727 script()->updatePlatformScriptObjects();
730 void Frame::disconnectOwnerElement()
732 if (m_ownerElement) {
733 if (Document* doc = document())
734 doc->clearAXObjectCache();
735 m_ownerElement->m_contentFrame = 0;
737 m_page->decrementFrameCount();
742 String Frame::documentTypeString() const
744 if (DocumentType* doctype = document()->doctype())
745 return createMarkup(doctype);
750 String Frame::displayStringModifiedByEncoding(const String& str) const
752 return document() ? document()->displayStringModifiedByEncoding(str) : str;
755 VisiblePosition Frame::visiblePositionForPoint(const IntPoint& framePoint)
757 HitTestResult result = eventHandler()->hitTestResultAtPoint(framePoint, true);
758 Node* node = result.innerNonSharedNode();
760 return VisiblePosition();
761 RenderObject* renderer = node->renderer();
763 return VisiblePosition();
764 VisiblePosition visiblePos = renderer->positionForPoint(result.localPoint());
765 if (visiblePos.isNull())
766 visiblePos = firstPositionInOrBeforeNode(node);
770 Document* Frame::documentAtPoint(const IntPoint& point)
775 IntPoint pt = view()->windowToContents(point);
776 HitTestResult result = HitTestResult(pt);
778 if (contentRenderer())
779 result = eventHandler()->hitTestResultAtPoint(pt, false);
780 return result.innerNode() ? result.innerNode()->document() : 0;
783 PassRefPtr<Range> Frame::rangeForPoint(const IntPoint& framePoint)
785 VisiblePosition position = visiblePositionForPoint(framePoint);
786 if (position.isNull())
789 VisiblePosition previous = position.previous();
790 if (previous.isNotNull()) {
791 RefPtr<Range> previousCharacterRange = makeRange(previous, position);
792 LayoutRect rect = editor()->firstRectForRange(previousCharacterRange.get());
793 if (rect.contains(framePoint))
794 return previousCharacterRange.release();
797 VisiblePosition next = position.next();
798 if (RefPtr<Range> nextCharacterRange = makeRange(position, next)) {
799 LayoutRect rect = editor()->firstRectForRange(nextCharacterRange.get());
800 if (rect.contains(framePoint))
801 return nextCharacterRange.release();
807 void Frame::createView(const IntSize& viewportSize, const Color& backgroundColor, bool transparent,
808 const IntSize& fixedLayoutSize, const IntRect& fixedVisibleContentRect ,
809 bool useFixedLayout, ScrollbarMode horizontalScrollbarMode, bool horizontalLock,
810 ScrollbarMode verticalScrollbarMode, bool verticalLock)
815 bool isMainFrame = this == m_page->mainFrame();
817 if (isMainFrame && view())
818 view()->setParentVisible(false);
822 RefPtr<FrameView> frameView;
824 frameView = FrameView::create(this, viewportSize);
825 frameView->setFixedLayoutSize(fixedLayoutSize);
826 frameView->setFixedVisibleContentRect(fixedVisibleContentRect);
827 frameView->setUseFixedLayout(useFixedLayout);
829 frameView = FrameView::create(this);
831 frameView->setScrollbarModes(horizontalScrollbarMode, verticalScrollbarMode, horizontalLock, verticalLock);
835 if (backgroundColor.isValid())
836 frameView->updateBackgroundRecursively(backgroundColor, transparent);
839 frameView->setParentVisible(true);
842 ownerRenderer()->setWidget(frameView);
844 if (HTMLFrameOwnerElement* owner = ownerElement())
845 view()->setCanHaveScrollbars(owner->scrollingMode() != ScrollbarAlwaysOff);
848 #if USE(TILED_BACKING_STORE)
849 void Frame::setTiledBackingStoreEnabled(bool enabled)
852 m_tiledBackingStore.clear();
855 if (m_tiledBackingStore)
857 m_tiledBackingStore = adoptPtr(new TiledBackingStore(this));
859 m_view->setPaintsEntireContents(true);
862 void Frame::tiledBackingStorePaintBegin()
866 m_view->updateLayoutAndStyleIfNeededRecursive();
867 m_view->flushDeferredRepaints();
870 void Frame::tiledBackingStorePaint(GraphicsContext* context, const IntRect& rect)
874 m_view->paintContents(context, rect);
877 void Frame::tiledBackingStorePaintEnd(const Vector<IntRect>& paintedArea)
879 if (!m_page || !m_view)
881 unsigned size = paintedArea.size();
882 // Request repaint from the system
883 for (unsigned n = 0; n < size; ++n)
884 m_page->chrome()->invalidateContentsAndRootView(m_view->contentsToRootView(paintedArea[n]), false);
887 IntRect Frame::tiledBackingStoreContentsRect()
891 return IntRect(IntPoint(), m_view->contentsSize());
894 IntRect Frame::tiledBackingStoreVisibleRect()
898 return m_page->chrome()->client()->visibleRectForTiledBackingStore();
901 Color Frame::tiledBackingStoreBackgroundColor() const
905 return m_view->baseBackgroundColor();
909 String Frame::layerTreeAsText(bool showDebugInfo) const
911 #if USE(ACCELERATED_COMPOSITING)
912 document()->updateLayout();
914 if (!contentRenderer())
917 return contentRenderer()->compositor()->layerTreeAsText(showDebugInfo);
923 void Frame::setPageZoomFactor(float factor)
925 setPageAndTextZoomFactors(factor, m_textZoomFactor);
928 void Frame::setTextZoomFactor(float factor)
930 setPageAndTextZoomFactors(m_pageZoomFactor, factor);
933 void Frame::setPageAndTextZoomFactors(float pageZoomFactor, float textZoomFactor)
935 if (m_pageZoomFactor == pageZoomFactor && m_textZoomFactor == textZoomFactor)
938 Page* page = this->page();
942 Document* document = this->document();
946 m_editor.dismissCorrectionPanelAsIgnored();
949 // Respect SVGs zoomAndPan="disabled" property in standalone SVG documents.
950 // FIXME: How to handle compound documents + zoomAndPan="disabled"? Needs SVG WG clarification.
951 if (document->isSVGDocument()) {
952 if (!static_cast<SVGDocument*>(document)->zoomAndPanEnabled())
957 if (m_pageZoomFactor != pageZoomFactor) {
958 if (FrameView* view = this->view()) {
959 // Update the scroll position when doing a full page zoom, so the content stays in relatively the same position.
960 LayoutPoint scrollPosition = view->scrollPosition();
961 float percentDifference = (pageZoomFactor / m_pageZoomFactor);
962 view->setScrollPosition(IntPoint(scrollPosition.x() * percentDifference, scrollPosition.y() * percentDifference));
966 m_pageZoomFactor = pageZoomFactor;
967 m_textZoomFactor = textZoomFactor;
969 document->recalcStyle(Node::Force);
971 for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
972 child->setPageAndTextZoomFactors(m_pageZoomFactor, m_textZoomFactor);
974 if (FrameView* view = this->view()) {
975 if (document->renderer() && document->renderer()->needsLayout() && view->didFirstLayout())
979 if (page->mainFrame() == this)
980 pageCache()->markPagesForFullStyleRecalc(page);
983 float Frame::frameScaleFactor() const
985 Page* page = this->page();
987 // Main frame is scaled with respect to he container but inner frames are not scaled with respect to the main frame.
988 if (!page || page->mainFrame() != this)
990 return page->pageScaleFactor();
993 #if ENABLE(TIZEN_WEBKIT2_HISTORICAL_RESTORE_VISIBLE_CONTENT_RECT)
994 float Frame::contentsScaleFactor() const
998 return m_page->chrome()->client()->contentsScaleFactor();
1002 void Frame::suspendActiveDOMObjectsAndAnimations()
1004 bool wasSuspended = activeDOMObjectsAndAnimationsSuspended();
1006 m_activeDOMObjectsAndAnimationsSuspendedCount++;
1012 document()->suspendScriptedAnimationControllerCallbacks();
1013 animation()->suspendAnimationsForDocument(document());
1014 document()->suspendActiveDOMObjects(ActiveDOMObject::PageWillBeSuspended);
1018 void Frame::resumeActiveDOMObjectsAndAnimations()
1020 ASSERT(activeDOMObjectsAndAnimationsSuspended());
1022 m_activeDOMObjectsAndAnimationsSuspendedCount--;
1024 if (activeDOMObjectsAndAnimationsSuspended())
1028 document()->resumeActiveDOMObjects();
1029 animation()->resumeAnimationsForDocument(document());
1030 document()->resumeScriptedAnimationControllerCallbacks();
1034 #if USE(ACCELERATED_COMPOSITING)
1035 void Frame::deviceOrPageScaleFactorChanged()
1037 for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
1038 child->deviceOrPageScaleFactorChanged();
1040 RenderView* root = contentRenderer();
1041 if (root && root->compositor())
1042 root->compositor()->deviceOrPageScaleFactorChanged();
1045 void Frame::notifyChromeClientWheelEventHandlerCountChanged() const
1047 // Ensure that this method is being called on the main frame of the page.
1048 ASSERT(m_page && m_page->mainFrame() == this);
1051 for (const Frame* frame = this; frame; frame = frame->tree()->traverseNext()) {
1052 if (frame->document())
1053 count += frame->document()->wheelEventHandlerCount();
1056 m_page->chrome()->client()->numWheelEventHandlersChanged(count);
1059 #if !PLATFORM(MAC) && !PLATFORM(WIN)
1060 struct ScopedFramePaintingState {
1061 ScopedFramePaintingState(Frame* frame, Node* node)
1064 , paintBehavior(frame->view()->paintBehavior())
1065 , backgroundColor(frame->view()->baseBackgroundColor())
1067 ASSERT(!node || node->renderer());
1069 node->renderer()->updateDragState(true);
1072 ~ScopedFramePaintingState()
1074 if (node && node->renderer())
1075 node->renderer()->updateDragState(false);
1076 frame->view()->setPaintBehavior(paintBehavior);
1077 frame->view()->setBaseBackgroundColor(backgroundColor);
1078 frame->view()->setNodeToDraw(0);
1083 PaintBehavior paintBehavior;
1084 Color backgroundColor;
1087 DragImageRef Frame::nodeImage(Node* node)
1089 if (!node->renderer())
1092 const ScopedFramePaintingState state(this, node);
1094 m_view->setPaintBehavior(state.paintBehavior | PaintBehaviorFlattenCompositingLayers);
1096 // When generating the drag image for an element, ignore the document background.
1097 m_view->setBaseBackgroundColor(colorWithOverrideAlpha(Color::white, 1.0));
1098 m_doc->updateLayout();
1099 m_view->setNodeToDraw(node); // Enable special sub-tree drawing mode.
1101 // Document::updateLayout may have blown away the original RenderObject.
1102 RenderObject* renderer = node->renderer();
1106 LayoutRect topLevelRect;
1107 IntRect paintingRect = pixelSnappedIntRect(renderer->paintingRootRect(topLevelRect));
1109 float deviceScaleFactor = 1;
1111 deviceScaleFactor = m_page->deviceScaleFactor();
1112 paintingRect.setWidth(paintingRect.width() * deviceScaleFactor);
1113 paintingRect.setHeight(paintingRect.height() * deviceScaleFactor);
1115 OwnPtr<ImageBuffer> buffer(ImageBuffer::create(paintingRect.size(), deviceScaleFactor, ColorSpaceDeviceRGB));
1118 buffer->context()->translate(-paintingRect.x(), -paintingRect.y());
1119 buffer->context()->clip(FloatRect(0, 0, paintingRect.maxX(), paintingRect.maxY()));
1121 m_view->paintContents(buffer->context(), paintingRect);
1123 RefPtr<Image> image = buffer->copyImage();
1124 return createDragImageFromImage(image.get(), renderer->shouldRespectImageOrientation());
1127 DragImageRef Frame::dragImageForSelection()
1129 if (!selection()->isRange())
1132 const ScopedFramePaintingState state(this, 0);
1133 m_view->setPaintBehavior(PaintBehaviorSelectionOnly);
1134 m_doc->updateLayout();
1136 IntRect paintingRect = enclosingIntRect(selection()->bounds());
1138 float deviceScaleFactor = 1;
1140 deviceScaleFactor = m_page->deviceScaleFactor();
1141 paintingRect.setWidth(paintingRect.width() * deviceScaleFactor);
1142 paintingRect.setHeight(paintingRect.height() * deviceScaleFactor);
1144 OwnPtr<ImageBuffer> buffer(ImageBuffer::create(paintingRect.size(), deviceScaleFactor, ColorSpaceDeviceRGB));
1147 buffer->context()->translate(-paintingRect.x(), -paintingRect.y());
1148 buffer->context()->clip(FloatRect(0, 0, paintingRect.maxX(), paintingRect.maxY()));
1150 m_view->paintContents(buffer->context(), paintingRect);
1152 RefPtr<Image> image = buffer->copyImage();
1153 return createDragImageFromImage(image.get());
1158 } // namespace WebCore