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