Upstream version 5.34.92.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/Frame.h"
29 #include "core/rendering/CompositedLayerMapping.h"
30 #include "core/rendering/GraphicsContextAnnotator.h"
31 #include "core/rendering/HitTestResult.h"
32 #include "core/rendering/LayoutRectRecorder.h"
33 #include "core/rendering/RenderLayer.h"
34 #include "core/rendering/RenderView.h"
35 #include "wtf/HashMap.h"
36
37 namespace WebCore {
38
39 typedef HashMap<RefPtr<Widget>, FrameView*> WidgetToParentMap;
40 static WidgetToParentMap& widgetNewParentMap()
41 {
42     DEFINE_STATIC_LOCAL(WidgetToParentMap, map, ());
43     return map;
44 }
45
46 static unsigned s_updateSuspendCount = 0;
47
48 RenderWidget::UpdateSuspendScope::UpdateSuspendScope()
49 {
50     ++s_updateSuspendCount;
51 }
52
53 RenderWidget::UpdateSuspendScope::~UpdateSuspendScope()
54 {
55     ASSERT(s_updateSuspendCount > 0);
56     if (s_updateSuspendCount == 1) {
57         WidgetToParentMap map;
58         widgetNewParentMap().swap(map);
59         WidgetToParentMap::iterator end = map.end();
60         for (WidgetToParentMap::iterator it = map.begin(); it != end; ++it) {
61             Widget* child = it->key.get();
62             ScrollView* currentParent = toScrollView(child->parent());
63             FrameView* newParent = it->value;
64             if (newParent != currentParent) {
65                 if (currentParent)
66                     currentParent->removeChild(child);
67                 if (newParent)
68                     newParent->addChild(child);
69             }
70         }
71     }
72     --s_updateSuspendCount;
73 }
74
75 static void moveWidgetToParentSoon(Widget* child, FrameView* parent)
76 {
77     if (!s_updateSuspendCount) {
78         if (parent)
79             parent->addChild(child);
80         else
81             toScrollView(child->parent())->removeChild(child);
82         return;
83     }
84     widgetNewParentMap().set(child, parent);
85 }
86
87 RenderWidget::RenderWidget(Element* element)
88     : RenderReplaced(element)
89     , m_widget(0)
90     // Reference counting is used to prevent the widget from being
91     // destroyed while inside the Widget code, which might not be
92     // able to handle that.
93     , m_refCount(1)
94 {
95     ASSERT(element);
96     frameView()->addWidget(this);
97 }
98
99 void RenderWidget::willBeDestroyed()
100 {
101     frameView()->removeWidget(this);
102
103     if (AXObjectCache* cache = document().existingAXObjectCache()) {
104         cache->childrenChanged(this->parent());
105         cache->remove(this);
106     }
107
108     setWidget(0);
109
110     RenderReplaced::willBeDestroyed();
111 }
112
113 void RenderWidget::destroy()
114 {
115     willBeDestroyed();
116     clearNode();
117     deref();
118 }
119
120 RenderWidget::~RenderWidget()
121 {
122     ASSERT(m_refCount <= 0);
123     clearWidget();
124 }
125
126 // Widgets are always placed on integer boundaries, so rounding the size is actually
127 // the desired behavior. This function is here because it's otherwise seldom what we
128 // want to do with a LayoutRect.
129 static inline IntRect roundedIntRect(const LayoutRect& rect)
130 {
131     return IntRect(roundedIntPoint(rect.location()), roundedIntSize(rect.size()));
132 }
133
134 bool RenderWidget::setWidgetGeometry(const LayoutRect& frame)
135 {
136     if (!node())
137         return false;
138
139     IntRect clipRect = roundedIntRect(enclosingLayer()->clipper().childrenClipRect());
140     IntRect newFrame = roundedIntRect(frame);
141     bool clipChanged = m_clipRect != clipRect;
142     bool frameRectChanged = m_widget->frameRect() != newFrame;
143
144     if (!frameRectChanged && !clipChanged)
145         return false;
146
147     m_clipRect = clipRect;
148
149     RefPtr<RenderWidget> protector(this);
150     RefPtr<Node> protectedNode(node());
151     m_widget->setFrameRect(newFrame);
152
153     if (clipChanged && !frameRectChanged)
154         m_widget->clipRectChanged();
155
156     if (hasLayer() && layer()->compositingState() == PaintsIntoOwnBacking)
157         layer()->compositedLayerMapping()->updateAfterWidgetResize();
158
159     bool boundsChanged = m_widget->frameRect().size() != newFrame.size();
160     return boundsChanged;
161 }
162
163 bool RenderWidget::updateWidgetGeometry()
164 {
165     LayoutRect contentBox = contentBoxRect();
166     LayoutRect absoluteContentBox(localToAbsoluteQuad(FloatQuad(contentBox)).boundingBox());
167     if (m_widget->isFrameView()) {
168         contentBox.setLocation(absoluteContentBox.location());
169         return setWidgetGeometry(contentBox);
170     }
171
172     return setWidgetGeometry(absoluteContentBox);
173 }
174
175 void RenderWidget::setWidget(PassRefPtr<Widget> widget)
176 {
177     if (widget == m_widget)
178         return;
179
180     if (m_widget) {
181         moveWidgetToParentSoon(m_widget.get(), 0);
182         clearWidget();
183     }
184     m_widget = widget;
185     if (m_widget) {
186         // If we've already received a layout, apply the calculated space to the
187         // widget immediately, but we have to have really been fully constructed (with a non-null
188         // style pointer).
189         if (style()) {
190             if (!needsLayout())
191                 updateWidgetGeometry();
192
193             if (style()->visibility() != VISIBLE)
194                 m_widget->hide();
195             else {
196                 m_widget->show();
197                 repaint();
198             }
199         }
200         moveWidgetToParentSoon(m_widget.get(), frameView());
201     }
202
203     if (AXObjectCache* cache = document().existingAXObjectCache())
204         cache->childrenChanged(this);
205 }
206
207 void RenderWidget::layout()
208 {
209     ASSERT(needsLayout());
210
211     LayoutRectRecorder recorder(*this);
212     clearNeedsLayout();
213 }
214
215 void RenderWidget::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
216 {
217     RenderReplaced::styleDidChange(diff, oldStyle);
218     if (m_widget) {
219         if (style()->visibility() != VISIBLE)
220             m_widget->hide();
221         else
222             m_widget->show();
223     }
224 }
225
226 void RenderWidget::paintContents(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
227 {
228     LayoutPoint adjustedPaintOffset = paintOffset + location();
229
230     // Tell the widget to paint now. This is the only time the widget is allowed
231     // to paint itself. That way it will composite properly with z-indexed layers.
232     IntPoint widgetLocation = m_widget->frameRect().location();
233     IntPoint paintLocation(roundToInt(adjustedPaintOffset.x() + borderLeft() + paddingLeft()),
234         roundToInt(adjustedPaintOffset.y() + borderTop() + paddingTop()));
235     IntRect paintRect = paintInfo.rect;
236
237     IntSize widgetPaintOffset = paintLocation - widgetLocation;
238     // When painting widgets into compositing layers, tx and ty are relative to the enclosing compositing layer,
239     // not the root. In this case, shift the CTM and adjust the paintRect to be root-relative to fix plug-in drawing.
240     if (!widgetPaintOffset.isZero()) {
241         paintInfo.context->translate(widgetPaintOffset);
242         paintRect.move(-widgetPaintOffset);
243     }
244     m_widget->paint(paintInfo.context, paintRect);
245
246     if (!widgetPaintOffset.isZero())
247         paintInfo.context->translate(-widgetPaintOffset);
248
249     if (m_widget->isFrameView()) {
250         FrameView* frameView = toFrameView(m_widget.get());
251         bool runOverlapTests = !frameView->useSlowRepaintsIfNotOverlapped() || frameView->hasCompositedContent();
252         if (paintInfo.overlapTestRequests && runOverlapTests) {
253             ASSERT(!paintInfo.overlapTestRequests->contains(this));
254             paintInfo.overlapTestRequests->set(this, m_widget->frameRect());
255         }
256     }
257 }
258
259 void RenderWidget::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
260 {
261     ANNOTATE_GRAPHICS_CONTEXT(paintInfo, this);
262
263     if (!shouldPaint(paintInfo, paintOffset))
264         return;
265
266     LayoutPoint adjustedPaintOffset = paintOffset + location();
267
268     if (hasBoxDecorations() && (paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection))
269         paintBoxDecorations(paintInfo, adjustedPaintOffset);
270
271     if (paintInfo.phase == PaintPhaseMask) {
272         paintMask(paintInfo, adjustedPaintOffset);
273         return;
274     }
275
276     if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && hasOutline())
277         paintOutline(paintInfo, LayoutRect(adjustedPaintOffset, size()));
278
279     if (paintInfo.phase != PaintPhaseForeground)
280         return;
281
282     if (style()->hasBorderRadius()) {
283         LayoutRect borderRect = LayoutRect(adjustedPaintOffset, size());
284
285         if (borderRect.isEmpty())
286             return;
287
288         // Push a clip if we have a border radius, since we want to round the foreground content that gets painted.
289         paintInfo.context->save();
290         RoundedRect roundedInnerRect = style()->getRoundedInnerBorderFor(borderRect,
291             paddingTop() + borderTop(), paddingBottom() + borderBottom(), paddingLeft() + borderLeft(), paddingRight() + borderRight(), true, true);
292         clipRoundedInnerRect(paintInfo.context, borderRect, roundedInnerRect);
293     }
294
295     if (m_widget)
296         paintContents(paintInfo, paintOffset);
297
298     if (style()->hasBorderRadius())
299         paintInfo.context->restore();
300
301     // Paint a partially transparent wash over selected widgets.
302     if (isSelected() && !document().printing()) {
303         // FIXME: selectionRect() is in absolute, not painting coordinates.
304         paintInfo.context->fillRect(pixelSnappedIntRect(selectionRect()), selectionBackgroundColor());
305     }
306
307     if (canResize())
308         layer()->scrollableArea()->paintResizer(paintInfo.context, roundedIntPoint(adjustedPaintOffset), paintInfo.rect);
309 }
310
311 void RenderWidget::setIsOverlapped(bool isOverlapped)
312 {
313     ASSERT(m_widget);
314     ASSERT(m_widget->isFrameView());
315     toFrameView(m_widget.get())->setIsOverlapped(isOverlapped);
316 }
317
318 void RenderWidget::deref()
319 {
320     if (--m_refCount <= 0)
321         postDestroy();
322 }
323
324 void RenderWidget::updateWidgetPosition()
325 {
326     if (!m_widget || !node()) // Check the node in case destroy() has been called.
327         return;
328
329     bool boundsChanged = updateWidgetGeometry();
330
331     // if the frame bounds got changed, or if view needs layout (possibly indicating
332     // content size is wrong) we have to do a layout to set the right widget size
333     if (m_widget && m_widget->isFrameView()) {
334         FrameView* frameView = toFrameView(m_widget.get());
335         // Check the frame's page to make sure that the frame isn't in the process of being destroyed.
336         if ((boundsChanged || frameView->needsLayout()) && frameView->frame().page())
337             frameView->layout();
338     }
339 }
340
341 void RenderWidget::widgetPositionsUpdated()
342 {
343     if (!m_widget)
344         return;
345     m_widget->widgetPositionsUpdated();
346 }
347
348 void RenderWidget::clearWidget()
349 {
350     m_widget = 0;
351 }
352
353 bool RenderWidget::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action)
354 {
355     bool hadResult = result.innerNode();
356     bool inside = RenderReplaced::nodeAtPoint(request, result, locationInContainer, accumulatedOffset, action);
357
358     // Check to see if we are really over the widget itself (and not just in the border/padding area).
359     if ((inside || result.isRectBasedTest()) && !hadResult && result.innerNode() == node())
360         result.setIsOverWidget(contentBoxRect().contains(result.localPoint()));
361     return inside;
362 }
363
364 CursorDirective RenderWidget::getCursor(const LayoutPoint& point, Cursor& cursor) const
365 {
366     if (widget() && widget()->isPluginView()) {
367         // A plug-in is responsible for setting the cursor when the pointer is over it.
368         return DoNotSetCursor;
369     }
370     return RenderReplaced::getCursor(point, cursor);
371 }
372
373 } // namespace WebCore