OLD | NEW |
| (Empty) |
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 HTMLAppletElem
ent. | |
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 actu
ally | |
107 // the desired behavior. This function is here because it's otherwise seldom wha
t 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)).bou
ndingBox()); | |
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* oldSt
yle) | |
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& paintO
ffset) | |
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 layer
s. | |
178 IntPoint widgetLocation = widget->frameRect().location(); | |
179 IntPoint paintLocation(roundToInt(adjustedPaintOffset.x() + borderLeft() + p
addingLeft()), | |
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(), widgetPaintOffse
t.height()); | |
188 paintRect.move(-widgetPaintOffset); | |
189 } | |
190 widget->paint(paintInfo.context, paintRect); | |
191 | |
192 if (!widgetPaintOffset.isZero()) | |
193 paintInfo.context->translate(-widgetPaintOffset.width(), -widgetPaintOff
set.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 == PaintPhaseSe
lfOutline) && 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 fo
reground content that gets painted. | |
226 paintInfo.context->save(); | |
227 RoundedRect roundedInnerRect = style()->getRoundedInnerBorderFor(borderR
ect, | |
228 paddingTop() + borderTop(), paddingBottom() + borderBottom(), paddin
gLeft() + borderLeft(), paddingRight() + borderRight(), true, true); | |
229 BoxPainter::clipRoundedInnerRect(paintInfo.context, borderRect, roundedI
nnerRect); | |
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), selectionBackgrou
ndColor()); | |
244 } | |
245 | |
246 if (canResize()) | |
247 layer()->scrollableArea()->paintResizer(paintInfo.context, roundedIntPoi
nt(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 no
t 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 indica
ting | |
288 // content size is wrong) we have to do a layout to set the right widget siz
e | |
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 proce
ss of being destroyed. | |
292 if ((boundsChanged || frameView->needsLayout()) && frameView->frame().pa
ge()) | |
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& res
ult, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedO
ffset, HitTestAction action) | |
306 { | |
307 bool hadResult = result.innerNode(); | |
308 bool inside = RenderReplaced::nodeAtPoint(request, result, locationInContain
er, 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 o
ver it. | |
320 return DoNotSetCursor; | |
321 } | |
322 return RenderReplaced::getCursor(point, cursor); | |
323 } | |
324 | |
325 } // namespace blink | |
OLD | NEW |