2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * Copyright (C) 2000 Dirk Mueller (mueller@kde.org)
4 * Copyright (C) 2004, 2006, 2009, 2010 Apple Inc. All rights reserved.
5 * Copyright (C) 2013 Google Inc. All rights reserved.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
25 #include "core/rendering/RenderWidget.h"
27 #include "core/accessibility/AXObjectCache.h"
28 #include "core/frame/LocalFrame.h"
29 #include "core/html/HTMLFrameOwnerElement.h"
30 #include "core/html/HTMLPlugInElement.h"
31 #include "core/paint/BoxPainter.h"
32 #include "core/rendering/GraphicsContextAnnotator.h"
33 #include "core/rendering/HitTestResult.h"
34 #include "core/rendering/RenderLayer.h"
35 #include "core/rendering/RenderView.h"
36 #include "core/rendering/compositing/CompositedLayerMapping.h"
37 #include "core/rendering/compositing/RenderLayerCompositor.h"
38 #include "wtf/HashMap.h"
42 RenderWidget::RenderWidget(Element* element)
43 : RenderReplaced(element)
45 // Reference counting is used to prevent the widget from being
46 // destroyed while inside the Widget code, which might not be
47 // able to handle that.
52 frameView()->addWidget(this);
55 void RenderWidget::willBeDestroyed()
57 frameView()->removeWidget(this);
59 if (AXObjectCache* cache = document().existingAXObjectCache()) {
60 cache->childrenChanged(this->parent());
64 Element* element = toElement(node());
65 if (element && element->isFrameOwnerElement())
66 toHTMLFrameOwnerElement(element)->setWidget(nullptr);
68 RenderReplaced::willBeDestroyed();
71 void RenderWidget::destroy()
73 #if ENABLE(ASSERT) && ENABLE(OILPAN)
74 ASSERT(!m_didCallDestroy);
75 m_didCallDestroy = true;
80 // In Oilpan, postDestroy doesn't delete |this|. So calling it here is safe
81 // though |this| will be referred in FrameView.
88 RenderWidget::~RenderWidget()
91 ASSERT(m_refCount <= 0);
95 Widget* RenderWidget::widget() const
97 // Plugin widgets are stored in their DOM node. This includes HTMLAppletElement.
98 Element* element = toElement(node());
100 if (element && element->isFrameOwnerElement())
101 return toHTMLFrameOwnerElement(element)->ownedWidget();
106 // Widgets are always placed on integer boundaries, so rounding the size is actually
107 // the desired behavior. This function is here because it's otherwise seldom what we
108 // want to do with a LayoutRect.
109 static inline IntRect roundedIntRect(const LayoutRect& rect)
111 return IntRect(roundedIntPoint(rect.location()), roundedIntSize(rect.size()));
114 bool RenderWidget::setWidgetGeometry(const LayoutRect& frame)
119 Widget* widget = this->widget();
122 IntRect newFrame = roundedIntRect(frame);
124 if (widget->frameRect() == newFrame)
127 RefPtrWillBeRawPtr<RenderWidget> protector(this);
128 RefPtrWillBeRawPtr<Node> protectedNode(node());
129 widget->setFrameRect(newFrame);
130 return widget->frameRect().size() != newFrame.size();
133 bool RenderWidget::updateWidgetGeometry()
135 Widget* widget = this->widget();
138 LayoutRect contentBox = contentBoxRect();
139 LayoutRect absoluteContentBox(localToAbsoluteQuad(FloatQuad(contentBox)).boundingBox());
140 if (widget->isFrameView()) {
141 contentBox.setLocation(absoluteContentBox.location());
142 return setWidgetGeometry(contentBox);
145 return setWidgetGeometry(absoluteContentBox);
148 void RenderWidget::layout()
150 ASSERT(needsLayout());
155 void RenderWidget::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
157 RenderReplaced::styleDidChange(diff, oldStyle);
158 Widget* widget = this->widget();
161 if (style()->visibility() != VISIBLE) {
169 void RenderWidget::paintContents(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
171 LayoutPoint adjustedPaintOffset = paintOffset + location();
173 Widget* widget = this->widget();
174 RELEASE_ASSERT(widget);
176 // Tell the widget to paint now. This is the only time the widget is allowed
177 // to paint itself. That way it will composite properly with z-indexed layers.
178 IntPoint widgetLocation = widget->frameRect().location();
179 IntPoint paintLocation(roundToInt(adjustedPaintOffset.x() + borderLeft() + paddingLeft()),
180 roundToInt(adjustedPaintOffset.y() + borderTop() + paddingTop()));
181 IntRect paintRect = paintInfo.rect;
183 IntSize widgetPaintOffset = paintLocation - widgetLocation;
184 // When painting widgets into compositing layers, tx and ty are relative to the enclosing compositing layer,
185 // not the root. In this case, shift the CTM and adjust the paintRect to be root-relative to fix plug-in drawing.
186 if (!widgetPaintOffset.isZero()) {
187 paintInfo.context->translate(widgetPaintOffset.width(), widgetPaintOffset.height());
188 paintRect.move(-widgetPaintOffset);
190 widget->paint(paintInfo.context, paintRect);
192 if (!widgetPaintOffset.isZero())
193 paintInfo.context->translate(-widgetPaintOffset.width(), -widgetPaintOffset.height());
196 void RenderWidget::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
198 ANNOTATE_GRAPHICS_CONTEXT(paintInfo, this);
200 if (!shouldPaint(paintInfo, paintOffset))
203 LayoutPoint adjustedPaintOffset = paintOffset + location();
205 if (hasBoxDecorationBackground() && (paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection))
206 paintBoxDecorationBackground(paintInfo, adjustedPaintOffset);
208 if (paintInfo.phase == PaintPhaseMask) {
209 paintMask(paintInfo, adjustedPaintOffset);
213 if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && style()->hasOutline())
214 paintOutline(paintInfo, LayoutRect(adjustedPaintOffset, size()));
216 if (paintInfo.phase != PaintPhaseForeground)
219 if (style()->hasBorderRadius()) {
220 LayoutRect borderRect = LayoutRect(adjustedPaintOffset, size());
222 if (borderRect.isEmpty())
225 // Push a clip if we have a border radius, since we want to round the foreground content that gets painted.
226 paintInfo.context->save();
227 RoundedRect roundedInnerRect = style()->getRoundedInnerBorderFor(borderRect,
228 paddingTop() + borderTop(), paddingBottom() + borderBottom(), paddingLeft() + borderLeft(), paddingRight() + borderRight(), true, true);
229 BoxPainter::clipRoundedInnerRect(paintInfo.context, borderRect, roundedInnerRect);
232 Widget* widget = this->widget();
234 paintContents(paintInfo, paintOffset);
236 if (style()->hasBorderRadius())
237 paintInfo.context->restore();
239 // Paint a partially transparent wash over selected widgets.
240 if (isSelected() && !document().printing()) {
241 LayoutRect rect = localSelectionRect();
242 rect.moveBy(adjustedPaintOffset);
243 paintInfo.context->fillRect(pixelSnappedIntRect(rect), selectionBackgroundColor());
247 layer()->scrollableArea()->paintResizer(paintInfo.context, roundedIntPoint(adjustedPaintOffset), paintInfo.rect);
251 void RenderWidget::deref()
253 if (--m_refCount <= 0)
258 void RenderWidget::updateOnWidgetChange()
260 Widget* widget = this->widget();
268 updateWidgetGeometry();
270 if (style()->visibility() != VISIBLE) {
274 // FIXME: Why do we issue a full paint invalidation in this case, but not the other?
275 setShouldDoFullPaintInvalidation(true);
279 void RenderWidget::updateWidgetPosition()
281 Widget* widget = this->widget();
282 if (!widget || !node()) // Check the node in case destroy() has been called.
285 bool boundsChanged = updateWidgetGeometry();
287 // if the frame bounds got changed, or if view needs layout (possibly indicating
288 // content size is wrong) we have to do a layout to set the right widget size
289 if (widget && widget->isFrameView()) {
290 FrameView* frameView = toFrameView(widget);
291 // Check the frame's page to make sure that the frame isn't in the process of being destroyed.
292 if ((boundsChanged || frameView->needsLayout()) && frameView->frame().page())
297 void RenderWidget::widgetPositionsUpdated()
299 Widget* widget = this->widget();
302 widget->widgetPositionsUpdated();
305 bool RenderWidget::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action)
307 bool hadResult = result.innerNode();
308 bool inside = RenderReplaced::nodeAtPoint(request, result, locationInContainer, accumulatedOffset, action);
310 // Check to see if we are really over the widget itself (and not just in the border/padding area).
311 if ((inside || result.isRectBasedTest()) && !hadResult && result.innerNode() == node())
312 result.setIsOverWidget(contentBoxRect().contains(result.localPoint()));
316 CursorDirective RenderWidget::getCursor(const LayoutPoint& point, Cursor& cursor) const
318 if (widget() && widget()->isPluginView()) {
319 // A plug-in is responsible for setting the cursor when the pointer is over it.
320 return DoNotSetCursor;
322 return RenderReplaced::getCursor(point, cursor);