OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) | 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) |
3 * (C) 2000 Simon Hausmann <hausmann@kde.org> | 3 * (C) 2000 Simon Hausmann <hausmann@kde.org> |
4 * (C) 2000 Stefan Schimanski (1Stein@gmx.de) | 4 * (C) 2000 Stefan Schimanski (1Stein@gmx.de) |
5 * Copyright (C) 2004, 2005, 2006, 2009 Apple Inc. All rights reserved. | 5 * Copyright (C) 2004, 2005, 2006, 2009 Apple Inc. All rights reserved. |
6 * Copyright (C) Research In Motion Limited 2011. All rights reserved. | 6 * Copyright (C) Research In Motion Limited 2011. All rights reserved. |
7 * | 7 * |
8 * This library is free software; you can redistribute it and/or | 8 * This library is free software; you can redistribute it and/or |
9 * modify it under the terms of the GNU Library General Public | 9 * modify it under the terms of the GNU Library General Public |
10 * License as published by the Free Software Foundation; either | 10 * License as published by the Free Software Foundation; either |
11 * version 2 of the License, or (at your option) any later version. | 11 * version 2 of the License, or (at your option) any later version. |
12 * | 12 * |
13 * This library is distributed in the hope that it will be useful, | 13 * This library is distributed in the hope that it will be useful, |
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
16 * Library General Public License for more details. | 16 * Library General Public License for more details. |
17 * | 17 * |
18 * You should have received a copy of the GNU Library General Public License | 18 * You should have received a copy of the GNU Library General Public License |
19 * along with this library; see the file COPYING.LIB. If not, write to | 19 * along with this library; see the file COPYING.LIB. If not, write to |
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | 20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
21 * Boston, MA 02110-1301, USA. | 21 * Boston, MA 02110-1301, USA. |
22 * | 22 * |
23 */ | 23 */ |
24 | 24 |
25 #include "config.h" | 25 #include "config.h" |
26 #include "core/rendering/RenderPart.h" | 26 #include "core/rendering/RenderPart.h" |
27 | 27 |
| 28 #include "core/accessibility/AXObjectCache.h" |
28 #include "core/frame/FrameView.h" | 29 #include "core/frame/FrameView.h" |
29 #include "core/frame/LocalFrame.h" | 30 #include "core/frame/LocalFrame.h" |
30 #include "core/html/HTMLFrameElementBase.h" | 31 #include "core/html/HTMLFrameElementBase.h" |
| 32 #include "core/paint/BoxPainter.h" |
31 #include "core/plugins/PluginView.h" | 33 #include "core/plugins/PluginView.h" |
| 34 #include "core/rendering/GraphicsContextAnnotator.h" |
32 #include "core/rendering/HitTestResult.h" | 35 #include "core/rendering/HitTestResult.h" |
33 #include "core/rendering/RenderLayer.h" | 36 #include "core/rendering/RenderLayer.h" |
34 #include "core/rendering/RenderView.h" | 37 #include "core/rendering/RenderView.h" |
35 #include "core/rendering/svg/RenderSVGRoot.h" | 38 #include "core/rendering/svg/RenderSVGRoot.h" |
36 | 39 |
37 namespace blink { | 40 namespace blink { |
38 | 41 |
39 RenderPart::RenderPart(Element* node) | 42 RenderPart::RenderPart(Element* element) |
40 : RenderWidget(node) | 43 : RenderReplaced(element) |
| 44 #if !ENABLE(OILPAN) |
| 45 // Reference counting is used to prevent the part from being destroyed |
| 46 // while inside the Widget code, which might not be able to handle that. |
| 47 , m_refCount(1) |
| 48 #endif |
41 { | 49 { |
| 50 ASSERT(element); |
| 51 frameView()->addPart(this); |
42 setInline(false); | 52 setInline(false); |
43 } | 53 } |
44 | 54 |
| 55 #if !ENABLE(OILPAN) |
| 56 void RenderPart::deref() |
| 57 { |
| 58 if (--m_refCount <= 0) |
| 59 postDestroy(); |
| 60 } |
| 61 #endif |
| 62 |
| 63 void RenderPart::willBeDestroyed() |
| 64 { |
| 65 frameView()->removePart(this); |
| 66 |
| 67 if (AXObjectCache* cache = document().existingAXObjectCache()) { |
| 68 cache->childrenChanged(this->parent()); |
| 69 cache->remove(this); |
| 70 } |
| 71 |
| 72 Element* element = toElement(node()); |
| 73 if (element && element->isFrameOwnerElement()) |
| 74 toHTMLFrameOwnerElement(element)->setWidget(nullptr); |
| 75 |
| 76 RenderReplaced::willBeDestroyed(); |
| 77 } |
| 78 |
| 79 void RenderPart::destroy() |
| 80 { |
| 81 #if ENABLE(ASSERT) && ENABLE(OILPAN) |
| 82 ASSERT(!m_didCallDestroy); |
| 83 m_didCallDestroy = true; |
| 84 #endif |
| 85 willBeDestroyed(); |
| 86 clearNode(); |
| 87 #if ENABLE(OILPAN) |
| 88 // In Oilpan, postDestroy doesn't delete |this|. So calling it here is safe |
| 89 // though |this| will be referred in FrameView. |
| 90 postDestroy(); |
| 91 #else |
| 92 deref(); |
| 93 #endif |
| 94 } |
| 95 |
45 RenderPart::~RenderPart() | 96 RenderPart::~RenderPart() |
46 { | 97 { |
| 98 #if !ENABLE(OILPAN) |
| 99 ASSERT(m_refCount <= 0); |
| 100 #endif |
| 101 } |
| 102 |
| 103 Widget* RenderPart::widget() const |
| 104 { |
| 105 // Plugin widgets are stored in their DOM node. This includes HTMLAppletElem
ent. |
| 106 Element* element = toElement(node()); |
| 107 |
| 108 if (element && element->isFrameOwnerElement()) |
| 109 return toHTMLFrameOwnerElement(element)->ownedWidget(); |
| 110 |
| 111 return 0; |
47 } | 112 } |
48 | 113 |
49 LayerType RenderPart::layerTypeRequired() const | 114 LayerType RenderPart::layerTypeRequired() const |
50 { | 115 { |
51 LayerType type = RenderWidget::layerTypeRequired(); | 116 LayerType type = RenderReplaced::layerTypeRequired(); |
52 if (type != NoLayer) | 117 if (type != NoLayer) |
53 return type; | 118 return type; |
54 return ForcedLayer; | 119 return ForcedLayer; |
55 } | 120 } |
56 | 121 |
57 bool RenderPart::requiresAcceleratedCompositing() const | 122 bool RenderPart::requiresAcceleratedCompositing() const |
58 { | 123 { |
59 // There are two general cases in which we can return true. First, if this i
s a plugin | 124 // There are two general cases in which we can return true. First, if this i
s a plugin |
60 // renderer and the plugin has a layer, then we need a layer. Second, if thi
s is | 125 // renderer and the plugin has a layer, then we need a layer. Second, if thi
s is |
61 // a renderer with a contentDocument and that document needs a layer, then w
e need | 126 // a renderer with a contentDocument and that document needs a layer, then w
e need |
(...skipping 11 matching lines...) Expand all Loading... |
73 if (Document* contentDocument = element->contentDocument()) { | 138 if (Document* contentDocument = element->contentDocument()) { |
74 if (RenderView* view = contentDocument->renderView()) | 139 if (RenderView* view = contentDocument->renderView()) |
75 return view->usesCompositing(); | 140 return view->usesCompositing(); |
76 } | 141 } |
77 | 142 |
78 return false; | 143 return false; |
79 } | 144 } |
80 | 145 |
81 bool RenderPart::needsPreferredWidthsRecalculation() const | 146 bool RenderPart::needsPreferredWidthsRecalculation() const |
82 { | 147 { |
83 if (RenderWidget::needsPreferredWidthsRecalculation()) | 148 if (RenderReplaced::needsPreferredWidthsRecalculation()) |
84 return true; | 149 return true; |
85 return embeddedContentBox(); | 150 return embeddedContentBox(); |
86 } | 151 } |
87 | 152 |
| 153 bool RenderPart::nodeAtPointOverWidget(const HitTestRequest& request, HitTestRes
ult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accu
mulatedOffset, HitTestAction action) |
| 154 { |
| 155 bool hadResult = result.innerNode(); |
| 156 bool inside = RenderReplaced::nodeAtPoint(request, result, locationInContain
er, accumulatedOffset, action); |
| 157 |
| 158 // Check to see if we are really over the widget itself (and not just in the
border/padding area). |
| 159 if ((inside || result.isRectBasedTest()) && !hadResult && result.innerNode()
== node()) |
| 160 result.setIsOverWidget(contentBoxRect().contains(result.localPoint())); |
| 161 return inside; |
| 162 } |
| 163 |
88 bool RenderPart::nodeAtPoint(const HitTestRequest& request, HitTestResult& resul
t, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOff
set, HitTestAction action) | 164 bool RenderPart::nodeAtPoint(const HitTestRequest& request, HitTestResult& resul
t, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOff
set, HitTestAction action) |
89 { | 165 { |
90 if (!widget() || !widget()->isFrameView() || !request.allowsChildFrameConten
t()) | 166 if (!widget() || !widget()->isFrameView() || !request.allowsChildFrameConten
t()) |
91 return RenderWidget::nodeAtPoint(request, result, locationInContainer, a
ccumulatedOffset, action); | 167 return nodeAtPointOverWidget(request, result, locationInContainer, accum
ulatedOffset, action); |
92 | 168 |
93 // FIXME: Until RemoteFrames use RemoteFrameViews, we need an explicit check
here. | 169 // FIXME: Until RemoteFrames use RemoteFrameViews, we need an explicit check
here. |
94 if (toFrameView(widget())->frame().isRemoteFrameTemporary()) | 170 if (toFrameView(widget())->frame().isRemoteFrameTemporary()) |
95 return RenderWidget::nodeAtPoint(request, result, locationInContainer, a
ccumulatedOffset, action); | 171 return nodeAtPointOverWidget(request, result, locationInContainer, accum
ulatedOffset, action); |
96 | 172 |
97 FrameView* childFrameView = toFrameView(widget()); | 173 FrameView* childFrameView = toFrameView(widget()); |
98 RenderView* childRoot = childFrameView->renderView(); | 174 RenderView* childRoot = childFrameView->renderView(); |
99 | 175 |
100 if (childRoot) { | 176 if (childRoot) { |
101 LayoutPoint adjustedLocation = accumulatedOffset + location(); | 177 LayoutPoint adjustedLocation = accumulatedOffset + location(); |
102 LayoutPoint contentOffset = LayoutPoint(borderLeft() + paddingLeft(), bo
rderTop() + paddingTop()) - childFrameView->scrollOffset(); | 178 LayoutPoint contentOffset = LayoutPoint(borderLeft() + paddingLeft(), bo
rderTop() + paddingTop()) - childFrameView->scrollOffset(); |
103 HitTestLocation newHitTestLocation(locationInContainer, -adjustedLocatio
n - contentOffset); | 179 HitTestLocation newHitTestLocation(locationInContainer, -adjustedLocatio
n - contentOffset); |
104 HitTestRequest newHitTestRequest(request.type() | HitTestRequest::ChildF
rameHitTest); | 180 HitTestRequest newHitTestRequest(request.type() | HitTestRequest::ChildF
rameHitTest); |
105 HitTestResult childFrameResult(newHitTestLocation); | 181 HitTestResult childFrameResult(newHitTestLocation); |
106 | 182 |
107 bool isInsideChildFrame = childRoot->hitTest(newHitTestRequest, newHitTe
stLocation, childFrameResult); | 183 bool isInsideChildFrame = childRoot->hitTest(newHitTestRequest, newHitTe
stLocation, childFrameResult); |
108 | 184 |
109 if (newHitTestLocation.isRectBasedTest()) | 185 if (newHitTestLocation.isRectBasedTest()) |
110 result.append(childFrameResult); | 186 result.append(childFrameResult); |
111 else if (isInsideChildFrame) | 187 else if (isInsideChildFrame) |
112 result = childFrameResult; | 188 result = childFrameResult; |
113 | 189 |
114 if (isInsideChildFrame) | 190 if (isInsideChildFrame) |
115 return true; | 191 return true; |
116 } | 192 } |
117 | 193 |
118 return RenderWidget::nodeAtPoint(request, result, locationInContainer, accum
ulatedOffset, action); | 194 return nodeAtPointOverWidget(request, result, locationInContainer, accumulat
edOffset, action); |
119 } | 195 } |
120 | 196 |
121 CompositingReasons RenderPart::additionalCompositingReasons() const | 197 CompositingReasons RenderPart::additionalCompositingReasons() const |
122 { | 198 { |
123 if (requiresAcceleratedCompositing()) | 199 if (requiresAcceleratedCompositing()) |
124 return CompositingReasonIFrame; | 200 return CompositingReasonIFrame; |
125 return CompositingReasonNone; | 201 return CompositingReasonNone; |
126 } | 202 } |
127 | 203 |
128 } | 204 void RenderPart::styleDidChange(StyleDifference diff, const RenderStyle* oldStyl
e) |
| 205 { |
| 206 RenderReplaced::styleDidChange(diff, oldStyle); |
| 207 Widget* widget = this->widget(); |
| 208 |
| 209 if (!widget) |
| 210 return; |
| 211 |
| 212 if (style()->visibility() != VISIBLE) { |
| 213 widget->hide(); |
| 214 } else { |
| 215 widget->show(); |
| 216 } |
| 217 } |
| 218 |
| 219 void RenderPart::layout() |
| 220 { |
| 221 ASSERT(needsLayout()); |
| 222 |
| 223 clearNeedsLayout(); |
| 224 } |
| 225 |
| 226 void RenderPart::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) |
| 227 { |
| 228 ANNOTATE_GRAPHICS_CONTEXT(paintInfo, this); |
| 229 |
| 230 if (!shouldPaint(paintInfo, paintOffset)) |
| 231 return; |
| 232 |
| 233 LayoutPoint adjustedPaintOffset = paintOffset + location(); |
| 234 |
| 235 if (hasBoxDecorationBackground() && (paintInfo.phase == PaintPhaseForeground
|| paintInfo.phase == PaintPhaseSelection)) |
| 236 paintBoxDecorationBackground(paintInfo, adjustedPaintOffset); |
| 237 |
| 238 if (paintInfo.phase == PaintPhaseMask) { |
| 239 paintMask(paintInfo, adjustedPaintOffset); |
| 240 return; |
| 241 } |
| 242 |
| 243 if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSe
lfOutline) && style()->hasOutline()) |
| 244 paintOutline(paintInfo, LayoutRect(adjustedPaintOffset, size())); |
| 245 |
| 246 if (paintInfo.phase != PaintPhaseForeground) |
| 247 return; |
| 248 |
| 249 if (style()->hasBorderRadius()) { |
| 250 LayoutRect borderRect = LayoutRect(adjustedPaintOffset, size()); |
| 251 |
| 252 if (borderRect.isEmpty()) |
| 253 return; |
| 254 |
| 255 // Push a clip if we have a border radius, since we want to round the fo
reground content that gets painted. |
| 256 paintInfo.context->save(); |
| 257 RoundedRect roundedInnerRect = style()->getRoundedInnerBorderFor(borderR
ect, |
| 258 paddingTop() + borderTop(), paddingBottom() + borderBottom(), paddin
gLeft() + borderLeft(), paddingRight() + borderRight(), true, true); |
| 259 BoxPainter::clipRoundedInnerRect(paintInfo.context, borderRect, roundedI
nnerRect); |
| 260 } |
| 261 |
| 262 if (this->widget()) |
| 263 paintContents(paintInfo, paintOffset); |
| 264 |
| 265 if (style()->hasBorderRadius()) |
| 266 paintInfo.context->restore(); |
| 267 |
| 268 // Paint a partially transparent wash over selected widgets. |
| 269 if (isSelected() && !document().printing()) { |
| 270 LayoutRect rect = localSelectionRect(); |
| 271 rect.moveBy(adjustedPaintOffset); |
| 272 paintInfo.context->fillRect(pixelSnappedIntRect(rect), selectionBackgrou
ndColor()); |
| 273 } |
| 274 |
| 275 if (canResize()) |
| 276 layer()->scrollableArea()->paintResizer(paintInfo.context, roundedIntPoi
nt(adjustedPaintOffset), paintInfo.rect); |
| 277 } |
| 278 |
| 279 void RenderPart::paintContents(PaintInfo& paintInfo, const LayoutPoint& paintOff
set) |
| 280 { |
| 281 LayoutPoint adjustedPaintOffset = paintOffset + location(); |
| 282 |
| 283 Widget* widget = this->widget(); |
| 284 RELEASE_ASSERT(widget); |
| 285 |
| 286 // Tell the widget to paint now. This is the only time the widget is allowed |
| 287 // to paint itself. That way it will composite properly with z-indexed layer
s. |
| 288 IntPoint widgetLocation = widget->frameRect().location(); |
| 289 IntPoint paintLocation(roundToInt(adjustedPaintOffset.x() + borderLeft() + p
addingLeft()), |
| 290 roundToInt(adjustedPaintOffset.y() + borderTop() + paddingTop())); |
| 291 IntRect paintRect = paintInfo.rect; |
| 292 |
| 293 IntSize widgetPaintOffset = paintLocation - widgetLocation; |
| 294 // When painting widgets into compositing layers, tx and ty are relative to
the enclosing compositing layer, |
| 295 // not the root. In this case, shift the CTM and adjust the paintRect to be
root-relative to fix plug-in drawing. |
| 296 if (!widgetPaintOffset.isZero()) { |
| 297 paintInfo.context->translate(widgetPaintOffset.width(), widgetPaintOffse
t.height()); |
| 298 paintRect.move(-widgetPaintOffset); |
| 299 } |
| 300 widget->paint(paintInfo.context, paintRect); |
| 301 |
| 302 if (!widgetPaintOffset.isZero()) |
| 303 paintInfo.context->translate(-widgetPaintOffset.width(), -widgetPaintOff
set.height()); |
| 304 } |
| 305 |
| 306 CursorDirective RenderPart::getCursor(const LayoutPoint& point, Cursor& cursor)
const |
| 307 { |
| 308 if (widget() && widget()->isPluginView()) { |
| 309 // A plug-in is responsible for setting the cursor when the pointer is o
ver it. |
| 310 return DoNotSetCursor; |
| 311 } |
| 312 return RenderReplaced::getCursor(point, cursor); |
| 313 } |
| 314 |
| 315 void RenderPart::updateOnWidgetChange() |
| 316 { |
| 317 Widget* widget = this->widget(); |
| 318 if (!widget) |
| 319 return; |
| 320 |
| 321 if (!style()) |
| 322 return; |
| 323 |
| 324 if (!needsLayout()) |
| 325 updateWidgetGeometry(); |
| 326 |
| 327 if (style()->visibility() != VISIBLE) { |
| 328 widget->hide(); |
| 329 } else { |
| 330 widget->show(); |
| 331 // FIXME: Why do we issue a full paint invalidation in this case, but no
t the other? |
| 332 setShouldDoFullPaintInvalidation(); |
| 333 } |
| 334 } |
| 335 |
| 336 void RenderPart::updateWidgetPosition() |
| 337 { |
| 338 Widget* widget = this->widget(); |
| 339 if (!widget || !node()) // Check the node in case destroy() has been called. |
| 340 return; |
| 341 |
| 342 bool boundsChanged = updateWidgetGeometry(); |
| 343 |
| 344 // If the frame bounds got changed, or if view needs layout (possibly indica
ting |
| 345 // content size is wrong) we have to do a layout to set the right widget siz
e. |
| 346 if (widget && widget->isFrameView()) { |
| 347 FrameView* frameView = toFrameView(widget); |
| 348 // Check the frame's page to make sure that the frame isn't in the proce
ss of being destroyed. |
| 349 if ((boundsChanged || frameView->needsLayout()) && frameView->frame().pa
ge()) |
| 350 frameView->layout(); |
| 351 } |
| 352 } |
| 353 |
| 354 void RenderPart::widgetPositionsUpdated() |
| 355 { |
| 356 Widget* widget = this->widget(); |
| 357 if (!widget) |
| 358 return; |
| 359 widget->widgetPositionsUpdated(); |
| 360 } |
| 361 |
| 362 bool RenderPart::updateWidgetGeometry() |
| 363 { |
| 364 Widget* widget = this->widget(); |
| 365 ASSERT(widget); |
| 366 |
| 367 LayoutRect contentBox = contentBoxRect(); |
| 368 LayoutRect absoluteContentBox(localToAbsoluteQuad(FloatQuad(contentBox)).bou
ndingBox()); |
| 369 if (widget->isFrameView()) { |
| 370 contentBox.setLocation(absoluteContentBox.location()); |
| 371 return setWidgetGeometry(contentBox); |
| 372 } |
| 373 |
| 374 return setWidgetGeometry(absoluteContentBox); |
| 375 } |
| 376 |
| 377 // Widgets are always placed on integer boundaries, so rounding the size is actu
ally |
| 378 // the desired behavior. This function is here because it's otherwise seldom wha
t we |
| 379 // want to do with a LayoutRect. |
| 380 static inline IntRect roundedIntRect(const LayoutRect& rect) |
| 381 { |
| 382 return IntRect(roundedIntPoint(rect.location()), roundedIntSize(rect.size())
); |
| 383 } |
| 384 |
| 385 bool RenderPart::setWidgetGeometry(const LayoutRect& frame) |
| 386 { |
| 387 if (!node()) |
| 388 return false; |
| 389 |
| 390 Widget* widget = this->widget(); |
| 391 ASSERT(widget); |
| 392 |
| 393 IntRect newFrame = roundedIntRect(frame); |
| 394 |
| 395 if (widget->frameRect() == newFrame) |
| 396 return false; |
| 397 |
| 398 RefPtrWillBeRawPtr<RenderPart> protector(this); |
| 399 RefPtrWillBeRawPtr<Node> protectedNode(node()); |
| 400 widget->setFrameRect(newFrame); |
| 401 return widget->frameRect().size() != newFrame.size(); |
| 402 } |
| 403 |
| 404 } |
OLD | NEW |