• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 Apple Inc. All rights reserved.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public License
17  * along with this library; see the file COPYING.LIB.  If not, write to
18  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "config.h"
24 #include "RenderWidget.h"
25 
26 #include "AnimationController.h"
27 #include "AXObjectCache.h"
28 #include "GraphicsContext.h"
29 #include "HitTestResult.h"
30 #include "RenderView.h"
31 
32 using namespace std;
33 
34 namespace WebCore {
35 
widgetRendererMap()36 static HashMap<const Widget*, RenderWidget*>& widgetRendererMap()
37 {
38     static HashMap<const Widget*, RenderWidget*>* staticWidgetRendererMap = new HashMap<const Widget*, RenderWidget*>;
39     return *staticWidgetRendererMap;
40 }
41 
RenderWidget(Node * node)42 RenderWidget::RenderWidget(Node* node)
43     : RenderReplaced(node)
44     , m_widget(0)
45     , m_frameView(node->document()->view())
46     , m_refCount(0)
47 {
48     view()->addWidget(this);
49 
50     // Reference counting is used to prevent the widget from being
51     // destroyed while inside the Widget code, which might not be
52     // able to handle that.
53     ref();
54 }
55 
destroy()56 void RenderWidget::destroy()
57 {
58     // We can't call the base class's destroy because we don't
59     // want to unconditionally delete ourselves (we're ref-counted).
60     // So the code below includes copied and pasted contents of
61     // both RenderBox::destroy() and RenderObject::destroy().
62     // Fix originally made for <rdar://problem/4228818>.
63     animation()->cancelAnimations(this);
64 
65     if (RenderView* v = view())
66         v->removeWidget(this);
67 
68     if (AXObjectCache::accessibilityEnabled()) {
69         document()->axObjectCache()->childrenChanged(this->parent());
70         document()->axObjectCache()->remove(this);
71     }
72     remove();
73 
74     if (m_widget) {
75         if (m_frameView)
76             m_frameView->removeChild(m_widget.get());
77         widgetRendererMap().remove(m_widget.get());
78     }
79 
80     // removes from override size map
81     if (hasOverrideSize())
82         setOverrideSize(-1);
83 
84     if (style() && (style()->height().isPercent() || style()->minHeight().isPercent() || style()->maxHeight().isPercent()))
85         RenderBlock::removePercentHeightDescendant(this);
86 
87     if (hasLayer()) {
88         layer()->clearClipRects();
89         setHasLayer(false);
90         destroyLayer();
91     }
92 
93     // Grab the arena from node()->document()->renderArena() before clearing the node pointer.
94     // Clear the node before deref-ing, as this may be deleted when deref is called.
95     RenderArena* arena = renderArena();
96     setNode(0);
97     deref(arena);
98 }
99 
~RenderWidget()100 RenderWidget::~RenderWidget()
101 {
102     ASSERT(m_refCount <= 0);
103     clearWidget();
104 }
105 
setWidgetGeometry(const IntRect & frame)106 void RenderWidget::setWidgetGeometry(const IntRect& frame)
107 {
108     if (node() && m_widget->frameRect() != frame) {
109         RenderArena* arena = ref();
110         RefPtr<Node> protectedElement(node());
111         m_widget->setFrameRect(frame);
112         deref(arena);
113     }
114 }
115 
setWidget(PassRefPtr<Widget> widget)116 void RenderWidget::setWidget(PassRefPtr<Widget> widget)
117 {
118     if (widget != m_widget) {
119         if (m_widget) {
120             m_widget->removeFromParent();
121             widgetRendererMap().remove(m_widget.get());
122             clearWidget();
123         }
124         m_widget = widget;
125         if (m_widget) {
126             widgetRendererMap().add(m_widget.get(), this);
127             // if we've already received a layout, apply the calculated space to the
128             // widget immediately, but we have to have really been full constructed (with a non-null
129             // style pointer).
130             if (style()) {
131                 if (!needsLayout())
132                     setWidgetGeometry(absoluteContentBox());
133                 if (style()->visibility() != VISIBLE)
134                     m_widget->hide();
135                 else
136                     m_widget->show();
137             }
138             m_frameView->addChild(m_widget.get());
139         }
140     }
141 }
142 
layout()143 void RenderWidget::layout()
144 {
145     ASSERT(needsLayout());
146 
147     setNeedsLayout(false);
148 }
149 
styleDidChange(StyleDifference diff,const RenderStyle * oldStyle)150 void RenderWidget::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
151 {
152     RenderReplaced::styleDidChange(diff, oldStyle);
153     if (m_widget) {
154         if (style()->visibility() != VISIBLE)
155             m_widget->hide();
156         else
157             m_widget->show();
158     }
159 }
160 
paint(PaintInfo & paintInfo,int tx,int ty)161 void RenderWidget::paint(PaintInfo& paintInfo, int tx, int ty)
162 {
163     if (!shouldPaint(paintInfo, tx, ty))
164         return;
165 
166     tx += x();
167     ty += y();
168 
169     if (hasBoxDecorations() && (paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection))
170         paintBoxDecorations(paintInfo, tx, ty);
171 
172     if (paintInfo.phase == PaintPhaseMask) {
173         paintMask(paintInfo, tx, ty);
174         return;
175     }
176 
177     if (!m_frameView || paintInfo.phase != PaintPhaseForeground || style()->visibility() != VISIBLE)
178         return;
179 
180 #if PLATFORM(MAC)
181     if (style()->highlight() != nullAtom && !paintInfo.context->paintingDisabled())
182         paintCustomHighlight(tx - x(), ty - y(), style()->highlight(), true);
183 #endif
184 
185     if (style()->hasBorderRadius()) {
186         // Push a clip if we have a border radius, since we want to round the foreground content that gets painted.
187         paintInfo.context->save();
188 
189         IntSize topLeft, topRight, bottomLeft, bottomRight;
190         IntRect borderRect = IntRect(tx, ty, width(), height());
191         style()->getBorderRadiiForRect(borderRect, topLeft, topRight, bottomLeft, bottomRight);
192 
193         paintInfo.context->addRoundedRectClip(borderRect, topLeft, topRight, bottomLeft, bottomRight);
194     }
195 
196     if (m_widget) {
197         // Move the widget if necessary.  We normally move and resize widgets during layout, but sometimes
198         // widgets can move without layout occurring (most notably when you scroll a document that
199         // contains fixed positioned elements).
200         m_widget->move(tx + borderLeft() + paddingLeft(), ty + borderTop() + paddingTop());
201 
202         // Tell the widget to paint now.  This is the only time the widget is allowed
203         // to paint itself.  That way it will composite properly with z-indexed layers.
204         m_widget->paint(paintInfo.context, paintInfo.rect);
205 
206         if (m_widget->isFrameView() && paintInfo.overlapTestRequests && !static_cast<FrameView*>(m_widget.get())->useSlowRepaints()) {
207             ASSERT(!paintInfo.overlapTestRequests->contains(this));
208             paintInfo.overlapTestRequests->set(this, m_widget->frameRect());
209         }
210     }
211 
212     if (style()->hasBorderRadius())
213         paintInfo.context->restore();
214 
215     // Paint a partially transparent wash over selected widgets.
216     if (isSelected() && !document()->printing()) {
217         // FIXME: selectionRect() is in absolute, not painting coordinates.
218         paintInfo.context->fillRect(selectionRect(), selectionBackgroundColor());
219     }
220 }
221 
setOverlapTestResult(bool isOverlapped)222 void RenderWidget::setOverlapTestResult(bool isOverlapped)
223 {
224     ASSERT(m_widget);
225     ASSERT(m_widget->isFrameView());
226     static_cast<FrameView*>(m_widget.get())->setIsOverlapped(isOverlapped);
227 }
228 
deref(RenderArena * arena)229 void RenderWidget::deref(RenderArena *arena)
230 {
231     if (--m_refCount <= 0)
232         arenaDelete(arena, this);
233 }
234 
updateWidgetPosition()235 void RenderWidget::updateWidgetPosition()
236 {
237     if (!m_widget)
238         return;
239 
240     // FIXME: This doesn't work correctly with transforms.
241     FloatPoint absPos = localToAbsolute();
242     absPos.move(borderLeft() + paddingLeft(), borderTop() + paddingTop());
243 
244     int w = width() - borderLeft() - borderRight() - paddingLeft() - paddingRight();
245     int h = height() - borderTop() - borderBottom() - paddingTop() - paddingBottom();
246 
247     IntRect newBounds(absPos.x(), absPos.y(), w, h);
248     IntRect oldBounds(m_widget->frameRect());
249     bool boundsChanged = newBounds != oldBounds;
250     if (boundsChanged) {
251         RenderArena* arena = ref();
252         node()->ref();
253         m_widget->setFrameRect(newBounds);
254         node()->deref();
255         deref(arena);
256     }
257 
258 #ifndef FLATTEN_IFRAME
259     // if the frame bounds got changed, or if view needs layout (possibly indicating
260     // content size is wrong) we have to do a layout to set the right widget size
261     if (m_widget->isFrameView()) {
262         FrameView* frameView = static_cast<FrameView*>(m_widget.get());
263         if (boundsChanged || frameView->needsLayout())
264             frameView->layout();
265     }
266 #endif
267 }
268 
setSelectionState(SelectionState state)269 void RenderWidget::setSelectionState(SelectionState state)
270 {
271     if (selectionState() != state) {
272         RenderReplaced::setSelectionState(state);
273         if (m_widget)
274             m_widget->setIsSelected(isSelected());
275     }
276 }
277 
clearWidget()278 void RenderWidget::clearWidget()
279 {
280     m_widget = 0;
281 }
282 
find(const Widget * widget)283 RenderWidget* RenderWidget::find(const Widget* widget)
284 {
285     return widgetRendererMap().get(widget);
286 }
287 
nodeAtPoint(const HitTestRequest & request,HitTestResult & result,int x,int y,int tx,int ty,HitTestAction action)288 bool RenderWidget::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestAction action)
289 {
290     bool hadResult = result.innerNode();
291     bool inside = RenderReplaced::nodeAtPoint(request, result, x, y, tx, ty, action);
292 
293     // Check to see if we are really over the widget itself (and not just in the border/padding area).
294     if (inside && !hadResult && result.innerNode() == node())
295         result.setIsOverWidget(contentBoxRect().contains(result.localPoint()));
296     return inside;
297 }
298 
299 } // namespace WebCore
300