Upstream version 11.39.266.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / rendering / RenderWidget.cpp
1 /*
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.
6  *
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.
11  *
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.
16  *
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.
21  *
22  */
23
24 #include "config.h"
25 #include "core/rendering/RenderWidget.h"
26
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"
39
40 namespace blink {
41
42 RenderWidget::RenderWidget(Element* element)
43     : RenderReplaced(element)
44 #if !ENABLE(OILPAN)
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.
48     , m_refCount(1)
49 #endif
50 {
51     ASSERT(element);
52     frameView()->addWidget(this);
53 }
54
55 void RenderWidget::willBeDestroyed()
56 {
57     frameView()->removeWidget(this);
58
59     if (AXObjectCache* cache = document().existingAXObjectCache()) {
60         cache->childrenChanged(this->parent());
61         cache->remove(this);
62     }
63
64     Element* element = toElement(node());
65     if (element && element->isFrameOwnerElement())
66         toHTMLFrameOwnerElement(element)->setWidget(nullptr);
67
68     RenderReplaced::willBeDestroyed();
69 }
70
71 void RenderWidget::destroy()
72 {
73 #if ENABLE(ASSERT) && ENABLE(OILPAN)
74     ASSERT(!m_didCallDestroy);
75     m_didCallDestroy = true;
76 #endif
77     willBeDestroyed();
78     clearNode();
79 #if ENABLE(OILPAN)
80     // In Oilpan, postDestroy doesn't delete |this|. So calling it here is safe
81     // though |this| will be referred in FrameView.
82     postDestroy();
83 #else
84     deref();
85 #endif
86 }
87
88 RenderWidget::~RenderWidget()
89 {
90 #if !ENABLE(OILPAN)
91     ASSERT(m_refCount <= 0);
92 #endif
93 }
94
95 Widget* RenderWidget::widget() const
96 {
97     // Plugin widgets are stored in their DOM node. This includes HTMLAppletElement.
98     Element* element = toElement(node());
99
100     if (element && element->isFrameOwnerElement())
101         return toHTMLFrameOwnerElement(element)->ownedWidget();
102
103     return 0;
104 }
105
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)
110 {
111     return IntRect(roundedIntPoint(rect.location()), roundedIntSize(rect.size()));
112 }
113
114 bool RenderWidget::setWidgetGeometry(const LayoutRect& frame)
115 {
116     if (!node())
117         return false;
118
119     Widget* widget = this->widget();
120     ASSERT(widget);
121
122     IntRect newFrame = roundedIntRect(frame);
123
124     if (widget->frameRect() == newFrame)
125         return false;
126
127     RefPtrWillBeRawPtr<RenderWidget> protector(this);
128     RefPtrWillBeRawPtr<Node> protectedNode(node());
129     widget->setFrameRect(newFrame);
130     return widget->frameRect().size() != newFrame.size();
131 }
132
133 bool RenderWidget::updateWidgetGeometry()
134 {
135     Widget* widget = this->widget();
136     ASSERT(widget);
137
138     LayoutRect contentBox = contentBoxRect();
139     LayoutRect absoluteContentBox(localToAbsoluteQuad(FloatQuad(contentBox)).boundingBox());
140     if (widget->isFrameView()) {
141         contentBox.setLocation(absoluteContentBox.location());
142         return setWidgetGeometry(contentBox);
143     }
144
145     return setWidgetGeometry(absoluteContentBox);
146 }
147
148 void RenderWidget::layout()
149 {
150     ASSERT(needsLayout());
151
152     clearNeedsLayout();
153 }
154
155 void RenderWidget::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
156 {
157     RenderReplaced::styleDidChange(diff, oldStyle);
158     Widget* widget = this->widget();
159
160     if (widget) {
161         if (style()->visibility() != VISIBLE) {
162             widget->hide();
163         } else {
164             widget->show();
165         }
166     }
167 }
168
169 void RenderWidget::paintContents(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
170 {
171     LayoutPoint adjustedPaintOffset = paintOffset + location();
172
173     Widget* widget = this->widget();
174     RELEASE_ASSERT(widget);
175
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;
182
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);
189     }
190     widget->paint(paintInfo.context, paintRect);
191
192     if (!widgetPaintOffset.isZero())
193         paintInfo.context->translate(-widgetPaintOffset.width(), -widgetPaintOffset.height());
194 }
195
196 void RenderWidget::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
197 {
198     ANNOTATE_GRAPHICS_CONTEXT(paintInfo, this);
199
200     if (!shouldPaint(paintInfo, paintOffset))
201         return;
202
203     LayoutPoint adjustedPaintOffset = paintOffset + location();
204
205     if (hasBoxDecorationBackground() && (paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection))
206         paintBoxDecorationBackground(paintInfo, adjustedPaintOffset);
207
208     if (paintInfo.phase == PaintPhaseMask) {
209         paintMask(paintInfo, adjustedPaintOffset);
210         return;
211     }
212
213     if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && style()->hasOutline())
214         paintOutline(paintInfo, LayoutRect(adjustedPaintOffset, size()));
215
216     if (paintInfo.phase != PaintPhaseForeground)
217         return;
218
219     if (style()->hasBorderRadius()) {
220         LayoutRect borderRect = LayoutRect(adjustedPaintOffset, size());
221
222         if (borderRect.isEmpty())
223             return;
224
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);
230     }
231
232     Widget* widget = this->widget();
233     if (widget)
234         paintContents(paintInfo, paintOffset);
235
236     if (style()->hasBorderRadius())
237         paintInfo.context->restore();
238
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());
244     }
245
246     if (canResize())
247         layer()->scrollableArea()->paintResizer(paintInfo.context, roundedIntPoint(adjustedPaintOffset), paintInfo.rect);
248 }
249
250 #if !ENABLE(OILPAN)
251 void RenderWidget::deref()
252 {
253     if (--m_refCount <= 0)
254         postDestroy();
255 }
256 #endif
257
258 void RenderWidget::updateOnWidgetChange()
259 {
260     Widget* widget = this->widget();
261     if (!widget)
262         return;
263
264     if (!style())
265         return;
266
267     if (!needsLayout())
268         updateWidgetGeometry();
269
270     if (style()->visibility() != VISIBLE) {
271         widget->hide();
272     } else {
273         widget->show();
274         // FIXME: Why do we issue a full paint invalidation in this case, but not the other?
275         setShouldDoFullPaintInvalidation(true);
276     }
277 }
278
279 void RenderWidget::updateWidgetPosition()
280 {
281     Widget* widget = this->widget();
282     if (!widget || !node()) // Check the node in case destroy() has been called.
283         return;
284
285     bool boundsChanged = updateWidgetGeometry();
286
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())
293             frameView->layout();
294     }
295 }
296
297 void RenderWidget::widgetPositionsUpdated()
298 {
299     Widget* widget = this->widget();
300     if (!widget)
301         return;
302     widget->widgetPositionsUpdated();
303 }
304
305 bool RenderWidget::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action)
306 {
307     bool hadResult = result.innerNode();
308     bool inside = RenderReplaced::nodeAtPoint(request, result, locationInContainer, accumulatedOffset, action);
309
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()));
313     return inside;
314 }
315
316 CursorDirective RenderWidget::getCursor(const LayoutPoint& point, Cursor& cursor) const
317 {
318     if (widget() && widget()->isPluginView()) {
319         // A plug-in is responsible for setting the cursor when the pointer is over it.
320         return DoNotSetCursor;
321     }
322     return RenderReplaced::getCursor(point, cursor);
323 }
324
325 } // namespace blink