• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
3  *                     1999 Lars Knoll <knoll@kde.org>
4  *                     1999 Antti Koivisto <koivisto@kde.org>
5  *                     2000 Simon Hausmann <hausmann@kde.org>
6  *                     2000 Stefan Schimanski <1Stein@gmx.de>
7  *                     2001 George Staikos <staikos@kde.org>
8  * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
9  * Copyright (C) 2005 Alexey Proskuryakov <ap@nypop.com>
10  * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
11  * Copyright (C) 2008 Eric Seidel <eric@webkit.org>
12  * Copyright (C) 2008 Google Inc.
13  *
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.
18  *
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.
23  *
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.
28  */
29 
30 #include "config.h"
31 #include "core/frame/Frame.h"
32 
33 #include "RuntimeEnabledFeatures.h"
34 #include "bindings/v8/ScriptController.h"
35 #include "core/dom/DocumentType.h"
36 #include "core/dom/WheelController.h"
37 #include "core/editing/Editor.h"
38 #include "core/editing/FrameSelection.h"
39 #include "core/editing/InputMethodController.h"
40 #include "core/editing/SpellChecker.h"
41 #include "core/editing/htmlediting.h"
42 #include "core/editing/markup.h"
43 #include "core/events/Event.h"
44 #include "core/fetch/ResourceFetcher.h"
45 #include "core/frame/DOMWindow.h"
46 #include "core/frame/FrameDestructionObserver.h"
47 #include "core/frame/FrameView.h"
48 #include "core/frame/Settings.h"
49 #include "core/frame/animation/AnimationController.h"
50 #include "core/html/HTMLFrameElementBase.h"
51 #include "core/inspector/InspectorInstrumentation.h"
52 #include "core/loader/EmptyClients.h"
53 #include "core/loader/FrameLoaderClient.h"
54 #include "core/page/Chrome.h"
55 #include "core/page/ChromeClient.h"
56 #include "core/page/EventHandler.h"
57 #include "core/page/FocusController.h"
58 #include "core/page/Page.h"
59 #include "core/page/scrolling/ScrollingCoordinator.h"
60 #include "core/platform/DragImage.h"
61 #include "core/rendering/HitTestResult.h"
62 #include "core/rendering/RenderLayerCompositor.h"
63 #include "core/rendering/RenderPart.h"
64 #include "core/rendering/RenderView.h"
65 #include "core/svg/SVGDocument.h"
66 #include "platform/graphics/GraphicsContext.h"
67 #include "platform/graphics/ImageBuffer.h"
68 #include "public/platform/WebLayer.h"
69 #include "wtf/PassOwnPtr.h"
70 #include "wtf/RefCountedLeakCounter.h"
71 #include "wtf/StdLibExtras.h"
72 
73 using namespace std;
74 
75 namespace WebCore {
76 
77 using namespace HTMLNames;
78 
79 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, frameCounter, ("Frame"));
80 
parentFromOwnerElement(HTMLFrameOwnerElement * ownerElement)81 static inline Frame* parentFromOwnerElement(HTMLFrameOwnerElement* ownerElement)
82 {
83     if (!ownerElement)
84         return 0;
85     return ownerElement->document().frame();
86 }
87 
parentPageZoomFactor(Frame * frame)88 static inline float parentPageZoomFactor(Frame* frame)
89 {
90     Frame* parent = frame->tree().parent();
91     if (!parent)
92         return 1;
93     return parent->pageZoomFactor();
94 }
95 
parentTextZoomFactor(Frame * frame)96 static inline float parentTextZoomFactor(Frame* frame)
97 {
98     Frame* parent = frame->tree().parent();
99     if (!parent)
100         return 1;
101     return parent->textZoomFactor();
102 }
103 
Frame(PassRefPtr<FrameInit> frameInit)104 inline Frame::Frame(PassRefPtr<FrameInit> frameInit)
105     : m_page(frameInit->page())
106     , m_treeNode(this, parentFromOwnerElement(frameInit->ownerElement()))
107     , m_loader(this, frameInit->frameLoaderClient())
108     , m_navigationScheduler(this)
109     , m_script(adoptPtr(new ScriptController(this)))
110     , m_editor(Editor::create(*this))
111     , m_spellChecker(SpellChecker::create(*this))
112     , m_selection(adoptPtr(new FrameSelection(this)))
113     , m_eventHandler(adoptPtr(new EventHandler(this)))
114     , m_animationController(adoptPtr(new AnimationController(this)))
115     , m_inputMethodController(InputMethodController::create(*this))
116     , m_frameInit(frameInit)
117     , m_pageZoomFactor(parentPageZoomFactor(this))
118     , m_textZoomFactor(parentTextZoomFactor(this))
119 #if ENABLE(ORIENTATION_EVENTS)
120     , m_orientation(0)
121 #endif
122     , m_inViewSourceMode(false)
123     , m_remotePlatformLayer(0)
124 {
125     ASSERT(m_page);
126 
127     if (ownerElement()) {
128         m_page->incrementSubframeCount();
129         ownerElement()->setContentFrame(*this);
130     }
131 
132 #ifndef NDEBUG
133     frameCounter.increment();
134 #endif
135 }
136 
create(PassRefPtr<FrameInit> frameInit)137 PassRefPtr<Frame> Frame::create(PassRefPtr<FrameInit> frameInit)
138 {
139     RefPtr<Frame> frame = adoptRef(new Frame(frameInit));
140     if (!frame->ownerElement())
141         frame->page()->setMainFrame(frame);
142     InspectorInstrumentation::frameAttachedToParent(frame.get());
143     return frame.release();
144 }
145 
~Frame()146 Frame::~Frame()
147 {
148     setView(0);
149     loader().clear(ClearScriptObjects | ClearWindowObject);
150 
151     // FIXME: We should not be doing all this work inside the destructor
152 
153 #ifndef NDEBUG
154     frameCounter.decrement();
155 #endif
156 
157     disconnectOwnerElement();
158 
159     HashSet<FrameDestructionObserver*>::iterator stop = m_destructionObservers.end();
160     for (HashSet<FrameDestructionObserver*>::iterator it = m_destructionObservers.begin(); it != stop; ++it)
161         (*it)->frameDestroyed();
162 }
163 
inScope(TreeScope * scope) const164 bool Frame::inScope(TreeScope* scope) const
165 {
166     ASSERT(scope);
167     Document* doc = document();
168     if (!doc)
169         return false;
170     HTMLFrameOwnerElement* owner = doc->ownerElement();
171     if (!owner)
172         return false;
173     return owner->treeScope() == scope;
174 }
175 
addDestructionObserver(FrameDestructionObserver * observer)176 void Frame::addDestructionObserver(FrameDestructionObserver* observer)
177 {
178     m_destructionObservers.add(observer);
179 }
180 
removeDestructionObserver(FrameDestructionObserver * observer)181 void Frame::removeDestructionObserver(FrameDestructionObserver* observer)
182 {
183     m_destructionObservers.remove(observer);
184 }
185 
setView(PassRefPtr<FrameView> view)186 void Frame::setView(PassRefPtr<FrameView> view)
187 {
188     // We the custom scroll bars as early as possible to prevent m_doc->detach()
189     // from messing with the view such that its scroll bars won't be torn down.
190     // FIXME: We should revisit this.
191     if (m_view)
192         m_view->prepareForDetach();
193 
194     // Prepare for destruction now, so any unload event handlers get run and the DOMWindow is
195     // notified. If we wait until the view is destroyed, then things won't be hooked up enough for
196     // these calls to work.
197     if (!view && document() && document()->isActive()) {
198         // FIXME: We don't call willRemove here. Why is that OK?
199         document()->prepareForDestruction();
200     }
201 
202     if (m_view)
203         m_view->unscheduleRelayout();
204 
205     eventHandler().clear();
206 
207     m_view = view;
208 
209     if (m_view && isMainFrame())
210         m_view->setVisibleContentScaleFactor(m_page->pageScaleFactor());
211 }
212 
213 #if ENABLE(ORIENTATION_EVENTS)
sendOrientationChangeEvent(int orientation)214 void Frame::sendOrientationChangeEvent(int orientation)
215 {
216     m_orientation = orientation;
217     if (DOMWindow* window = domWindow())
218         window->dispatchEvent(Event::create(EventTypeNames::orientationchange));
219 }
220 #endif // ENABLE(ORIENTATION_EVENTS)
221 
settings() const222 Settings* Frame::settings() const
223 {
224     return m_page ? &m_page->settings() : 0;
225 }
226 
setPrinting(bool printing,const FloatSize & pageSize,const FloatSize & originalPageSize,float maximumShrinkRatio,AdjustViewSizeOrNot shouldAdjustViewSize)227 void Frame::setPrinting(bool printing, const FloatSize& pageSize, const FloatSize& originalPageSize, float maximumShrinkRatio, AdjustViewSizeOrNot shouldAdjustViewSize)
228 {
229     // In setting printing, we should not validate resources already cached for the document.
230     // See https://bugs.webkit.org/show_bug.cgi?id=43704
231     ResourceCacheValidationSuppressor validationSuppressor(document()->fetcher());
232 
233     document()->setPrinting(printing);
234     view()->adjustMediaTypeForPrinting(printing);
235 
236     document()->styleResolverChanged(RecalcStyleImmediately);
237     if (shouldUsePrintingLayout()) {
238         view()->forceLayoutForPagination(pageSize, originalPageSize, maximumShrinkRatio, shouldAdjustViewSize);
239     } else {
240         view()->forceLayout();
241         if (shouldAdjustViewSize == AdjustViewSize)
242             view()->adjustViewSize();
243     }
244 
245     // Subframes of the one we're printing don't lay out to the page size.
246     for (RefPtr<Frame> child = tree().firstChild(); child; child = child->tree().nextSibling())
247         child->setPrinting(printing, FloatSize(), FloatSize(), 0, shouldAdjustViewSize);
248 }
249 
shouldUsePrintingLayout() const250 bool Frame::shouldUsePrintingLayout() const
251 {
252     // Only top frame being printed should be fit to page size.
253     // Subframes should be constrained by parents only.
254     return document()->printing() && (!tree().parent() || !tree().parent()->document()->printing());
255 }
256 
resizePageRectsKeepingRatio(const FloatSize & originalSize,const FloatSize & expectedSize)257 FloatSize Frame::resizePageRectsKeepingRatio(const FloatSize& originalSize, const FloatSize& expectedSize)
258 {
259     FloatSize resultSize;
260     if (!contentRenderer())
261         return FloatSize();
262 
263     if (contentRenderer()->style()->isHorizontalWritingMode()) {
264         ASSERT(fabs(originalSize.width()) > numeric_limits<float>::epsilon());
265         float ratio = originalSize.height() / originalSize.width();
266         resultSize.setWidth(floorf(expectedSize.width()));
267         resultSize.setHeight(floorf(resultSize.width() * ratio));
268     } else {
269         ASSERT(fabs(originalSize.height()) > numeric_limits<float>::epsilon());
270         float ratio = originalSize.width() / originalSize.height();
271         resultSize.setHeight(floorf(expectedSize.height()));
272         resultSize.setWidth(floorf(resultSize.height() * ratio));
273     }
274     return resultSize;
275 }
276 
setDOMWindow(PassRefPtr<DOMWindow> domWindow)277 void Frame::setDOMWindow(PassRefPtr<DOMWindow> domWindow)
278 {
279     m_domWindow = domWindow;
280 }
281 
emptyChromeClient()282 static ChromeClient& emptyChromeClient()
283 {
284     DEFINE_STATIC_LOCAL(EmptyChromeClient, client, ());
285     return client;
286 }
287 
chromeClient() const288 ChromeClient& Frame::chromeClient() const
289 {
290     if (Page* page = this->page())
291         return page->chrome().client();
292     return emptyChromeClient();
293 }
294 
document() const295 Document* Frame::document() const
296 {
297     return m_domWindow ? m_domWindow->document() : 0;
298 }
299 
contentRenderer() const300 RenderView* Frame::contentRenderer() const
301 {
302     return document() ? document()->renderView() : 0;
303 }
304 
ownerRenderer() const305 RenderPart* Frame::ownerRenderer() const
306 {
307     if (!ownerElement())
308         return 0;
309     RenderObject* object = ownerElement()->renderer();
310     if (!object)
311         return 0;
312     // FIXME: If <object> is ever fixed to disassociate itself from frames
313     // that it has started but canceled, then this can turn into an ASSERT
314     // since ownerElement() would be 0 when the load is canceled.
315     // https://bugs.webkit.org/show_bug.cgi?id=18585
316     if (!object->isRenderPart())
317         return 0;
318     return toRenderPart(object);
319 }
320 
dispatchVisibilityStateChangeEvent()321 void Frame::dispatchVisibilityStateChangeEvent()
322 {
323     if (document())
324         document()->dispatchVisibilityStateChangeEvent();
325 
326     Vector<RefPtr<Frame> > childFrames;
327     for (Frame* child = tree().firstChild(); child; child = child->tree().nextSibling())
328         childFrames.append(child);
329 
330     for (size_t i = 0; i < childFrames.size(); ++i)
331         childFrames[i]->dispatchVisibilityStateChangeEvent();
332 }
333 
willDetachPage()334 void Frame::willDetachPage()
335 {
336     // We should never be detatching the page during a Layout.
337     RELEASE_ASSERT(!m_view || !m_view->isInLayout());
338 
339     if (Frame* parent = tree().parent())
340         parent->loader().checkLoadComplete();
341 
342     HashSet<FrameDestructionObserver*>::iterator stop = m_destructionObservers.end();
343     for (HashSet<FrameDestructionObserver*>::iterator it = m_destructionObservers.begin(); it != stop; ++it)
344         (*it)->willDetachPage();
345 
346     // FIXME: It's unclear as to why this is called more than once, but it is,
347     // so page() could be NULL.
348     if (page() && page()->focusController().focusedFrame() == this)
349         page()->focusController().setFocusedFrame(0);
350 
351     if (page() && page()->scrollingCoordinator() && m_view)
352         page()->scrollingCoordinator()->willDestroyScrollableArea(m_view.get());
353 
354     script().clearScriptObjects();
355 }
356 
detachFromPage()357 void Frame::detachFromPage()
358 {
359     // We should never be detatching the page during a Layout.
360     RELEASE_ASSERT(!m_view || !m_view->isInLayout());
361     m_page = 0;
362 }
363 
disconnectOwnerElement()364 void Frame::disconnectOwnerElement()
365 {
366     if (ownerElement()) {
367         if (Document* doc = document())
368             doc->topDocument()->clearAXObjectCache();
369         ownerElement()->clearContentFrame();
370         if (m_page)
371             m_page->decrementSubframeCount();
372     }
373     m_frameInit->setOwnerElement(0);
374 }
375 
isMainFrame() const376 bool Frame::isMainFrame() const
377 {
378     return m_page && this == m_page->mainFrame();
379 }
380 
documentTypeString() const381 String Frame::documentTypeString() const
382 {
383     if (DocumentType* doctype = document()->doctype())
384         return createMarkup(doctype);
385 
386     return String();
387 }
388 
selectedText() const389 String Frame::selectedText() const
390 {
391     return selection().selectedText();
392 }
393 
selectedTextForClipboard() const394 String Frame::selectedTextForClipboard() const
395 {
396     return selection().selectedTextForClipboard();
397 }
398 
visiblePositionForPoint(const IntPoint & framePoint)399 VisiblePosition Frame::visiblePositionForPoint(const IntPoint& framePoint)
400 {
401     HitTestResult result = eventHandler().hitTestResultAtPoint(framePoint);
402     Node* node = result.innerNonSharedNode();
403     if (!node)
404         return VisiblePosition();
405     RenderObject* renderer = node->renderer();
406     if (!renderer)
407         return VisiblePosition();
408     VisiblePosition visiblePos = VisiblePosition(renderer->positionForPoint(result.localPoint()));
409     if (visiblePos.isNull())
410         visiblePos = firstPositionInOrBeforeNode(node);
411     return visiblePos;
412 }
413 
documentAtPoint(const IntPoint & point)414 Document* Frame::documentAtPoint(const IntPoint& point)
415 {
416     if (!view())
417         return 0;
418 
419     IntPoint pt = view()->windowToContents(point);
420     HitTestResult result = HitTestResult(pt);
421 
422     if (contentRenderer())
423         result = eventHandler().hitTestResultAtPoint(pt, HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
424     return result.innerNode() ? &result.innerNode()->document() : 0;
425 }
426 
rangeForPoint(const IntPoint & framePoint)427 PassRefPtr<Range> Frame::rangeForPoint(const IntPoint& framePoint)
428 {
429     VisiblePosition position = visiblePositionForPoint(framePoint);
430     if (position.isNull())
431         return 0;
432 
433     VisiblePosition previous = position.previous();
434     if (previous.isNotNull()) {
435         RefPtr<Range> previousCharacterRange = makeRange(previous, position);
436         LayoutRect rect = editor().firstRectForRange(previousCharacterRange.get());
437         if (rect.contains(framePoint))
438             return previousCharacterRange.release();
439     }
440 
441     VisiblePosition next = position.next();
442     if (RefPtr<Range> nextCharacterRange = makeRange(position, next)) {
443         LayoutRect rect = editor().firstRectForRange(nextCharacterRange.get());
444         if (rect.contains(framePoint))
445             return nextCharacterRange.release();
446     }
447 
448     return 0;
449 }
450 
createView(const IntSize & viewportSize,const Color & backgroundColor,bool transparent,ScrollbarMode horizontalScrollbarMode,bool horizontalLock,ScrollbarMode verticalScrollbarMode,bool verticalLock)451 void Frame::createView(const IntSize& viewportSize, const Color& backgroundColor, bool transparent,
452     ScrollbarMode horizontalScrollbarMode, bool horizontalLock,
453     ScrollbarMode verticalScrollbarMode, bool verticalLock)
454 {
455     ASSERT(this);
456     ASSERT(m_page);
457 
458     bool isMainFrame = this->isMainFrame();
459 
460     if (isMainFrame && view())
461         view()->setParentVisible(false);
462 
463     setView(0);
464 
465     RefPtr<FrameView> frameView;
466     if (isMainFrame) {
467         frameView = FrameView::create(this, viewportSize);
468 
469         // The layout size is set by WebViewImpl to support @viewport
470         frameView->setLayoutSizeFixedToFrameSize(false);
471     } else
472         frameView = FrameView::create(this);
473 
474     frameView->setScrollbarModes(horizontalScrollbarMode, verticalScrollbarMode, horizontalLock, verticalLock);
475 
476     setView(frameView);
477 
478     if (backgroundColor.isValid())
479         frameView->updateBackgroundRecursively(backgroundColor, transparent);
480 
481     if (isMainFrame)
482         frameView->setParentVisible(true);
483 
484     if (ownerRenderer())
485         ownerRenderer()->setWidget(frameView);
486 
487     if (HTMLFrameOwnerElement* owner = ownerElement())
488         view()->setCanHaveScrollbars(owner->scrollingMode() != ScrollbarAlwaysOff);
489 }
490 
layerTreeAsText(unsigned flags) const491 String Frame::layerTreeAsText(unsigned flags) const
492 {
493     document()->updateLayout();
494 
495     if (!contentRenderer())
496         return String();
497 
498     return contentRenderer()->compositor()->layerTreeAsText(static_cast<LayerTreeFlags>(flags));
499 }
500 
trackedRepaintRectsAsText() const501 String Frame::trackedRepaintRectsAsText() const
502 {
503     if (!m_view)
504         return String();
505     return m_view->trackedRepaintRectsAsText();
506 }
507 
setPageZoomFactor(float factor)508 void Frame::setPageZoomFactor(float factor)
509 {
510     setPageAndTextZoomFactors(factor, m_textZoomFactor);
511 }
512 
setTextZoomFactor(float factor)513 void Frame::setTextZoomFactor(float factor)
514 {
515     setPageAndTextZoomFactors(m_pageZoomFactor, factor);
516 }
517 
setPageAndTextZoomFactors(float pageZoomFactor,float textZoomFactor)518 void Frame::setPageAndTextZoomFactors(float pageZoomFactor, float textZoomFactor)
519 {
520     if (m_pageZoomFactor == pageZoomFactor && m_textZoomFactor == textZoomFactor)
521         return;
522 
523     Page* page = this->page();
524     if (!page)
525         return;
526 
527     Document* document = this->document();
528     if (!document)
529         return;
530 
531     // Respect SVGs zoomAndPan="disabled" property in standalone SVG documents.
532     // FIXME: How to handle compound documents + zoomAndPan="disabled"? Needs SVG WG clarification.
533     if (document->isSVGDocument()) {
534         if (!toSVGDocument(document)->zoomAndPanEnabled())
535             return;
536     }
537 
538     if (m_pageZoomFactor != pageZoomFactor) {
539         if (FrameView* view = this->view()) {
540             // Update the scroll position when doing a full page zoom, so the content stays in relatively the same position.
541             LayoutPoint scrollPosition = view->scrollPosition();
542             float percentDifference = (pageZoomFactor / m_pageZoomFactor);
543             view->setScrollPosition(IntPoint(scrollPosition.x() * percentDifference, scrollPosition.y() * percentDifference));
544         }
545     }
546 
547     m_pageZoomFactor = pageZoomFactor;
548     m_textZoomFactor = textZoomFactor;
549 
550     document->recalcStyle(Force);
551 
552     for (RefPtr<Frame> child = tree().firstChild(); child; child = child->tree().nextSibling())
553         child->setPageAndTextZoomFactors(m_pageZoomFactor, m_textZoomFactor);
554 
555     if (FrameView* view = this->view()) {
556         if (document->renderer() && document->renderer()->needsLayout() && view->didFirstLayout())
557             view->layout();
558     }
559 }
560 
deviceOrPageScaleFactorChanged()561 void Frame::deviceOrPageScaleFactorChanged()
562 {
563     document()->mediaQueryAffectingValueChanged();
564     for (RefPtr<Frame> child = tree().firstChild(); child; child = child->tree().nextSibling())
565         child->deviceOrPageScaleFactorChanged();
566 }
567 
notifyChromeClientWheelEventHandlerCountChanged() const568 void Frame::notifyChromeClientWheelEventHandlerCountChanged() const
569 {
570     // Ensure that this method is being called on the main frame of the page.
571     ASSERT(isMainFrame());
572 
573     unsigned count = 0;
574     for (const Frame* frame = this; frame; frame = frame->tree().traverseNext()) {
575         if (frame->document())
576             count += WheelController::from(frame->document())->wheelEventHandlerCount();
577     }
578 
579     m_page->chrome().client().numWheelEventHandlersChanged(count);
580 }
581 
isURLAllowed(const KURL & url) const582 bool Frame::isURLAllowed(const KURL& url) const
583 {
584     // We allow one level of self-reference because some sites depend on that,
585     // but we don't allow more than one.
586     if (m_page->subframeCount() >= Page::maxNumberOfFrames)
587         return false;
588     bool foundSelfReference = false;
589     for (const Frame* frame = this; frame; frame = frame->tree().parent()) {
590         if (equalIgnoringFragmentIdentifier(frame->document()->url(), url)) {
591             if (foundSelfReference)
592                 return false;
593             foundSelfReference = true;
594         }
595     }
596     return true;
597 }
598 
599 struct ScopedFramePaintingState {
ScopedFramePaintingStateWebCore::ScopedFramePaintingState600     ScopedFramePaintingState(Frame* frame, Node* node)
601         : frame(frame)
602         , node(node)
603         , paintBehavior(frame->view()->paintBehavior())
604         , backgroundColor(frame->view()->baseBackgroundColor())
605     {
606         ASSERT(!node || node->renderer());
607         if (node)
608             node->renderer()->updateDragState(true);
609     }
610 
~ScopedFramePaintingStateWebCore::ScopedFramePaintingState611     ~ScopedFramePaintingState()
612     {
613         if (node && node->renderer())
614             node->renderer()->updateDragState(false);
615         frame->view()->setPaintBehavior(paintBehavior);
616         frame->view()->setBaseBackgroundColor(backgroundColor);
617         frame->view()->setNodeToDraw(0);
618     }
619 
620     Frame* frame;
621     Node* node;
622     PaintBehavior paintBehavior;
623     Color backgroundColor;
624 };
625 
nodeImage(Node * node)626 PassOwnPtr<DragImage> Frame::nodeImage(Node* node)
627 {
628     if (!node->renderer())
629         return nullptr;
630 
631     const ScopedFramePaintingState state(this, node);
632 
633     m_view->setPaintBehavior(state.paintBehavior | PaintBehaviorFlattenCompositingLayers);
634 
635     // When generating the drag image for an element, ignore the document background.
636     m_view->setBaseBackgroundColor(Color::transparent);
637     document()->updateLayout();
638     m_view->setNodeToDraw(node); // Enable special sub-tree drawing mode.
639 
640     // Document::updateLayout may have blown away the original RenderObject.
641     RenderObject* renderer = node->renderer();
642     if (!renderer)
643         return nullptr;
644 
645     LayoutRect topLevelRect;
646     IntRect paintingRect = pixelSnappedIntRect(renderer->paintingRootRect(topLevelRect));
647 
648     float deviceScaleFactor = 1;
649     if (m_page)
650         deviceScaleFactor = m_page->deviceScaleFactor();
651     paintingRect.setWidth(paintingRect.width() * deviceScaleFactor);
652     paintingRect.setHeight(paintingRect.height() * deviceScaleFactor);
653 
654     OwnPtr<ImageBuffer> buffer = ImageBuffer::create(paintingRect.size());
655     if (!buffer)
656         return nullptr;
657     buffer->context()->scale(FloatSize(deviceScaleFactor, deviceScaleFactor));
658     buffer->context()->translate(-paintingRect.x(), -paintingRect.y());
659     buffer->context()->clip(FloatRect(0, 0, paintingRect.maxX(), paintingRect.maxY()));
660 
661     m_view->paintContents(buffer->context(), paintingRect);
662 
663     RefPtr<Image> image = buffer->copyImage();
664     return DragImage::create(image.get(), renderer->shouldRespectImageOrientation(), deviceScaleFactor);
665 }
666 
dragImageForSelection()667 PassOwnPtr<DragImage> Frame::dragImageForSelection()
668 {
669     if (!selection().isRange())
670         return nullptr;
671 
672     const ScopedFramePaintingState state(this, 0);
673     m_view->setPaintBehavior(PaintBehaviorSelectionOnly | PaintBehaviorFlattenCompositingLayers);
674     document()->updateLayout();
675 
676     IntRect paintingRect = enclosingIntRect(selection().bounds());
677 
678     float deviceScaleFactor = 1;
679     if (m_page)
680         deviceScaleFactor = m_page->deviceScaleFactor();
681     paintingRect.setWidth(paintingRect.width() * deviceScaleFactor);
682     paintingRect.setHeight(paintingRect.height() * deviceScaleFactor);
683 
684     OwnPtr<ImageBuffer> buffer = ImageBuffer::create(paintingRect.size());
685     if (!buffer)
686         return nullptr;
687     buffer->context()->scale(FloatSize(deviceScaleFactor, deviceScaleFactor));
688     buffer->context()->translate(-paintingRect.x(), -paintingRect.y());
689     buffer->context()->clip(FloatRect(0, 0, paintingRect.maxX(), paintingRect.maxY()));
690 
691     m_view->paintContents(buffer->context(), paintingRect);
692 
693     RefPtr<Image> image = buffer->copyImage();
694     return DragImage::create(image.get(), DoNotRespectImageOrientation, deviceScaleFactor);
695 }
696 
devicePixelRatio() const697 double Frame::devicePixelRatio() const
698 {
699     if (!m_page)
700         return 0;
701 
702     double ratio = m_page->deviceScaleFactor();
703     if (RuntimeEnabledFeatures::devicePixelRatioIncludesZoomEnabled())
704         ratio *= pageZoomFactor();
705     return ratio;
706 }
707 
708 } // namespace WebCore
709