OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) | |
3 * (C) 1999 Antti Koivisto (koivisto@kde.org) | |
4 * (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com) | |
5 * (C) 2005, 2006 Samuel Weinig (sam.weinig@gmail.com) | |
6 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserv
ed. | |
7 * Copyright (C) 2013 Adobe Systems Incorporated. All rights reserved. | |
8 * | |
9 * This library is free software; you can redistribute it and/or | |
10 * modify it under the terms of the GNU Library General Public | |
11 * License as published by the Free Software Foundation; either | |
12 * version 2 of the License, or (at your option) any later version. | |
13 * | |
14 * This library is distributed in the hope that it will be useful, | |
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 * Library General Public License for more details. | |
18 * | |
19 * You should have received a copy of the GNU Library General Public License | |
20 * along with this library; see the file COPYING.LIB. If not, write to | |
21 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | |
22 * Boston, MA 02110-1301, USA. | |
23 * | |
24 */ | |
25 | |
26 #include "config.h" | |
27 #include "core/rendering/RenderBox.h" | |
28 | |
29 #include "core/HTMLNames.h" | |
30 #include "core/dom/Document.h" | |
31 #include "core/editing/htmlediting.h" | |
32 #include "core/frame/FrameHost.h" | |
33 #include "core/frame/FrameView.h" | |
34 #include "core/frame/LocalFrame.h" | |
35 #include "core/frame/PinchViewport.h" | |
36 #include "core/frame/Settings.h" | |
37 #include "core/html/HTMLElement.h" | |
38 #include "core/html/HTMLFrameElementBase.h" | |
39 #include "core/html/HTMLFrameOwnerElement.h" | |
40 #include "core/layout/HitTestResult.h" | |
41 #include "core/layout/Layer.h" | |
42 #include "core/layout/LayoutGeometryMap.h" | |
43 #include "core/layout/LayoutListBox.h" | |
44 #include "core/layout/LayoutListMarker.h" | |
45 #include "core/layout/LayoutMultiColumnSpannerPlaceholder.h" | |
46 #include "core/layout/LayoutScrollbarPart.h" | |
47 #include "core/layout/LayoutTableCell.h" | |
48 #include "core/layout/PaintInfo.h" | |
49 #include "core/layout/compositing/LayerCompositor.h" | |
50 #include "core/layout/style/ShadowList.h" | |
51 #include "core/page/AutoscrollController.h" | |
52 #include "core/page/EventHandler.h" | |
53 #include "core/page/Page.h" | |
54 #include "core/paint/BackgroundImageGeometry.h" | |
55 #include "core/paint/BoxPainter.h" | |
56 #include "core/rendering/RenderDeprecatedFlexibleBox.h" | |
57 #include "core/rendering/RenderFlexibleBox.h" | |
58 #include "core/rendering/RenderGrid.h" | |
59 #include "core/rendering/RenderInline.h" | |
60 #include "core/rendering/RenderView.h" | |
61 #include "platform/LengthFunctions.h" | |
62 #include "platform/geometry/FloatQuad.h" | |
63 #include "platform/geometry/FloatRoundedRect.h" | |
64 #include "platform/geometry/TransformState.h" | |
65 #include "platform/graphics/paint/DisplayItemList.h" | |
66 #include <algorithm> | |
67 #include <math.h> | |
68 | |
69 namespace blink { | |
70 | |
71 using namespace HTMLNames; | |
72 | |
73 // Used by flexible boxes when flexing this element and by table cells. | |
74 typedef WTF::HashMap<const RenderBox*, LayoutUnit> OverrideSizeMap; | |
75 | |
76 // Used by grid elements to properly size their grid items. | |
77 // FIXME: Move these into RenderBoxRareData. | |
78 static OverrideSizeMap* gOverrideContainingBlockLogicalHeightMap = 0; | |
79 static OverrideSizeMap* gOverrideContainingBlockLogicalWidthMap = 0; | |
80 static OverrideSizeMap* gExtraInlineOffsetMap = 0; | |
81 static OverrideSizeMap* gExtraBlockOffsetMap = 0; | |
82 | |
83 | |
84 // Size of border belt for autoscroll. When mouse pointer in border belt, | |
85 // autoscroll is started. | |
86 static const int autoscrollBeltSize = 20; | |
87 static const unsigned backgroundObscurationTestMaxDepth = 4; | |
88 | |
89 static bool skipBodyBackground(const RenderBox* bodyElementRenderer) | |
90 { | |
91 ASSERT(bodyElementRenderer->isBody()); | |
92 // The <body> only paints its background if the root element has defined a b
ackground independent of the body, | |
93 // or if the <body>'s parent is not the document element's renderer (e.g. in
side SVG foreignObject). | |
94 LayoutObject* documentElementRenderer = bodyElementRenderer->document().docu
mentElement()->renderer(); | |
95 return documentElementRenderer | |
96 && !documentElementRenderer->hasBackground() | |
97 && (documentElementRenderer == bodyElementRenderer->parent()); | |
98 } | |
99 | |
100 RenderBox::RenderBox(ContainerNode* node) | |
101 : LayoutBoxModelObject(node) | |
102 , m_intrinsicContentLogicalHeight(-1) | |
103 , m_minPreferredLogicalWidth(-1) | |
104 , m_maxPreferredLogicalWidth(-1) | |
105 { | |
106 setIsBox(); | |
107 } | |
108 | |
109 LayerType RenderBox::layerTypeRequired() const | |
110 { | |
111 // hasAutoZIndex only returns true if the element is positioned or a flex-it
em since | |
112 // position:static elements that are not flex-items get their z-index coerce
d to auto. | |
113 if (isPositioned() || createsGroup() || hasClipPath() || hasTransformRelated
Property() | |
114 || hasHiddenBackface() || hasReflection() || style()->specifiesColumns() | |
115 || !style()->hasAutoZIndex() || style()->shouldCompositeForCurrentAnimat
ions()) | |
116 return NormalLayer; | |
117 | |
118 // Ensure that explicit use of scroll-blocks-on creates a Layer (since we mi
ght need | |
119 // it to be composited). | |
120 if (style()->hasScrollBlocksOn()) { | |
121 if (isDocumentElement()) { | |
122 ASSERT(style()->scrollBlocksOn() == view()->style()->scrollBlocksOn(
)); | |
123 return NoLayer; | |
124 } | |
125 return NormalLayer; | |
126 } | |
127 if (hasOverflowClip()) | |
128 return OverflowClipLayer; | |
129 | |
130 return NoLayer; | |
131 } | |
132 | |
133 void RenderBox::willBeDestroyed() | |
134 { | |
135 clearOverrideSize(); | |
136 clearContainingBlockOverrideSize(); | |
137 clearExtraInlineAndBlockOffests(); | |
138 | |
139 RenderBlock::removePercentHeightDescendantIfNeeded(this); | |
140 | |
141 ShapeOutsideInfo::removeInfo(*this); | |
142 | |
143 LayoutBoxModelObject::willBeDestroyed(); | |
144 } | |
145 | |
146 void RenderBox::removeFloatingOrPositionedChildFromBlockLists() | |
147 { | |
148 ASSERT(isFloatingOrOutOfFlowPositioned()); | |
149 | |
150 if (documentBeingDestroyed()) | |
151 return; | |
152 | |
153 if (isFloating()) { | |
154 RenderBlockFlow* parentBlockFlow = 0; | |
155 for (LayoutObject* curr = parent(); curr && !curr->isRenderView(); curr
= curr->parent()) { | |
156 if (curr->isRenderBlockFlow()) { | |
157 RenderBlockFlow* currBlockFlow = toRenderBlockFlow(curr); | |
158 if (!parentBlockFlow || currBlockFlow->containsFloat(this)) | |
159 parentBlockFlow = currBlockFlow; | |
160 } | |
161 } | |
162 | |
163 if (parentBlockFlow) { | |
164 parentBlockFlow->markSiblingsWithFloatsForLayout(this); | |
165 parentBlockFlow->markAllDescendantsWithFloatsForLayout(this, false); | |
166 } | |
167 } | |
168 | |
169 if (isOutOfFlowPositioned()) | |
170 RenderBlock::removePositionedObject(this); | |
171 } | |
172 | |
173 void RenderBox::styleWillChange(StyleDifference diff, const LayoutStyle& newStyl
e) | |
174 { | |
175 const LayoutStyle* oldStyle = style(); | |
176 if (oldStyle) { | |
177 // The background of the root element or the body element could propagat
e up to | |
178 // the canvas. Just dirty the entire canvas when our style changes subst
antially. | |
179 if ((diff.needsPaintInvalidation() || diff.needsLayout()) && node() | |
180 && (isHTMLHtmlElement(*node()) || isHTMLBodyElement(*node()))) { | |
181 view()->setShouldDoFullPaintInvalidation(); | |
182 | |
183 if (oldStyle->hasEntirelyFixedBackground() != newStyle.hasEntirelyFi
xedBackground()) | |
184 view()->compositor()->setNeedsUpdateFixedBackground(); | |
185 } | |
186 | |
187 // When a layout hint happens and an object's position style changes, we
have to do a layout | |
188 // to dirty the render tree using the old position value now. | |
189 if (diff.needsFullLayout() && parent() && oldStyle->position() != newSty
le.position()) { | |
190 markContainingBlocksForLayout(); | |
191 if (oldStyle->position() == StaticPosition) | |
192 setShouldDoFullPaintInvalidation(); | |
193 else if (newStyle.hasOutOfFlowPosition()) | |
194 parent()->setChildNeedsLayout(); | |
195 if (isFloating() && !isOutOfFlowPositioned() && newStyle.hasOutOfFlo
wPosition()) | |
196 removeFloatingOrPositionedChildFromBlockLists(); | |
197 } | |
198 // FIXME: This branch runs when !oldStyle, which means that layout was never
called | |
199 // so what's the point in invalidating the whole view that we never painted? | |
200 } else if (isBody()) { | |
201 view()->setShouldDoFullPaintInvalidation(); | |
202 } | |
203 | |
204 LayoutBoxModelObject::styleWillChange(diff, newStyle); | |
205 } | |
206 | |
207 void RenderBox::styleDidChange(StyleDifference diff, const LayoutStyle* oldStyle
) | |
208 { | |
209 // Horizontal writing mode definition is updated in LayoutBoxModelObject::up
dateFromStyle, | |
210 // (as part of the LayoutBoxModelObject::styleDidChange call below). So, we
can safely cache the horizontal | |
211 // writing mode value before style change here. | |
212 bool oldHorizontalWritingMode = isHorizontalWritingMode(); | |
213 | |
214 LayoutBoxModelObject::styleDidChange(diff, oldStyle); | |
215 | |
216 const LayoutStyle& newStyle = styleRef(); | |
217 if (needsLayout() && oldStyle) | |
218 RenderBlock::removePercentHeightDescendantIfNeeded(this); | |
219 | |
220 if (RenderBlock::hasPercentHeightContainerMap() && slowFirstChild() | |
221 && oldHorizontalWritingMode != isHorizontalWritingMode()) | |
222 RenderBlock::clearPercentHeightDescendantsFrom(this); | |
223 | |
224 // If our zoom factor changes and we have a defined scrollLeft/Top, we need
to adjust that value into the | |
225 // new zoomed coordinate space. | |
226 if (hasOverflowClip() && oldStyle && oldStyle->effectiveZoom() != newStyle.e
ffectiveZoom() && layer()) { | |
227 if (int left = layer()->scrollableArea()->scrollXOffset()) { | |
228 left = (left / oldStyle->effectiveZoom()) * newStyle.effectiveZoom()
; | |
229 layer()->scrollableArea()->scrollToXOffset(left); | |
230 } | |
231 if (int top = layer()->scrollableArea()->scrollYOffset()) { | |
232 top = (top / oldStyle->effectiveZoom()) * newStyle.effectiveZoom(); | |
233 layer()->scrollableArea()->scrollToYOffset(top); | |
234 } | |
235 } | |
236 | |
237 // Our opaqueness might have changed without triggering layout. | |
238 if (diff.needsPaintInvalidation()) { | |
239 LayoutObject* parentToInvalidate = parent(); | |
240 for (unsigned i = 0; i < backgroundObscurationTestMaxDepth && parentToIn
validate; ++i) { | |
241 parentToInvalidate->invalidateBackgroundObscurationStatus(); | |
242 parentToInvalidate = parentToInvalidate->parent(); | |
243 } | |
244 } | |
245 | |
246 if (isDocumentElement() || isBody()) { | |
247 document().view()->recalculateScrollbarOverlayStyle(); | |
248 document().view()->recalculateCustomScrollbarStyle(); | |
249 } | |
250 updateShapeOutsideInfoAfterStyleChange(*style(), oldStyle); | |
251 updateGridPositionAfterStyleChange(oldStyle); | |
252 | |
253 if (LayoutMultiColumnSpannerPlaceholder* placeholder = this->spannerPlacehol
der()) | |
254 placeholder->updateMarginProperties(); | |
255 } | |
256 | |
257 void RenderBox::updateShapeOutsideInfoAfterStyleChange(const LayoutStyle& style,
const LayoutStyle* oldStyle) | |
258 { | |
259 const ShapeValue* shapeOutside = style.shapeOutside(); | |
260 const ShapeValue* oldShapeOutside = oldStyle ? oldStyle->shapeOutside() : La
youtStyle::initialShapeOutside(); | |
261 | |
262 Length shapeMargin = style.shapeMargin(); | |
263 Length oldShapeMargin = oldStyle ? oldStyle->shapeMargin() : LayoutStyle::in
itialShapeMargin(); | |
264 | |
265 float shapeImageThreshold = style.shapeImageThreshold(); | |
266 float oldShapeImageThreshold = oldStyle ? oldStyle->shapeImageThreshold() :
LayoutStyle::initialShapeImageThreshold(); | |
267 | |
268 // FIXME: A future optimization would do a deep comparison for equality. (bu
g 100811) | |
269 if (shapeOutside == oldShapeOutside && shapeMargin == oldShapeMargin && shap
eImageThreshold == oldShapeImageThreshold) | |
270 return; | |
271 | |
272 if (!shapeOutside) | |
273 ShapeOutsideInfo::removeInfo(*this); | |
274 else | |
275 ShapeOutsideInfo::ensureInfo(*this).markShapeAsDirty(); | |
276 | |
277 if (shapeOutside || shapeOutside != oldShapeOutside) | |
278 markShapeOutsideDependentsForLayout(); | |
279 } | |
280 | |
281 void RenderBox::updateGridPositionAfterStyleChange(const LayoutStyle* oldStyle) | |
282 { | |
283 if (!oldStyle || !parent() || !parent()->isRenderGrid()) | |
284 return; | |
285 | |
286 if (oldStyle->gridColumnStart() == style()->gridColumnStart() | |
287 && oldStyle->gridColumnEnd() == style()->gridColumnEnd() | |
288 && oldStyle->gridRowStart() == style()->gridRowStart() | |
289 && oldStyle->gridRowEnd() == style()->gridRowEnd() | |
290 && oldStyle->order() == style()->order() | |
291 && oldStyle->hasOutOfFlowPosition() == style()->hasOutOfFlowPosition()) | |
292 return; | |
293 | |
294 // It should be possible to not dirty the grid in some cases (like moving an
explicitly placed grid item). | |
295 // For now, it's more simple to just always recompute the grid. | |
296 toRenderGrid(parent())->dirtyGrid(); | |
297 } | |
298 | |
299 void RenderBox::updateFromStyle() | |
300 { | |
301 LayoutBoxModelObject::updateFromStyle(); | |
302 | |
303 const LayoutStyle& styleToUse = styleRef(); | |
304 bool isRootObject = isDocumentElement(); | |
305 bool isViewObject = isRenderView(); | |
306 bool rootLayerScrolls = document().settings() && document().settings()->root
LayerScrolls(); | |
307 | |
308 // The root and the RenderView always paint their backgrounds/borders. | |
309 if (isRootObject || isViewObject) | |
310 setHasBoxDecorationBackground(true); | |
311 | |
312 setFloating(!isOutOfFlowPositioned() && styleToUse.isFloating()); | |
313 | |
314 bool boxHasOverflowClip = false; | |
315 if (!styleToUse.isOverflowVisible() && isRenderBlock() && (rootLayerScrolls
|| !isViewObject)) { | |
316 // If overflow has been propagated to the viewport, it has no effect her
e. | |
317 if (node() != document().viewportDefiningElement()) | |
318 boxHasOverflowClip = true; | |
319 } | |
320 | |
321 if (boxHasOverflowClip != hasOverflowClip()) { | |
322 // FIXME: This shouldn't be required if we tracked the visual overflow | |
323 // generated by positioned children or self painting layers. crbug.com/3
45403 | |
324 for (LayoutObject* child = slowFirstChild(); child; child = child->nextS
ibling()) | |
325 child->setMayNeedPaintInvalidation(); | |
326 } | |
327 | |
328 setHasOverflowClip(boxHasOverflowClip); | |
329 | |
330 setHasTransformRelatedProperty(styleToUse.hasTransformRelatedProperty()); | |
331 setHasReflection(styleToUse.boxReflect()); | |
332 } | |
333 | |
334 void RenderBox::layout() | |
335 { | |
336 ASSERT(needsLayout()); | |
337 | |
338 LayoutObject* child = slowFirstChild(); | |
339 if (!child) { | |
340 clearNeedsLayout(); | |
341 return; | |
342 } | |
343 | |
344 LayoutState state(*this, locationOffset()); | |
345 while (child) { | |
346 child->layoutIfNeeded(); | |
347 ASSERT(!child->needsLayout()); | |
348 child = child->nextSibling(); | |
349 } | |
350 invalidateBackgroundObscurationStatus(); | |
351 clearNeedsLayout(); | |
352 } | |
353 | |
354 // More IE extensions. clientWidth and clientHeight represent the interior of a
n object | |
355 // excluding border and scrollbar. | |
356 LayoutUnit RenderBox::clientWidth() const | |
357 { | |
358 return m_frameRect.width() - borderLeft() - borderRight() - verticalScrollba
rWidth(); | |
359 } | |
360 | |
361 LayoutUnit RenderBox::clientHeight() const | |
362 { | |
363 return m_frameRect.height() - borderTop() - borderBottom() - horizontalScrol
lbarHeight(); | |
364 } | |
365 | |
366 int RenderBox::pixelSnappedClientWidth() const | |
367 { | |
368 return snapSizeToPixel(clientWidth(), location().x() + clientLeft()); | |
369 } | |
370 | |
371 int RenderBox::pixelSnappedClientHeight() const | |
372 { | |
373 return snapSizeToPixel(clientHeight(), location().y() + clientTop()); | |
374 } | |
375 | |
376 int RenderBox::pixelSnappedOffsetWidth() const | |
377 { | |
378 return snapSizeToPixel(offsetWidth(), location().x() + clientLeft()); | |
379 } | |
380 | |
381 int RenderBox::pixelSnappedOffsetHeight() const | |
382 { | |
383 return snapSizeToPixel(offsetHeight(), location().y() + clientTop()); | |
384 } | |
385 | |
386 LayoutUnit RenderBox::scrollWidth() const | |
387 { | |
388 if (hasOverflowClip()) | |
389 return layer()->scrollableArea()->scrollWidth(); | |
390 // For objects with visible overflow, this matches IE. | |
391 // FIXME: Need to work right with writing modes. | |
392 if (style()->isLeftToRightDirection()) | |
393 return std::max(clientWidth(), layoutOverflowRect().maxX() - borderLeft(
)); | |
394 return clientWidth() - std::min(LayoutUnit(), layoutOverflowRect().x() - bor
derLeft()); | |
395 } | |
396 | |
397 LayoutUnit RenderBox::scrollHeight() const | |
398 { | |
399 if (hasOverflowClip()) | |
400 return layer()->scrollableArea()->scrollHeight(); | |
401 // For objects with visible overflow, this matches IE. | |
402 // FIXME: Need to work right with writing modes. | |
403 return std::max(clientHeight(), layoutOverflowRect().maxY() - borderTop()); | |
404 } | |
405 | |
406 LayoutUnit RenderBox::scrollLeft() const | |
407 { | |
408 return hasOverflowClip() ? layer()->scrollableArea()->scrollXOffset() : 0; | |
409 } | |
410 | |
411 LayoutUnit RenderBox::scrollTop() const | |
412 { | |
413 return hasOverflowClip() ? layer()->scrollableArea()->scrollYOffset() : 0; | |
414 } | |
415 | |
416 int RenderBox::pixelSnappedScrollWidth() const | |
417 { | |
418 return snapSizeToPixel(scrollWidth(), location().x() + clientLeft()); | |
419 } | |
420 | |
421 int RenderBox::pixelSnappedScrollHeight() const | |
422 { | |
423 if (hasOverflowClip()) | |
424 return layer()->scrollableArea()->scrollHeight(); | |
425 // For objects with visible overflow, this matches IE. | |
426 // FIXME: Need to work right with writing modes. | |
427 return snapSizeToPixel(scrollHeight(), location().y() + clientTop()); | |
428 } | |
429 | |
430 void RenderBox::setScrollLeft(LayoutUnit newLeft) | |
431 { | |
432 // This doesn't hit in any tests, but since the equivalent code in setScroll
Top | |
433 // does, presumably this code does as well. | |
434 DisableCompositingQueryAsserts disabler; | |
435 | |
436 if (hasOverflowClip()) | |
437 layer()->scrollableArea()->scrollToXOffset(newLeft, ScrollOffsetClamped,
ScrollBehaviorAuto); | |
438 } | |
439 | |
440 void RenderBox::setScrollTop(LayoutUnit newTop) | |
441 { | |
442 // Hits in compositing/overflow/do-not-assert-on-invisible-composited-layers
.html | |
443 DisableCompositingQueryAsserts disabler; | |
444 | |
445 if (hasOverflowClip()) | |
446 layer()->scrollableArea()->scrollToYOffset(newTop, ScrollOffsetClamped,
ScrollBehaviorAuto); | |
447 } | |
448 | |
449 void RenderBox::scrollToOffset(const DoubleSize& offset, ScrollBehavior scrollBe
havior) | |
450 { | |
451 // This doesn't hit in any tests, but since the equivalent code in setScroll
Top | |
452 // does, presumably this code does as well. | |
453 DisableCompositingQueryAsserts disabler; | |
454 | |
455 if (hasOverflowClip()) | |
456 layer()->scrollableArea()->scrollToOffset(offset, ScrollOffsetClamped, s
crollBehavior); | |
457 } | |
458 | |
459 static inline bool frameElementAndViewPermitScroll(HTMLFrameElementBase* frameEl
ementBase, FrameView* frameView) | |
460 { | |
461 // If scrollbars aren't explicitly forbidden, permit scrolling. | |
462 if (frameElementBase && frameElementBase->scrollingMode() != ScrollbarAlways
Off) | |
463 return true; | |
464 | |
465 // If scrollbars are forbidden, user initiated scrolls should obviously be i
gnored. | |
466 if (frameView->wasScrolledByUser()) | |
467 return false; | |
468 | |
469 // Forbid autoscrolls when scrollbars are off, but permits other programmati
c scrolls, | |
470 // like navigation to an anchor. | |
471 Page* page = frameView->frame().page(); | |
472 if (!page) | |
473 return false; | |
474 return !page->autoscrollController().autoscrollInProgress(); | |
475 } | |
476 | |
477 void RenderBox::scrollRectToVisible(const LayoutRect& rect, const ScrollAlignmen
t& alignX, const ScrollAlignment& alignY) | |
478 { | |
479 // Presumably the same issue as in setScrollTop. See crbug.com/343132. | |
480 DisableCompositingQueryAsserts disabler; | |
481 | |
482 RenderBox* parentBox = 0; | |
483 LayoutRect newRect = rect; | |
484 | |
485 bool restrictedByLineClamp = false; | |
486 if (parent()) { | |
487 parentBox = parent()->enclosingBox(); | |
488 restrictedByLineClamp = !parent()->style()->lineClamp().isNone(); | |
489 } | |
490 | |
491 if (hasOverflowClip() && !restrictedByLineClamp) { | |
492 // Don't scroll to reveal an overflow layer that is restricted by the -w
ebkit-line-clamp property. | |
493 // This will prevent us from revealing text hidden by the slider in Safa
ri RSS. | |
494 newRect = layer()->scrollableArea()->exposeRect(rect, alignX, alignY); | |
495 } else if (!parentBox && canBeProgramaticallyScrolled()) { | |
496 if (FrameView* frameView = this->frameView()) { | |
497 HTMLFrameOwnerElement* ownerElement = document().ownerElement(); | |
498 | |
499 if (ownerElement && ownerElement->renderer()) { | |
500 HTMLFrameElementBase* frameElementBase = isHTMLFrameElementBase(
*ownerElement) ? toHTMLFrameElementBase(ownerElement) : 0; | |
501 if (frameElementAndViewPermitScroll(frameElementBase, frameView)
) { | |
502 LayoutRect viewRect = frameView->visibleContentRect(); | |
503 LayoutRect exposeRect = ScrollAlignment::getRectToExpose(vie
wRect, rect, alignX, alignY); | |
504 | |
505 double xOffset = exposeRect.x(); | |
506 double yOffset = exposeRect.y(); | |
507 // Adjust offsets if they're outside of the allowable range. | |
508 xOffset = std::max(0.0, std::min<double>(frameView->contents
Width(), xOffset)); | |
509 yOffset = std::max(0.0, std::min<double>(frameView->contents
Height(), yOffset)); | |
510 | |
511 frameView->setScrollPosition(DoublePoint(xOffset, yOffset)); | |
512 if (frameView->safeToPropagateScrollToParent()) { | |
513 parentBox = ownerElement->renderer()->enclosingBox(); | |
514 // FIXME: This doesn't correctly convert the rect to | |
515 // absolute coordinates in the parent. | |
516 newRect.setX(rect.x() - frameView->scrollX() + frameView
->x()); | |
517 newRect.setY(rect.y() - frameView->scrollY() + frameView
->y()); | |
518 } else { | |
519 parentBox = 0; | |
520 } | |
521 } | |
522 } else { | |
523 if (frame()->settings()->pinchVirtualViewportEnabled()) { | |
524 PinchViewport& pinchViewport = frame()->page()->frameHost().
pinchViewport(); | |
525 | |
526 // We want to move the rect into the viewport that excludes
the scrollbars so we intersect | |
527 // the pinch viewport with the scrollbar-excluded frameView
content rect. | |
528 LayoutRect viewRect = intersection( | |
529 LayoutRect(pinchViewport.visibleRectInDocument()), frame
View->visibleContentRect()); | |
530 LayoutRect r = ScrollAlignment::getRectToExpose(viewRect, re
ct, alignX, alignY); | |
531 | |
532 // pinchViewport.scrollIntoView will attempt to center the g
iven rect within the viewport | |
533 // so to prevent it from adjusting r's coordinates the rect
must match the viewport's size | |
534 // i.e. add the subtracted scrollbars from above back in. | |
535 // FIXME: This is hacky and required because getRectToExpose
doesn't naturally account | |
536 // for the two viewports. crbug.com/449340. | |
537 r.setSize(LayoutSize(pinchViewport.visibleRectInDocument().s
ize())); | |
538 | |
539 pinchViewport.scrollIntoView(r); | |
540 } else { | |
541 LayoutRect viewRect = frameView->visibleContentRect(); | |
542 LayoutRect r = ScrollAlignment::getRectToExpose(viewRect, re
ct, alignX, alignY); | |
543 frameView->setScrollPosition(DoublePoint(r.location())); | |
544 } | |
545 } | |
546 } | |
547 } | |
548 | |
549 if (frame()->page()->autoscrollController().autoscrollInProgress()) | |
550 parentBox = enclosingScrollableBox(); | |
551 | |
552 if (parentBox) | |
553 parentBox->scrollRectToVisible(newRect, alignX, alignY); | |
554 } | |
555 | |
556 void RenderBox::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumul
atedOffset) const | |
557 { | |
558 rects.append(pixelSnappedIntRect(accumulatedOffset, size())); | |
559 } | |
560 | |
561 void RenderBox::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const | |
562 { | |
563 quads.append(localToAbsoluteQuad(FloatRect(0, 0, m_frameRect.width().toFloat
(), m_frameRect.height().toFloat()), 0 /* mode */, wasFixed)); | |
564 } | |
565 | |
566 void RenderBox::updateLayerTransformAfterLayout() | |
567 { | |
568 // Transform-origin depends on box size, so we need to update the layer tran
sform after layout. | |
569 if (hasLayer()) | |
570 layer()->updateTransformationMatrix(); | |
571 } | |
572 | |
573 LayoutUnit RenderBox::constrainLogicalWidthByMinMax(LayoutUnit logicalWidth, Lay
outUnit availableWidth, RenderBlock* cb) const | |
574 { | |
575 const LayoutStyle& styleToUse = styleRef(); | |
576 if (!styleToUse.logicalMaxWidth().isMaxSizeNone()) | |
577 logicalWidth = std::min(logicalWidth, computeLogicalWidthUsing(MaxSize,
styleToUse.logicalMaxWidth(), availableWidth, cb)); | |
578 return std::max(logicalWidth, computeLogicalWidthUsing(MinSize, styleToUse.l
ogicalMinWidth(), availableWidth, cb)); | |
579 } | |
580 | |
581 LayoutUnit RenderBox::constrainLogicalHeightByMinMax(LayoutUnit logicalHeight, L
ayoutUnit intrinsicContentHeight) const | |
582 { | |
583 const LayoutStyle& styleToUse = styleRef(); | |
584 if (!styleToUse.logicalMaxHeight().isMaxSizeNone()) { | |
585 LayoutUnit maxH = computeLogicalHeightUsing(styleToUse.logicalMaxHeight(
), intrinsicContentHeight); | |
586 if (maxH != -1) | |
587 logicalHeight = std::min(logicalHeight, maxH); | |
588 } | |
589 return std::max(logicalHeight, computeLogicalHeightUsing(styleToUse.logicalM
inHeight(), intrinsicContentHeight)); | |
590 } | |
591 | |
592 LayoutUnit RenderBox::constrainContentBoxLogicalHeightByMinMax(LayoutUnit logica
lHeight, LayoutUnit intrinsicContentHeight) const | |
593 { | |
594 const LayoutStyle& styleToUse = styleRef(); | |
595 if (!styleToUse.logicalMaxHeight().isMaxSizeNone()) { | |
596 LayoutUnit maxH = computeContentLogicalHeight(styleToUse.logicalMaxHeigh
t(), intrinsicContentHeight); | |
597 if (maxH != -1) | |
598 logicalHeight = std::min(logicalHeight, maxH); | |
599 } | |
600 return std::max(logicalHeight, computeContentLogicalHeight(styleToUse.logica
lMinHeight(), intrinsicContentHeight)); | |
601 } | |
602 | |
603 IntRect RenderBox::absoluteContentBox() const | |
604 { | |
605 // This is wrong with transforms and flipped writing modes. | |
606 IntRect rect = pixelSnappedIntRect(contentBoxRect()); | |
607 FloatPoint absPos = localToAbsolute(); | |
608 rect.move(absPos.x(), absPos.y()); | |
609 return rect; | |
610 } | |
611 | |
612 IntSize RenderBox::absoluteContentBoxOffset() const | |
613 { | |
614 IntPoint offset = roundedIntPoint(contentBoxOffset()); | |
615 FloatPoint absPos = localToAbsolute(); | |
616 offset.move(absPos.x(), absPos.y()); | |
617 return toIntSize(offset); | |
618 } | |
619 | |
620 FloatQuad RenderBox::absoluteContentQuad() const | |
621 { | |
622 LayoutRect rect = contentBoxRect(); | |
623 return localToAbsoluteQuad(FloatRect(rect)); | |
624 } | |
625 | |
626 void RenderBox::addFocusRingRects(Vector<LayoutRect>& rects, const LayoutPoint&
additionalOffset) const | |
627 { | |
628 if (!size().isEmpty()) | |
629 rects.append(LayoutRect(additionalOffset, size())); | |
630 } | |
631 | |
632 bool RenderBox::canResize() const | |
633 { | |
634 // We need a special case for <iframe> because they never have | |
635 // hasOverflowClip(). However, they do "implicitly" clip their contents, so | |
636 // we want to allow resizing them also. | |
637 return (hasOverflowClip() || isLayoutIFrame()) && style()->resize() != RESIZ
E_NONE; | |
638 } | |
639 | |
640 void RenderBox::addLayerHitTestRects(LayerHitTestRects& layerRects, const Layer*
currentLayer, const LayoutPoint& layerOffset, const LayoutRect& containerRect)
const | |
641 { | |
642 LayoutPoint adjustedLayerOffset = layerOffset + locationOffset(); | |
643 LayoutBoxModelObject::addLayerHitTestRects(layerRects, currentLayer, adjuste
dLayerOffset, containerRect); | |
644 } | |
645 | |
646 void RenderBox::computeSelfHitTestRects(Vector<LayoutRect>& rects, const LayoutP
oint& layerOffset) const | |
647 { | |
648 if (!size().isEmpty()) | |
649 rects.append(LayoutRect(layerOffset, size())); | |
650 } | |
651 | |
652 int RenderBox::reflectionOffset() const | |
653 { | |
654 if (!style()->boxReflect()) | |
655 return 0; | |
656 if (style()->boxReflect()->direction() == ReflectionLeft || style()->boxRefl
ect()->direction() == ReflectionRight) | |
657 return valueForLength(style()->boxReflect()->offset(), borderBoxRect().w
idth()); | |
658 return valueForLength(style()->boxReflect()->offset(), borderBoxRect().heigh
t()); | |
659 } | |
660 | |
661 LayoutRect RenderBox::reflectedRect(const LayoutRect& r) const | |
662 { | |
663 if (!style()->boxReflect()) | |
664 return LayoutRect(); | |
665 | |
666 LayoutRect box = borderBoxRect(); | |
667 LayoutRect result = r; | |
668 switch (style()->boxReflect()->direction()) { | |
669 case ReflectionBelow: | |
670 result.setY(box.maxY() + reflectionOffset() + (box.maxY() - r.maxY()
)); | |
671 break; | |
672 case ReflectionAbove: | |
673 result.setY(box.y() - reflectionOffset() - box.height() + (box.maxY(
) - r.maxY())); | |
674 break; | |
675 case ReflectionLeft: | |
676 result.setX(box.x() - reflectionOffset() - box.width() + (box.maxX()
- r.maxX())); | |
677 break; | |
678 case ReflectionRight: | |
679 result.setX(box.maxX() + reflectionOffset() + (box.maxX() - r.maxX()
)); | |
680 break; | |
681 } | |
682 return result; | |
683 } | |
684 | |
685 int RenderBox::verticalScrollbarWidth() const | |
686 { | |
687 if (!hasOverflowClip() || style()->overflowY() == OOVERLAY) | |
688 return 0; | |
689 | |
690 return layer()->scrollableArea()->verticalScrollbarWidth(); | |
691 } | |
692 | |
693 int RenderBox::horizontalScrollbarHeight() const | |
694 { | |
695 if (!hasOverflowClip() || style()->overflowX() == OOVERLAY) | |
696 return 0; | |
697 | |
698 return layer()->scrollableArea()->horizontalScrollbarHeight(); | |
699 } | |
700 | |
701 int RenderBox::intrinsicScrollbarLogicalWidth() const | |
702 { | |
703 if (!hasOverflowClip()) | |
704 return 0; | |
705 | |
706 if (isHorizontalWritingMode() && style()->overflowY() == OSCROLL) { | |
707 ASSERT(layer()->scrollableArea() && layer()->scrollableArea()->hasVertic
alScrollbar()); | |
708 return verticalScrollbarWidth(); | |
709 } | |
710 | |
711 if (!isHorizontalWritingMode() && style()->overflowX() == OSCROLL) { | |
712 ASSERT(layer()->scrollableArea() && layer()->scrollableArea()->hasHorizo
ntalScrollbar()); | |
713 return horizontalScrollbarHeight(); | |
714 } | |
715 | |
716 return 0; | |
717 } | |
718 | |
719 bool RenderBox::scroll(ScrollDirection direction, ScrollGranularity granularity,
float delta) | |
720 { | |
721 // Presumably the same issue as in setScrollTop. See crbug.com/343132. | |
722 DisableCompositingQueryAsserts disabler; | |
723 | |
724 // Logical scroll is a higher level concept, all directions by here must be
physical | |
725 ASSERT(!isLogical(direction)); | |
726 | |
727 if (!layer() || !layer()->scrollableArea()) | |
728 return false; | |
729 | |
730 return layer()->scrollableArea()->scroll(direction, granularity, delta); | |
731 } | |
732 | |
733 bool RenderBox::canBeScrolledAndHasScrollableArea() const | |
734 { | |
735 return canBeProgramaticallyScrolled() && (pixelSnappedScrollHeight() != pixe
lSnappedClientHeight() || pixelSnappedScrollWidth() != pixelSnappedClientWidth()
); | |
736 } | |
737 | |
738 bool RenderBox::canBeProgramaticallyScrolled() const | |
739 { | |
740 Node* node = this->node(); | |
741 if (node && node->isDocumentNode()) | |
742 return true; | |
743 | |
744 if (!hasOverflowClip()) | |
745 return false; | |
746 | |
747 bool hasScrollableOverflow = hasScrollableOverflowX() || hasScrollableOverfl
owY(); | |
748 if (scrollsOverflow() && hasScrollableOverflow) | |
749 return true; | |
750 | |
751 return node && node->hasEditableStyle(); | |
752 } | |
753 | |
754 bool RenderBox::usesCompositedScrolling() const | |
755 { | |
756 return hasOverflowClip() && hasLayer() && layer()->scrollableArea()->usesCom
positedScrolling(); | |
757 } | |
758 | |
759 void RenderBox::autoscroll(const IntPoint& position) | |
760 { | |
761 LocalFrame* frame = this->frame(); | |
762 if (!frame) | |
763 return; | |
764 | |
765 FrameView* frameView = frame->view(); | |
766 if (!frameView) | |
767 return; | |
768 | |
769 IntPoint currentDocumentPosition = frameView->windowToContents(position); | |
770 scrollRectToVisible(LayoutRect(currentDocumentPosition, LayoutSize(1, 1)), S
crollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded); | |
771 } | |
772 | |
773 // There are two kinds of renderer that can autoscroll. | |
774 bool RenderBox::canAutoscroll() const | |
775 { | |
776 if (node() && node()->isDocumentNode()) | |
777 return view()->frameView()->isScrollable(); | |
778 | |
779 // Check for a box that can be scrolled in its own right. | |
780 return canBeScrolledAndHasScrollableArea(); | |
781 } | |
782 | |
783 // If specified point is in border belt, returned offset denotes direction of | |
784 // scrolling. | |
785 IntSize RenderBox::calculateAutoscrollDirection(const IntPoint& windowPoint) con
st | |
786 { | |
787 if (!frame()) | |
788 return IntSize(); | |
789 | |
790 FrameView* frameView = frame()->view(); | |
791 if (!frameView) | |
792 return IntSize(); | |
793 | |
794 IntRect box(absoluteBoundingBoxRect()); | |
795 box.move(view()->frameView()->scrollOffset()); | |
796 IntRect windowBox = view()->frameView()->contentsToWindow(box); | |
797 | |
798 IntPoint windowAutoscrollPoint = windowPoint; | |
799 | |
800 if (windowAutoscrollPoint.x() < windowBox.x() + autoscrollBeltSize) | |
801 windowAutoscrollPoint.move(-autoscrollBeltSize, 0); | |
802 else if (windowAutoscrollPoint.x() > windowBox.maxX() - autoscrollBeltSize) | |
803 windowAutoscrollPoint.move(autoscrollBeltSize, 0); | |
804 | |
805 if (windowAutoscrollPoint.y() < windowBox.y() + autoscrollBeltSize) | |
806 windowAutoscrollPoint.move(0, -autoscrollBeltSize); | |
807 else if (windowAutoscrollPoint.y() > windowBox.maxY() - autoscrollBeltSize) | |
808 windowAutoscrollPoint.move(0, autoscrollBeltSize); | |
809 | |
810 return windowAutoscrollPoint - windowPoint; | |
811 } | |
812 | |
813 RenderBox* RenderBox::findAutoscrollable(LayoutObject* renderer) | |
814 { | |
815 while (renderer && !(renderer->isBox() && toRenderBox(renderer)->canAutoscro
ll())) { | |
816 if (!renderer->parent() && renderer->node() == renderer->document() && r
enderer->document().ownerElement()) | |
817 renderer = renderer->document().ownerElement()->renderer(); | |
818 else | |
819 renderer = renderer->parent(); | |
820 } | |
821 | |
822 return renderer && renderer->isBox() ? toRenderBox(renderer) : 0; | |
823 } | |
824 | |
825 static inline int adjustedScrollDelta(int beginningDelta) | |
826 { | |
827 // This implemention matches Firefox's. | |
828 // http://mxr.mozilla.org/firefox/source/toolkit/content/widgets/browser.xml
#856. | |
829 const int speedReducer = 12; | |
830 | |
831 int adjustedDelta = beginningDelta / speedReducer; | |
832 if (adjustedDelta > 1) | |
833 adjustedDelta = static_cast<int>(adjustedDelta * sqrt(static_cast<double
>(adjustedDelta))) - 1; | |
834 else if (adjustedDelta < -1) | |
835 adjustedDelta = static_cast<int>(adjustedDelta * sqrt(static_cast<double
>(-adjustedDelta))) + 1; | |
836 | |
837 return adjustedDelta; | |
838 } | |
839 | |
840 static inline IntSize adjustedScrollDelta(const IntSize& delta) | |
841 { | |
842 return IntSize(adjustedScrollDelta(delta.width()), adjustedScrollDelta(delta
.height())); | |
843 } | |
844 | |
845 void RenderBox::panScroll(const IntPoint& sourcePoint) | |
846 { | |
847 LocalFrame* frame = this->frame(); | |
848 if (!frame) | |
849 return; | |
850 | |
851 IntPoint lastKnownMousePosition = frame->eventHandler().lastKnownMousePositi
on(); | |
852 | |
853 // We need to check if the last known mouse position is out of the window. W
hen the mouse is out of the window, the position is incoherent | |
854 static IntPoint previousMousePosition; | |
855 if (lastKnownMousePosition.x() < 0 || lastKnownMousePosition.y() < 0) | |
856 lastKnownMousePosition = previousMousePosition; | |
857 else | |
858 previousMousePosition = lastKnownMousePosition; | |
859 | |
860 IntSize delta = lastKnownMousePosition - sourcePoint; | |
861 | |
862 if (abs(delta.width()) <= FrameView::noPanScrollRadius) // at the center we
let the space for the icon | |
863 delta.setWidth(0); | |
864 if (abs(delta.height()) <= FrameView::noPanScrollRadius) | |
865 delta.setHeight(0); | |
866 scrollByRecursively(adjustedScrollDelta(delta), ScrollOffsetClamped); | |
867 } | |
868 | |
869 void RenderBox::scrollByRecursively(const DoubleSize& delta, ScrollOffsetClampin
g clamp) | |
870 { | |
871 if (delta.isZero()) | |
872 return; | |
873 | |
874 bool restrictedByLineClamp = false; | |
875 if (parent()) | |
876 restrictedByLineClamp = !parent()->style()->lineClamp().isNone(); | |
877 | |
878 if (hasOverflowClip() && !restrictedByLineClamp) { | |
879 DoubleSize newScrollOffset = layer()->scrollableArea()->adjustedScrollOf
fset() + delta; | |
880 layer()->scrollableArea()->scrollToOffset(newScrollOffset, clamp); | |
881 | |
882 // If this layer can't do the scroll we ask the next layer up that can s
croll to try | |
883 DoubleSize remainingScrollOffset = newScrollOffset - layer()->scrollable
Area()->adjustedScrollOffset(); | |
884 if (!remainingScrollOffset.isZero() && parent()) { | |
885 if (RenderBox* scrollableBox = enclosingScrollableBox()) | |
886 scrollableBox->scrollByRecursively(remainingScrollOffset, clamp)
; | |
887 | |
888 LocalFrame* frame = this->frame(); | |
889 if (frame && frame->page()) | |
890 frame->page()->autoscrollController().updateAutoscrollRenderer()
; | |
891 } | |
892 } else if (view()->frameView()) { | |
893 // If we are here, we were called on a renderer that can be programmatic
ally scrolled, but doesn't | |
894 // have an overflow clip. Which means that it is a document node that ca
n be scrolled. | |
895 // FIXME: Pass in DoubleSize. crbug.com/414283. | |
896 view()->frameView()->scrollBy(flooredIntSize(delta)); | |
897 | |
898 // FIXME: If we didn't scroll the whole way, do we want to try looking a
t the frames ownerElement? | |
899 // https://bugs.webkit.org/show_bug.cgi?id=28237 | |
900 } | |
901 } | |
902 | |
903 bool RenderBox::needsPreferredWidthsRecalculation() const | |
904 { | |
905 return style()->paddingStart().isPercent() || style()->paddingEnd().isPercen
t(); | |
906 } | |
907 | |
908 IntSize RenderBox::scrolledContentOffset() const | |
909 { | |
910 ASSERT(hasOverflowClip()); | |
911 ASSERT(hasLayer()); | |
912 // FIXME: Return DoubleSize here. crbug.com/414283. | |
913 return flooredIntSize(layer()->scrollableArea()->scrollOffset()); | |
914 } | |
915 | |
916 void RenderBox::applyCachedClipAndScrollOffsetForPaintInvalidation(LayoutRect& p
aintRect) const | |
917 { | |
918 ASSERT(hasLayer()); | |
919 ASSERT(hasOverflowClip()); | |
920 | |
921 flipForWritingMode(paintRect); | |
922 paintRect.move(-scrolledContentOffset()); // For overflow:auto/scroll/hidden
. | |
923 | |
924 // Do not clip scroll layer contents because the compositor expects the whol
e layer | |
925 // to be always invalidated in-time. | |
926 if (usesCompositedScrolling()) { | |
927 flipForWritingMode(paintRect); | |
928 return; | |
929 } | |
930 | |
931 // size() is inaccurate if we're in the middle of a layout of this RenderBox
, so use the | |
932 // layer's size instead. Even if the layer's size is wrong, the layer itself
will issue paint invalidations | |
933 // anyway if its size does change. | |
934 LayoutRect clipRect(LayoutPoint(), LayoutSize(layer()->size())); | |
935 paintRect = intersection(paintRect, clipRect); | |
936 flipForWritingMode(paintRect); | |
937 } | |
938 | |
939 void RenderBox::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, Layou
tUnit& maxLogicalWidth) const | |
940 { | |
941 minLogicalWidth = minPreferredLogicalWidth() - borderAndPaddingLogicalWidth(
); | |
942 maxLogicalWidth = maxPreferredLogicalWidth() - borderAndPaddingLogicalWidth(
); | |
943 } | |
944 | |
945 LayoutUnit RenderBox::minPreferredLogicalWidth() const | |
946 { | |
947 if (preferredLogicalWidthsDirty()) { | |
948 #if ENABLE(ASSERT) | |
949 SetLayoutNeededForbiddenScope layoutForbiddenScope(const_cast<RenderBox&
>(*this)); | |
950 #endif | |
951 const_cast<RenderBox*>(this)->computePreferredLogicalWidths(); | |
952 } | |
953 | |
954 return m_minPreferredLogicalWidth; | |
955 } | |
956 | |
957 LayoutUnit RenderBox::maxPreferredLogicalWidth() const | |
958 { | |
959 if (preferredLogicalWidthsDirty()) { | |
960 #if ENABLE(ASSERT) | |
961 SetLayoutNeededForbiddenScope layoutForbiddenScope(const_cast<RenderBox&
>(*this)); | |
962 #endif | |
963 const_cast<RenderBox*>(this)->computePreferredLogicalWidths(); | |
964 } | |
965 | |
966 return m_maxPreferredLogicalWidth; | |
967 } | |
968 | |
969 bool RenderBox::hasOverrideHeight() const | |
970 { | |
971 return m_rareData && m_rareData->m_overrideLogicalContentHeight != -1; | |
972 } | |
973 | |
974 bool RenderBox::hasOverrideWidth() const | |
975 { | |
976 return m_rareData && m_rareData->m_overrideLogicalContentWidth != -1; | |
977 } | |
978 | |
979 void RenderBox::setOverrideLogicalContentHeight(LayoutUnit height) | |
980 { | |
981 ASSERT(height >= 0); | |
982 ensureRareData().m_overrideLogicalContentHeight = height; | |
983 } | |
984 | |
985 void RenderBox::setOverrideLogicalContentWidth(LayoutUnit width) | |
986 { | |
987 ASSERT(width >= 0); | |
988 ensureRareData().m_overrideLogicalContentWidth = width; | |
989 } | |
990 | |
991 void RenderBox::clearOverrideLogicalContentHeight() | |
992 { | |
993 if (m_rareData) | |
994 m_rareData->m_overrideLogicalContentHeight = -1; | |
995 } | |
996 | |
997 void RenderBox::clearOverrideLogicalContentWidth() | |
998 { | |
999 if (m_rareData) | |
1000 m_rareData->m_overrideLogicalContentWidth = -1; | |
1001 } | |
1002 | |
1003 void RenderBox::clearOverrideSize() | |
1004 { | |
1005 clearOverrideLogicalContentHeight(); | |
1006 clearOverrideLogicalContentWidth(); | |
1007 } | |
1008 | |
1009 LayoutUnit RenderBox::overrideLogicalContentWidth() const | |
1010 { | |
1011 ASSERT(hasOverrideWidth()); | |
1012 return m_rareData->m_overrideLogicalContentWidth; | |
1013 } | |
1014 | |
1015 LayoutUnit RenderBox::overrideLogicalContentHeight() const | |
1016 { | |
1017 ASSERT(hasOverrideHeight()); | |
1018 return m_rareData->m_overrideLogicalContentHeight; | |
1019 } | |
1020 | |
1021 LayoutUnit RenderBox::overrideContainingBlockContentLogicalWidth() const | |
1022 { | |
1023 ASSERT(hasOverrideContainingBlockLogicalWidth()); | |
1024 return gOverrideContainingBlockLogicalWidthMap->get(this); | |
1025 } | |
1026 | |
1027 LayoutUnit RenderBox::overrideContainingBlockContentLogicalHeight() const | |
1028 { | |
1029 ASSERT(hasOverrideContainingBlockLogicalHeight()); | |
1030 return gOverrideContainingBlockLogicalHeightMap->get(this); | |
1031 } | |
1032 | |
1033 bool RenderBox::hasOverrideContainingBlockLogicalWidth() const | |
1034 { | |
1035 return gOverrideContainingBlockLogicalWidthMap && gOverrideContainingBlockLo
gicalWidthMap->contains(this); | |
1036 } | |
1037 | |
1038 bool RenderBox::hasOverrideContainingBlockLogicalHeight() const | |
1039 { | |
1040 return gOverrideContainingBlockLogicalHeightMap && gOverrideContainingBlockL
ogicalHeightMap->contains(this); | |
1041 } | |
1042 | |
1043 void RenderBox::setOverrideContainingBlockContentLogicalWidth(LayoutUnit logical
Width) | |
1044 { | |
1045 if (!gOverrideContainingBlockLogicalWidthMap) | |
1046 gOverrideContainingBlockLogicalWidthMap = new OverrideSizeMap; | |
1047 gOverrideContainingBlockLogicalWidthMap->set(this, logicalWidth); | |
1048 } | |
1049 | |
1050 void RenderBox::setOverrideContainingBlockContentLogicalHeight(LayoutUnit logica
lHeight) | |
1051 { | |
1052 if (!gOverrideContainingBlockLogicalHeightMap) | |
1053 gOverrideContainingBlockLogicalHeightMap = new OverrideSizeMap; | |
1054 gOverrideContainingBlockLogicalHeightMap->set(this, logicalHeight); | |
1055 } | |
1056 | |
1057 void RenderBox::clearContainingBlockOverrideSize() | |
1058 { | |
1059 if (gOverrideContainingBlockLogicalWidthMap) | |
1060 gOverrideContainingBlockLogicalWidthMap->remove(this); | |
1061 clearOverrideContainingBlockContentLogicalHeight(); | |
1062 } | |
1063 | |
1064 void RenderBox::clearOverrideContainingBlockContentLogicalHeight() | |
1065 { | |
1066 if (gOverrideContainingBlockLogicalHeightMap) | |
1067 gOverrideContainingBlockLogicalHeightMap->remove(this); | |
1068 } | |
1069 | |
1070 LayoutUnit RenderBox::extraInlineOffset() const | |
1071 { | |
1072 return gExtraInlineOffsetMap ? gExtraInlineOffsetMap->get(this) : LayoutUnit
(); | |
1073 } | |
1074 | |
1075 LayoutUnit RenderBox::extraBlockOffset() const | |
1076 { | |
1077 return gExtraBlockOffsetMap ? gExtraBlockOffsetMap->get(this) : LayoutUnit()
; | |
1078 } | |
1079 | |
1080 void RenderBox::setExtraInlineOffset(LayoutUnit inlineOffest) | |
1081 { | |
1082 if (!gExtraInlineOffsetMap) | |
1083 gExtraInlineOffsetMap = new OverrideSizeMap; | |
1084 gExtraInlineOffsetMap->set(this, inlineOffest); | |
1085 } | |
1086 | |
1087 void RenderBox::setExtraBlockOffset(LayoutUnit blockOffest) | |
1088 { | |
1089 if (!gExtraBlockOffsetMap) | |
1090 gExtraBlockOffsetMap = new OverrideSizeMap; | |
1091 gExtraBlockOffsetMap->set(this, blockOffest); | |
1092 } | |
1093 | |
1094 void RenderBox::clearExtraInlineAndBlockOffests() | |
1095 { | |
1096 if (gExtraInlineOffsetMap) | |
1097 gExtraInlineOffsetMap->remove(this); | |
1098 if (gExtraBlockOffsetMap) | |
1099 gExtraBlockOffsetMap->remove(this); | |
1100 } | |
1101 | |
1102 LayoutUnit RenderBox::adjustBorderBoxLogicalWidthForBoxSizing(LayoutUnit width)
const | |
1103 { | |
1104 LayoutUnit bordersPlusPadding = borderAndPaddingLogicalWidth(); | |
1105 if (style()->boxSizing() == CONTENT_BOX) | |
1106 return width + bordersPlusPadding; | |
1107 return std::max(width, bordersPlusPadding); | |
1108 } | |
1109 | |
1110 LayoutUnit RenderBox::adjustBorderBoxLogicalHeightForBoxSizing(LayoutUnit height
) const | |
1111 { | |
1112 LayoutUnit bordersPlusPadding = borderAndPaddingLogicalHeight(); | |
1113 if (style()->boxSizing() == CONTENT_BOX) | |
1114 return height + bordersPlusPadding; | |
1115 return std::max(height, bordersPlusPadding); | |
1116 } | |
1117 | |
1118 LayoutUnit RenderBox::adjustContentBoxLogicalWidthForBoxSizing(LayoutUnit width)
const | |
1119 { | |
1120 if (style()->boxSizing() == BORDER_BOX) | |
1121 width -= borderAndPaddingLogicalWidth(); | |
1122 return std::max(LayoutUnit(), width); | |
1123 } | |
1124 | |
1125 LayoutUnit RenderBox::adjustContentBoxLogicalHeightForBoxSizing(LayoutUnit heigh
t) const | |
1126 { | |
1127 if (style()->boxSizing() == BORDER_BOX) | |
1128 height -= borderAndPaddingLogicalHeight(); | |
1129 return std::max(LayoutUnit(), height); | |
1130 } | |
1131 | |
1132 // Hit Testing | |
1133 bool RenderBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result
, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffs
et, HitTestAction action) | |
1134 { | |
1135 LayoutPoint adjustedLocation = accumulatedOffset + location(); | |
1136 | |
1137 // Check kids first. | |
1138 for (LayoutObject* child = slowLastChild(); child; child = child->previousSi
bling()) { | |
1139 if ((!child->hasLayer() || !toLayoutBoxModelObject(child)->layer()->isSe
lfPaintingLayer()) && child->nodeAtPoint(request, result, locationInContainer, a
djustedLocation, action)) { | |
1140 updateHitTestResult(result, locationInContainer.point() - toLayoutSi
ze(adjustedLocation)); | |
1141 return true; | |
1142 } | |
1143 } | |
1144 | |
1145 // Check our bounds next. For this purpose always assume that we can only be
hit in the | |
1146 // foreground phase (which is true for replaced elements like images). | |
1147 LayoutRect boundsRect = borderBoxRect(); | |
1148 boundsRect.moveBy(adjustedLocation); | |
1149 if (visibleToHitTestRequest(request) && action == HitTestForeground && locat
ionInContainer.intersects(boundsRect)) { | |
1150 updateHitTestResult(result, locationInContainer.point() - toLayoutSize(a
djustedLocation)); | |
1151 if (!result.addNodeToListBasedTestResult(node(), request, locationInCont
ainer, boundsRect)) | |
1152 return true; | |
1153 } | |
1154 | |
1155 return false; | |
1156 } | |
1157 | |
1158 void RenderBox::paint(const PaintInfo& paintInfo, const LayoutPoint& paintOffset
) | |
1159 { | |
1160 BoxPainter(*this).paint(paintInfo, paintOffset); | |
1161 } | |
1162 | |
1163 | |
1164 void RenderBox::paintBoxDecorationBackground(const PaintInfo& paintInfo, const L
ayoutPoint& paintOffset) | |
1165 { | |
1166 BoxPainter(*this).paintBoxDecorationBackground(paintInfo, paintOffset); | |
1167 } | |
1168 | |
1169 | |
1170 bool RenderBox::getBackgroundPaintedExtent(LayoutRect& paintedExtent) | |
1171 { | |
1172 ASSERT(hasBackground()); | |
1173 LayoutRect backgroundRect = pixelSnappedIntRect(borderBoxRect()); | |
1174 | |
1175 Color backgroundColor = resolveColor(CSSPropertyBackgroundColor); | |
1176 if (backgroundColor.alpha()) { | |
1177 paintedExtent = backgroundRect; | |
1178 return true; | |
1179 } | |
1180 | |
1181 if (!style()->backgroundLayers().image() || style()->backgroundLayers().next
()) { | |
1182 paintedExtent = backgroundRect; | |
1183 return true; | |
1184 } | |
1185 | |
1186 BackgroundImageGeometry geometry; | |
1187 BoxPainter::calculateBackgroundImageGeometry(*this, 0, style()->backgroundLa
yers(), backgroundRect, geometry); | |
1188 if (geometry.hasNonLocalGeometry()) | |
1189 return false; | |
1190 paintedExtent = geometry.destRect(); | |
1191 return true; | |
1192 } | |
1193 | |
1194 bool RenderBox::backgroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect) c
onst | |
1195 { | |
1196 if (isBody() && skipBodyBackground(this)) | |
1197 return false; | |
1198 | |
1199 Color backgroundColor = resolveColor(CSSPropertyBackgroundColor); | |
1200 if (backgroundColor.hasAlpha()) | |
1201 return false; | |
1202 | |
1203 // If the element has appearance, it might be painted by theme. | |
1204 // We cannot be sure if theme paints the background opaque. | |
1205 // In this case it is safe to not assume opaqueness. | |
1206 // FIXME: May be ask theme if it paints opaque. | |
1207 if (style()->hasAppearance()) | |
1208 return false; | |
1209 // FIXME: Check the opaqueness of background images. | |
1210 | |
1211 // FIXME: Use rounded rect if border radius is present. | |
1212 if (style()->hasBorderRadius()) | |
1213 return false; | |
1214 // FIXME: The background color clip is defined by the last layer. | |
1215 if (style()->backgroundLayers().next()) | |
1216 return false; | |
1217 LayoutRect backgroundRect; | |
1218 switch (style()->backgroundClip()) { | |
1219 case BorderFillBox: | |
1220 backgroundRect = borderBoxRect(); | |
1221 break; | |
1222 case PaddingFillBox: | |
1223 backgroundRect = paddingBoxRect(); | |
1224 break; | |
1225 case ContentFillBox: | |
1226 backgroundRect = contentBoxRect(); | |
1227 break; | |
1228 default: | |
1229 break; | |
1230 } | |
1231 return backgroundRect.contains(localRect); | |
1232 } | |
1233 | |
1234 static bool isCandidateForOpaquenessTest(const RenderBox& childBox) | |
1235 { | |
1236 const LayoutStyle& childStyle = childBox.styleRef(); | |
1237 if (childStyle.position() != StaticPosition && childBox.containingBlock() !=
childBox.parent()) | |
1238 return false; | |
1239 if (childStyle.visibility() != VISIBLE || childStyle.shapeOutside()) | |
1240 return false; | |
1241 if (childBox.size().isZero()) | |
1242 return false; | |
1243 if (Layer* childLayer = childBox.layer()) { | |
1244 // FIXME: perhaps this could be less conservative? | |
1245 if (childLayer->compositingState() != NotComposited) | |
1246 return false; | |
1247 // FIXME: Deal with z-index. | |
1248 if (!childStyle.hasAutoZIndex()) | |
1249 return false; | |
1250 if (childLayer->hasTransformRelatedProperty() || childLayer->isTranspare
nt() || childLayer->hasFilter()) | |
1251 return false; | |
1252 if (childBox.hasOverflowClip() && childStyle.hasBorderRadius()) | |
1253 return false; | |
1254 } | |
1255 return true; | |
1256 } | |
1257 | |
1258 bool RenderBox::foregroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect, u
nsigned maxDepthToTest) const | |
1259 { | |
1260 if (!maxDepthToTest) | |
1261 return false; | |
1262 for (LayoutObject* child = slowFirstChild(); child; child = child->nextSibli
ng()) { | |
1263 if (!child->isBox()) | |
1264 continue; | |
1265 RenderBox* childBox = toRenderBox(child); | |
1266 if (!isCandidateForOpaquenessTest(*childBox)) | |
1267 continue; | |
1268 LayoutPoint childLocation = childBox->location(); | |
1269 if (childBox->isRelPositioned()) | |
1270 childLocation.move(childBox->relativePositionOffset()); | |
1271 LayoutRect childLocalRect = localRect; | |
1272 childLocalRect.moveBy(-childLocation); | |
1273 if (childLocalRect.y() < 0 || childLocalRect.x() < 0) { | |
1274 // If there is unobscured area above/left of a static positioned box
then the rect is probably not covered. | |
1275 if (childBox->style()->position() == StaticPosition) | |
1276 return false; | |
1277 continue; | |
1278 } | |
1279 if (childLocalRect.maxY() > childBox->size().height() || childLocalRect.
maxX() > childBox->size().width()) | |
1280 continue; | |
1281 if (childBox->backgroundIsKnownToBeOpaqueInRect(childLocalRect)) | |
1282 return true; | |
1283 if (childBox->foregroundIsKnownToBeOpaqueInRect(childLocalRect, maxDepth
ToTest - 1)) | |
1284 return true; | |
1285 } | |
1286 return false; | |
1287 } | |
1288 | |
1289 bool RenderBox::computeBackgroundIsKnownToBeObscured() | |
1290 { | |
1291 // Test to see if the children trivially obscure the background. | |
1292 // FIXME: This test can be much more comprehensive. | |
1293 if (!hasBackground()) | |
1294 return false; | |
1295 // Table and root background painting is special. | |
1296 if (isTable() || isDocumentElement()) | |
1297 return false; | |
1298 // FIXME: box-shadow is painted while background painting. | |
1299 if (style()->boxShadow()) | |
1300 return false; | |
1301 LayoutRect backgroundRect; | |
1302 if (!getBackgroundPaintedExtent(backgroundRect)) | |
1303 return false; | |
1304 return foregroundIsKnownToBeOpaqueInRect(backgroundRect, backgroundObscurati
onTestMaxDepth); | |
1305 } | |
1306 | |
1307 bool RenderBox::backgroundHasOpaqueTopLayer() const | |
1308 { | |
1309 const FillLayer& fillLayer = style()->backgroundLayers(); | |
1310 if (fillLayer.clip() != BorderFillBox) | |
1311 return false; | |
1312 | |
1313 // Clipped with local scrolling | |
1314 if (hasOverflowClip() && fillLayer.attachment() == LocalBackgroundAttachment
) | |
1315 return false; | |
1316 | |
1317 if (fillLayer.hasOpaqueImage(this) && fillLayer.hasRepeatXY() && fillLayer.i
mage()->canRender(*this, style()->effectiveZoom())) | |
1318 return true; | |
1319 | |
1320 // If there is only one layer and no image, check whether the background col
or is opaque | |
1321 if (!fillLayer.next() && !fillLayer.hasImage()) { | |
1322 Color bgColor = resolveColor(CSSPropertyBackgroundColor); | |
1323 if (bgColor.alpha() == 255) | |
1324 return true; | |
1325 } | |
1326 | |
1327 return false; | |
1328 } | |
1329 | |
1330 void RenderBox::paintMask(const PaintInfo& paintInfo, const LayoutPoint& paintOf
fset) | |
1331 { | |
1332 BoxPainter(*this).paintMask(paintInfo, paintOffset); | |
1333 } | |
1334 | |
1335 void RenderBox::paintClippingMask(const PaintInfo& paintInfo, const LayoutPoint&
paintOffset) | |
1336 { | |
1337 BoxPainter(*this).paintClippingMask(paintInfo, paintOffset); | |
1338 } | |
1339 | |
1340 void RenderBox::imageChanged(WrappedImagePtr image, const IntRect*) | |
1341 { | |
1342 if (!parent()) | |
1343 return; | |
1344 | |
1345 if ((style()->borderImage().image() && style()->borderImage().image()->data(
) == image) || | |
1346 (style()->maskBoxImage().image() && style()->maskBoxImage().image()->dat
a() == image)) { | |
1347 setShouldDoFullPaintInvalidation(); | |
1348 return; | |
1349 } | |
1350 | |
1351 ShapeValue* shapeOutsideValue = style()->shapeOutside(); | |
1352 if (!frameView()->isInPerformLayout() && isFloating() && shapeOutsideValue &
& shapeOutsideValue->image() && shapeOutsideValue->image()->data() == image) { | |
1353 ShapeOutsideInfo& info = ShapeOutsideInfo::ensureInfo(*this); | |
1354 if (!info.isComputingShape()) { | |
1355 info.markShapeAsDirty(); | |
1356 markShapeOutsideDependentsForLayout(); | |
1357 } | |
1358 } | |
1359 | |
1360 if (!paintInvalidationLayerRectsForImage(image, style()->backgroundLayers(),
true)) | |
1361 paintInvalidationLayerRectsForImage(image, style()->maskLayers(), false)
; | |
1362 } | |
1363 | |
1364 bool RenderBox::paintInvalidationLayerRectsForImage(WrappedImagePtr image, const
FillLayer& layers, bool drawingBackground) | |
1365 { | |
1366 Vector<LayoutObject*> layerRenderers; | |
1367 | |
1368 // A background of the body or document must extend to the total visible siz
e of the document. This means the union of the | |
1369 // view and document bounds, since it can be the case that the view is large
r than the document and vice-versa. | |
1370 // http://dev.w3.org/csswg/css-backgrounds/#the-background | |
1371 if (drawingBackground && (isDocumentElement() || (isBody() && !document().do
cumentElement()->renderer()->hasBackground()))) { | |
1372 layerRenderers.append(document().documentElement()->renderer()); | |
1373 layerRenderers.append(view()); | |
1374 if (view()->frameView()) | |
1375 view()->frameView()->setNeedsFullPaintInvalidation(); | |
1376 } else { | |
1377 layerRenderers.append(this); | |
1378 } | |
1379 for (const FillLayer* curLayer = &layers; curLayer; curLayer = curLayer->nex
t()) { | |
1380 if (curLayer->image() && image == curLayer->image()->data() && curLayer-
>image()->canRender(*this, style()->effectiveZoom())) { | |
1381 for (LayoutObject* layerRenderer : layerRenderers) | |
1382 layerRenderer->setShouldDoFullPaintInvalidation(); | |
1383 return true; | |
1384 } | |
1385 } | |
1386 return false; | |
1387 } | |
1388 | |
1389 PaintInvalidationReason RenderBox::invalidatePaintIfNeeded(const PaintInvalidati
onState& paintInvalidationState, const LayoutBoxModelObject& newPaintInvalidatio
nContainer) | |
1390 { | |
1391 PaintInvalidationReason reason = LayoutBoxModelObject::invalidatePaintIfNeed
ed(paintInvalidationState, newPaintInvalidationContainer); | |
1392 | |
1393 // If we are set to do a full paint invalidation that means the RenderView w
ill be | |
1394 // issue paint invalidations. We can then skip issuing of paint invalidation
s for the child | |
1395 // renderers as they'll be covered by the RenderView. | |
1396 if (!view()->doingFullPaintInvalidation() && !isFullPaintInvalidationReason(
reason)) { | |
1397 invalidatePaintForOverflowIfNeeded(); | |
1398 | |
1399 // Issue paint invalidations for any scrollbars if there is a scrollable
area for this renderer. | |
1400 if (ScrollableArea* area = scrollableArea()) { | |
1401 if (area->hasVerticalBarDamage()) | |
1402 invalidatePaintRectangle(area->verticalBarDamage()); | |
1403 if (area->hasHorizontalBarDamage()) | |
1404 invalidatePaintRectangle(area->horizontalBarDamage()); | |
1405 } | |
1406 } | |
1407 | |
1408 // This is for the next invalidatePaintIfNeeded so must be at the end. | |
1409 savePreviousBorderBoxSizeIfNeeded(); | |
1410 return reason; | |
1411 } | |
1412 | |
1413 void RenderBox::clearPaintInvalidationState(const PaintInvalidationState& paintI
nvalidationState) | |
1414 { | |
1415 LayoutBoxModelObject::clearPaintInvalidationState(paintInvalidationState); | |
1416 | |
1417 if (ScrollableArea* area = scrollableArea()) | |
1418 area->resetScrollbarDamage(); | |
1419 } | |
1420 | |
1421 #if ENABLE(ASSERT) | |
1422 bool RenderBox::paintInvalidationStateIsDirty() const | |
1423 { | |
1424 if (ScrollableArea* area = scrollableArea()) { | |
1425 if (area->hasVerticalBarDamage() || area->hasHorizontalBarDamage()) | |
1426 return true; | |
1427 } | |
1428 return LayoutBoxModelObject::paintInvalidationStateIsDirty(); | |
1429 } | |
1430 #endif | |
1431 | |
1432 LayoutRect RenderBox::overflowClipRect(const LayoutPoint& location, OverlayScrol
lbarSizeRelevancy relevancy) | |
1433 { | |
1434 // FIXME: When overflow-clip (CSS3) is implemented, we'll obtain the propert
y | |
1435 // here. | |
1436 LayoutRect clipRect = borderBoxRect(); | |
1437 clipRect.setLocation(location + clipRect.location() + LayoutSize(borderLeft(
), borderTop())); | |
1438 clipRect.setSize(clipRect.size() - LayoutSize(borderLeft() + borderRight(),
borderTop() + borderBottom())); | |
1439 | |
1440 if (!hasOverflowClip()) | |
1441 return clipRect; | |
1442 | |
1443 // Subtract out scrollbars if we have them. | |
1444 if (style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) | |
1445 clipRect.move(layer()->scrollableArea()->verticalScrollbarWidth(relevanc
y), 0); | |
1446 clipRect.contract(layer()->scrollableArea()->verticalScrollbarWidth(relevanc
y), layer()->scrollableArea()->horizontalScrollbarHeight(relevancy)); | |
1447 | |
1448 return clipRect; | |
1449 } | |
1450 | |
1451 LayoutRect RenderBox::clipRect(const LayoutPoint& location) | |
1452 { | |
1453 LayoutRect borderBoxRect = this->borderBoxRect(); | |
1454 LayoutRect clipRect = LayoutRect(borderBoxRect.location() + location, border
BoxRect.size()); | |
1455 | |
1456 if (!style()->clipLeft().isAuto()) { | |
1457 LayoutUnit c = valueForLength(style()->clipLeft(), borderBoxRect.width()
); | |
1458 clipRect.move(c, 0); | |
1459 clipRect.contract(c, 0); | |
1460 } | |
1461 | |
1462 if (!style()->clipRight().isAuto()) | |
1463 clipRect.contract(size().width() - valueForLength(style()->clipRight(),
size().width()), 0); | |
1464 | |
1465 if (!style()->clipTop().isAuto()) { | |
1466 LayoutUnit c = valueForLength(style()->clipTop(), borderBoxRect.height()
); | |
1467 clipRect.move(0, c); | |
1468 clipRect.contract(0, c); | |
1469 } | |
1470 | |
1471 if (!style()->clipBottom().isAuto()) | |
1472 clipRect.contract(0, size().height() - valueForLength(style()->clipBotto
m(), size().height())); | |
1473 | |
1474 return clipRect; | |
1475 } | |
1476 | |
1477 static LayoutUnit portionOfMarginNotConsumedByFloat(LayoutUnit childMargin, Layo
utUnit contentSide, LayoutUnit offset) | |
1478 { | |
1479 if (childMargin <= 0) | |
1480 return LayoutUnit(); | |
1481 LayoutUnit contentSideWithMargin = contentSide + childMargin; | |
1482 if (offset > contentSideWithMargin) | |
1483 return childMargin; | |
1484 return offset - contentSide; | |
1485 } | |
1486 | |
1487 LayoutUnit RenderBox::shrinkLogicalWidthToAvoidFloats(LayoutUnit childMarginStar
t, LayoutUnit childMarginEnd, const RenderBlockFlow* cb) const | |
1488 { | |
1489 LayoutUnit logicalTopPosition = logicalTop(); | |
1490 LayoutUnit startOffsetForContent = cb->startOffsetForContent(); | |
1491 LayoutUnit endOffsetForContent = cb->endOffsetForContent(); | |
1492 LayoutUnit logicalHeight = cb->logicalHeightForChild(*this); | |
1493 LayoutUnit startOffsetForLine = cb->startOffsetForLine(logicalTopPosition, f
alse, logicalHeight); | |
1494 LayoutUnit endOffsetForLine = cb->endOffsetForLine(logicalTopPosition, false
, logicalHeight); | |
1495 | |
1496 // If there aren't any floats constraining us then allow the margins to shri
nk/expand the width as much as they want. | |
1497 if (startOffsetForContent == startOffsetForLine && endOffsetForContent == en
dOffsetForLine) | |
1498 return cb->availableLogicalWidthForLine(logicalTopPosition, false, logic
alHeight) - childMarginStart - childMarginEnd; | |
1499 | |
1500 LayoutUnit width = cb->availableLogicalWidthForLine(logicalTopPosition, fals
e, logicalHeight) - std::max(LayoutUnit(), childMarginStart) - std::max(LayoutUn
it(), childMarginEnd); | |
1501 // We need to see if margins on either the start side or the end side can co
ntain the floats in question. If they can, | |
1502 // then just using the line width is inaccurate. In the case where a float c
ompletely fits, we don't need to use the line | |
1503 // offset at all, but can instead push all the way to the content edge of th
e containing block. In the case where the float | |
1504 // doesn't fit, we can use the line offset, but we need to grow it by the ma
rgin to reflect the fact that the margin was | |
1505 // "consumed" by the float. Negative margins aren't consumed by the float, a
nd so we ignore them. | |
1506 width += portionOfMarginNotConsumedByFloat(childMarginStart, startOffsetForC
ontent, startOffsetForLine); | |
1507 width += portionOfMarginNotConsumedByFloat(childMarginEnd, endOffsetForConte
nt, endOffsetForLine); | |
1508 return width; | |
1509 } | |
1510 | |
1511 LayoutUnit RenderBox::containingBlockLogicalWidthForContent() const | |
1512 { | |
1513 if (hasOverrideContainingBlockLogicalWidth()) | |
1514 return overrideContainingBlockContentLogicalWidth(); | |
1515 | |
1516 RenderBlock* cb = containingBlock(); | |
1517 return cb->availableLogicalWidth(); | |
1518 } | |
1519 | |
1520 LayoutUnit RenderBox::containingBlockLogicalHeightForContent(AvailableLogicalHei
ghtType heightType) const | |
1521 { | |
1522 if (hasOverrideContainingBlockLogicalHeight()) | |
1523 return overrideContainingBlockContentLogicalHeight(); | |
1524 | |
1525 RenderBlock* cb = containingBlock(); | |
1526 return cb->availableLogicalHeight(heightType); | |
1527 } | |
1528 | |
1529 LayoutUnit RenderBox::containingBlockAvailableLineWidth() const | |
1530 { | |
1531 RenderBlock* cb = containingBlock(); | |
1532 if (cb->isRenderBlockFlow()) | |
1533 return toRenderBlockFlow(cb)->availableLogicalWidthForLine(logicalTop(),
false, availableLogicalHeight(IncludeMarginBorderPadding)); | |
1534 return LayoutUnit(); | |
1535 } | |
1536 | |
1537 LayoutUnit RenderBox::perpendicularContainingBlockLogicalHeight() const | |
1538 { | |
1539 if (hasOverrideContainingBlockLogicalHeight()) | |
1540 return overrideContainingBlockContentLogicalHeight(); | |
1541 | |
1542 RenderBlock* cb = containingBlock(); | |
1543 if (cb->hasOverrideHeight()) | |
1544 return cb->overrideLogicalContentHeight(); | |
1545 | |
1546 const LayoutStyle& containingBlockStyle = cb->styleRef(); | |
1547 Length logicalHeightLength = containingBlockStyle.logicalHeight(); | |
1548 | |
1549 // FIXME: For now just support fixed heights. Eventually should support per
centage heights as well. | |
1550 if (!logicalHeightLength.isFixed()) { | |
1551 LayoutUnit fillFallbackExtent = containingBlockStyle.isHorizontalWriting
Mode() | |
1552 ? view()->frameView()->unscaledVisibleContentSize().height() | |
1553 : view()->frameView()->unscaledVisibleContentSize().width(); | |
1554 LayoutUnit fillAvailableExtent = containingBlock()->availableLogicalHeig
ht(ExcludeMarginBorderPadding); | |
1555 return std::min(fillAvailableExtent, fillFallbackExtent); | |
1556 } | |
1557 | |
1558 // Use the content box logical height as specified by the style. | |
1559 return cb->adjustContentBoxLogicalHeightForBoxSizing(logicalHeightLength.val
ue()); | |
1560 } | |
1561 | |
1562 void RenderBox::mapLocalToContainer(const LayoutBoxModelObject* paintInvalidatio
nContainer, TransformState& transformState, MapCoordinatesFlags mode, bool* wasF
ixed, const PaintInvalidationState* paintInvalidationState) const | |
1563 { | |
1564 if (paintInvalidationContainer == this) | |
1565 return; | |
1566 | |
1567 if (paintInvalidationState && paintInvalidationState->canMapToContainer(pain
tInvalidationContainer)) { | |
1568 LayoutSize offset = paintInvalidationState->paintOffset() + locationOffs
et(); | |
1569 if (style()->hasInFlowPosition() && layer()) | |
1570 offset += layer()->offsetForInFlowPosition(); | |
1571 transformState.move(offset); | |
1572 return; | |
1573 } | |
1574 | |
1575 bool containerSkipped; | |
1576 LayoutObject* o = container(paintInvalidationContainer, &containerSkipped); | |
1577 if (!o) | |
1578 return; | |
1579 | |
1580 bool isFixedPos = style()->position() == FixedPosition; | |
1581 bool hasTransform = hasLayer() && layer()->transform(); | |
1582 // If this box has a transform, it acts as a fixed position container for fi
xed descendants, | |
1583 // and may itself also be fixed position. So propagate 'fixed' up only if th
is box is fixed position. | |
1584 if (hasTransform && !isFixedPos) | |
1585 mode &= ~IsFixed; | |
1586 else if (isFixedPos) | |
1587 mode |= IsFixed; | |
1588 | |
1589 if (wasFixed) | |
1590 *wasFixed = mode & IsFixed; | |
1591 | |
1592 LayoutSize containerOffset = offsetFromContainer(o, roundedLayoutPoint(trans
formState.mappedPoint())); | |
1593 | |
1594 bool preserve3D = mode & UseTransforms && (o->style()->preserves3D() || styl
e()->preserves3D()); | |
1595 if (mode & UseTransforms && shouldUseTransformFromContainer(o)) { | |
1596 TransformationMatrix t; | |
1597 getTransformFromContainer(o, containerOffset, t); | |
1598 transformState.applyTransform(t, preserve3D ? TransformState::Accumulate
Transform : TransformState::FlattenTransform); | |
1599 } else | |
1600 transformState.move(containerOffset.width(), containerOffset.height(), p
reserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransfo
rm); | |
1601 | |
1602 if (containerSkipped) { | |
1603 // There can't be a transform between paintInvalidationContainer and o,
because transforms create containers, so it should be safe | |
1604 // to just subtract the delta between the paintInvalidationContainer and
o. | |
1605 LayoutSize containerOffset = paintInvalidationContainer->offsetFromAnces
torContainer(o); | |
1606 transformState.move(-containerOffset.width(), -containerOffset.height(),
preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTrans
form); | |
1607 return; | |
1608 } | |
1609 | |
1610 mode &= ~ApplyContainerFlip; | |
1611 | |
1612 o->mapLocalToContainer(paintInvalidationContainer, transformState, mode, was
Fixed); | |
1613 } | |
1614 | |
1615 void RenderBox::mapAbsoluteToLocalPoint(MapCoordinatesFlags mode, TransformState
& transformState) const | |
1616 { | |
1617 bool isFixedPos = style()->position() == FixedPosition; | |
1618 bool hasTransform = hasLayer() && layer()->transform(); | |
1619 if (hasTransform && !isFixedPos) { | |
1620 // If this box has a transform, it acts as a fixed position container fo
r fixed descendants, | |
1621 // and may itself also be fixed position. So propagate 'fixed' up only i
f this box is fixed position. | |
1622 mode &= ~IsFixed; | |
1623 } else if (isFixedPos) | |
1624 mode |= IsFixed; | |
1625 | |
1626 LayoutBoxModelObject::mapAbsoluteToLocalPoint(mode, transformState); | |
1627 } | |
1628 | |
1629 LayoutSize RenderBox::offsetFromContainer(const LayoutObject* o, const LayoutPoi
nt& point, bool* offsetDependsOnPoint) const | |
1630 { | |
1631 ASSERT(o == container()); | |
1632 | |
1633 LayoutSize offset; | |
1634 if (isRelPositioned()) | |
1635 offset += offsetForInFlowPosition(); | |
1636 | |
1637 if (!isInline() || isReplaced()) { | |
1638 if (!style()->hasOutOfFlowPosition() && o->hasColumns()) { | |
1639 const RenderBlock* block = toRenderBlock(o); | |
1640 LayoutRect columnRect(frameRect()); | |
1641 block->adjustStartEdgeForWritingModeIncludingColumns(columnRect); | |
1642 offset += toSize(columnRect.location()); | |
1643 LayoutPoint columnPoint = block->flipForWritingModeIncludingColumns(
point + offset); | |
1644 offset = toLayoutSize(block->flipForWritingModeIncludingColumns(toLa
youtPoint(offset))); | |
1645 offset += o->columnOffset(columnPoint); | |
1646 offset = block->flipForWritingMode(offset); | |
1647 | |
1648 if (offsetDependsOnPoint) | |
1649 *offsetDependsOnPoint = true; | |
1650 } else { | |
1651 offset += topLeftLocationOffset(); | |
1652 if (o->isLayoutFlowThread()) { | |
1653 // So far the point has been in flow thread coordinates (i.e. as
if everything in | |
1654 // the fragmentation context lived in one tall single column). C
onvert it to a | |
1655 // visual point now. | |
1656 LayoutPoint pointInContainer = point + offset; | |
1657 offset += o->columnOffset(pointInContainer); | |
1658 if (offsetDependsOnPoint) | |
1659 *offsetDependsOnPoint = true; | |
1660 } | |
1661 } | |
1662 } | |
1663 | |
1664 if (o->hasOverflowClip()) | |
1665 offset -= toRenderBox(o)->scrolledContentOffset(); | |
1666 | |
1667 if (style()->position() == AbsolutePosition && o->isRelPositioned() && o->is
RenderInline()) | |
1668 offset += toRenderInline(o)->offsetForInFlowPositionedInline(*this); | |
1669 | |
1670 return offset; | |
1671 } | |
1672 | |
1673 InlineBox* RenderBox::createInlineBox() | |
1674 { | |
1675 return new InlineBox(*this); | |
1676 } | |
1677 | |
1678 void RenderBox::dirtyLineBoxes(bool fullLayout) | |
1679 { | |
1680 if (inlineBoxWrapper()) { | |
1681 if (fullLayout) { | |
1682 inlineBoxWrapper()->destroy(); | |
1683 ASSERT(m_rareData); | |
1684 m_rareData->m_inlineBoxWrapper = 0; | |
1685 } else { | |
1686 inlineBoxWrapper()->dirtyLineBoxes(); | |
1687 } | |
1688 } | |
1689 } | |
1690 | |
1691 void RenderBox::positionLineBox(InlineBox* box) | |
1692 { | |
1693 if (isOutOfFlowPositioned()) { | |
1694 // Cache the x position only if we were an INLINE type originally. | |
1695 bool originallyInline = style()->isOriginalDisplayInlineType(); | |
1696 if (originallyInline) { | |
1697 // The value is cached in the xPos of the box. We only need this va
lue if | |
1698 // our object was inline originally, since otherwise it would have e
nded up underneath | |
1699 // the inlines. | |
1700 RootInlineBox& root = box->root(); | |
1701 root.block().setStaticInlinePositionForChild(*this, LayoutUnit::from
FloatRound(box->logicalLeft())); | |
1702 } else { | |
1703 // Our object was a block originally, so we make our normal flow pos
ition be | |
1704 // just below the line box (as though all the inlines that came befo
re us got | |
1705 // wrapped in an anonymous block, which is what would have happened
had we been | |
1706 // in flow). This value was cached in the y() of the box. | |
1707 layer()->setStaticBlockPosition(box->logicalTop()); | |
1708 } | |
1709 markStaticPositionedBoxForLayout(box->isHorizontal(), originallyInline); | |
1710 | |
1711 if (container()->isRenderInline()) | |
1712 moveWithEdgeOfInlineContainerIfNecessary(box->isHorizontal()); | |
1713 | |
1714 // Nuke the box. | |
1715 box->remove(DontMarkLineBoxes); | |
1716 box->destroy(); | |
1717 } else if (isReplaced()) { | |
1718 // FIXME: the call to roundedLayoutPoint() below is temporary and should
be removed once | |
1719 // the transition to LayoutUnit-based types is complete (crbug.com/32123
7) | |
1720 setLocation(box->topLeft().roundedLayoutPoint()); | |
1721 setInlineBoxWrapper(box); | |
1722 } | |
1723 } | |
1724 | |
1725 void RenderBox::markStaticPositionedBoxForLayout(bool isHorizontal, bool isInlin
e) | |
1726 { | |
1727 ASSERT(isOutOfFlowPositioned()); | |
1728 if (normalChildNeedsLayout()) | |
1729 return; | |
1730 if (isInline ? style()->hasStaticInlinePosition(isHorizontal) : style()->has
StaticBlockPosition(isHorizontal)) | |
1731 setChildNeedsLayout(MarkOnlyThis); | |
1732 } | |
1733 | |
1734 void RenderBox::moveWithEdgeOfInlineContainerIfNecessary(bool isHorizontal) | |
1735 { | |
1736 ASSERT(isOutOfFlowPositioned() && container()->isRenderInline() && container
()->isRelPositioned()); | |
1737 // If this object is inside a relative positioned inline and its inline posi
tion is an explicit offset from the edge of its container | |
1738 // then it will need to move if its inline container has changed width. We d
o not track if the width has changed | |
1739 // but if we are here then we are laying out lines inside it, so it probably
has - mark our object for layout so that it can | |
1740 // move to the new offset created by the new width. | |
1741 if (!normalChildNeedsLayout() && !style()->hasStaticInlinePosition(isHorizon
tal)) | |
1742 setChildNeedsLayout(MarkOnlyThis); | |
1743 } | |
1744 | |
1745 void RenderBox::deleteLineBoxWrapper() | |
1746 { | |
1747 if (inlineBoxWrapper()) { | |
1748 if (!documentBeingDestroyed()) | |
1749 inlineBoxWrapper()->remove(); | |
1750 inlineBoxWrapper()->destroy(); | |
1751 ASSERT(m_rareData); | |
1752 m_rareData->m_inlineBoxWrapper = 0; | |
1753 } | |
1754 } | |
1755 | |
1756 void RenderBox::setSpannerPlaceholder(LayoutMultiColumnSpannerPlaceholder& place
holder) | |
1757 { | |
1758 RELEASE_ASSERT(!m_rareData || !m_rareData->m_spannerPlaceholder); // not exp
ected to change directly from one spanner to another. | |
1759 ensureRareData().m_spannerPlaceholder = &placeholder; | |
1760 } | |
1761 | |
1762 void RenderBox::clearSpannerPlaceholder() | |
1763 { | |
1764 if (!m_rareData) | |
1765 return; | |
1766 m_rareData->m_spannerPlaceholder = 0; | |
1767 } | |
1768 | |
1769 LayoutRect RenderBox::clippedOverflowRectForPaintInvalidation(const LayoutBoxMod
elObject* paintInvalidationContainer, const PaintInvalidationState* paintInvalid
ationState) const | |
1770 { | |
1771 if (style()->visibility() != VISIBLE) { | |
1772 Layer* layer = enclosingLayer(); | |
1773 layer->updateDescendantDependentFlags(); | |
1774 if (layer->subtreeIsInvisible()) | |
1775 return LayoutRect(); | |
1776 } | |
1777 | |
1778 LayoutRect r = visualOverflowRect(); | |
1779 mapRectToPaintInvalidationBacking(paintInvalidationContainer, r, paintInvali
dationState); | |
1780 return r; | |
1781 } | |
1782 | |
1783 void RenderBox::mapRectToPaintInvalidationBacking(const LayoutBoxModelObject* pa
intInvalidationContainer, LayoutRect& rect, const PaintInvalidationState* paintI
nvalidationState) const | |
1784 { | |
1785 // The rect we compute at each step is shifted by our x/y offset in the pare
nt container's coordinate space. | |
1786 // Only when we cross a writing mode boundary will we have to possibly flipF
orWritingMode (to convert into a more appropriate | |
1787 // offset corner for the enclosing container). This allows for a fully RL or
BT document to issue paint invalidations | |
1788 // properly even during layout, since the rect remains flipped all the way u
ntil the end. | |
1789 // | |
1790 // RenderView::computeRectForPaintInvalidation then converts the rect to phy
sical coordinates. We also convert to | |
1791 // physical when we hit a paintInvalidationContainer boundary. Therefore the
final rect returned is always in the | |
1792 // physical coordinate space of the paintInvalidationContainer. | |
1793 const LayoutStyle& styleToUse = styleRef(); | |
1794 | |
1795 EPosition position = styleToUse.position(); | |
1796 | |
1797 // We need to inflate the paint invalidation rect before we use paintInvalid
ationState, | |
1798 // else we would forget to inflate it for the current renderer. FIXME: If th
ese were | |
1799 // included into the visual overflow for repaint, we wouldn't have this issu
e. | |
1800 inflatePaintInvalidationRectForReflectionAndFilter(rect); | |
1801 | |
1802 if (paintInvalidationState && paintInvalidationState->canMapToContainer(pain
tInvalidationContainer) && position != FixedPosition) { | |
1803 if (layer() && layer()->transform()) | |
1804 rect = layer()->transform()->mapRect(pixelSnappedIntRect(rect)); | |
1805 | |
1806 // We can't trust the bits on LayoutObject, because this might be called
while re-resolving style. | |
1807 if (styleToUse.hasInFlowPosition() && layer()) | |
1808 rect.move(layer()->offsetForInFlowPosition()); | |
1809 | |
1810 rect.moveBy(location()); | |
1811 rect.move(paintInvalidationState->paintOffset()); | |
1812 if (paintInvalidationState->isClipped()) | |
1813 rect.intersect(paintInvalidationState->clipRect()); | |
1814 return; | |
1815 } | |
1816 | |
1817 if (paintInvalidationContainer == this) { | |
1818 if (paintInvalidationContainer->style()->isFlippedBlocksWritingMode()) | |
1819 flipForWritingMode(rect); | |
1820 return; | |
1821 } | |
1822 | |
1823 bool containerSkipped; | |
1824 LayoutObject* o = container(paintInvalidationContainer, &containerSkipped); | |
1825 if (!o) | |
1826 return; | |
1827 | |
1828 if (isWritingModeRoot()) | |
1829 flipForWritingMode(rect); | |
1830 | |
1831 LayoutPoint topLeft = rect.location(); | |
1832 topLeft.move(locationOffset()); | |
1833 | |
1834 // We are now in our parent container's coordinate space. Apply our transfo
rm to obtain a bounding box | |
1835 // in the parent's coordinate space that encloses us. | |
1836 if (hasLayer() && layer()->transform()) { | |
1837 rect = layer()->transform()->mapRect(pixelSnappedIntRect(rect)); | |
1838 topLeft = rect.location(); | |
1839 topLeft.move(locationOffset()); | |
1840 } | |
1841 | |
1842 if (position == AbsolutePosition && o->isRelPositioned() && o->isRenderInlin
e()) { | |
1843 topLeft += toRenderInline(o)->offsetForInFlowPositionedInline(*this); | |
1844 } else if (styleToUse.hasInFlowPosition() && layer()) { | |
1845 // Apply the relative position offset when invalidating a rectangle. Th
e layer | |
1846 // is translated, but the render box isn't, so we need to do this to get
the | |
1847 // right dirty rect. Since this is called from LayoutObject::setStyle,
the relative position | |
1848 // flag on the LayoutObject has been cleared, so use the one on the styl
e(). | |
1849 topLeft += layer()->offsetForInFlowPosition(); | |
1850 } | |
1851 | |
1852 if (position != AbsolutePosition && position != FixedPosition && o->hasColum
ns() && o->isRenderBlockFlow()) { | |
1853 LayoutRect paintInvalidationRect(topLeft, rect.size()); | |
1854 toRenderBlock(o)->adjustRectForColumns(paintInvalidationRect); | |
1855 topLeft = paintInvalidationRect.location(); | |
1856 rect = paintInvalidationRect; | |
1857 } | |
1858 | |
1859 // FIXME: We ignore the lightweight clipping rect that controls use, since i
f |o| is in mid-layout, | |
1860 // its controlClipRect will be wrong. For overflow clip we use the values ca
ched by the layer. | |
1861 rect.setLocation(topLeft); | |
1862 if (o->hasOverflowClip()) { | |
1863 RenderBox* containerBox = toRenderBox(o); | |
1864 containerBox->applyCachedClipAndScrollOffsetForPaintInvalidation(rect); | |
1865 if (rect.isEmpty()) | |
1866 return; | |
1867 } | |
1868 | |
1869 if (containerSkipped) { | |
1870 // If the paintInvalidationContainer is below o, then we need to map the
rect into paintInvalidationContainer's coordinates. | |
1871 LayoutSize containerOffset = paintInvalidationContainer->offsetFromAnces
torContainer(o); | |
1872 rect.move(-containerOffset); | |
1873 // If the paintInvalidationContainer is fixed, then the rect is already
in its coordinates so doesn't need viewport-adjusting. | |
1874 if (paintInvalidationContainer->style()->position() != FixedPosition &&
o->isRenderView()) | |
1875 toRenderView(o)->adjustViewportConstrainedOffset(rect, RenderView::v
iewportConstrainedPosition(position)); | |
1876 return; | |
1877 } | |
1878 | |
1879 if (o->isRenderView()) | |
1880 toRenderView(o)->mapRectToPaintInvalidationBacking(paintInvalidationCont
ainer, rect, RenderView::viewportConstrainedPosition(position), paintInvalidatio
nState); | |
1881 else | |
1882 o->mapRectToPaintInvalidationBacking(paintInvalidationContainer, rect, p
aintInvalidationState); | |
1883 } | |
1884 | |
1885 void RenderBox::inflatePaintInvalidationRectForReflectionAndFilter(LayoutRect& p
aintInvalidationRect) const | |
1886 { | |
1887 if (hasReflection()) | |
1888 paintInvalidationRect.unite(reflectedRect(paintInvalidationRect)); | |
1889 | |
1890 if (style()->hasFilter()) | |
1891 paintInvalidationRect.expand(style()->filterOutsets()); | |
1892 } | |
1893 | |
1894 void RenderBox::invalidatePaintForOverhangingFloats(bool) | |
1895 { | |
1896 } | |
1897 | |
1898 void RenderBox::updateLogicalWidth() | |
1899 { | |
1900 LogicalExtentComputedValues computedValues; | |
1901 computeLogicalWidth(computedValues); | |
1902 | |
1903 setLogicalWidth(computedValues.m_extent); | |
1904 setLogicalLeft(computedValues.m_position); | |
1905 setMarginStart(computedValues.m_margins.m_start); | |
1906 setMarginEnd(computedValues.m_margins.m_end); | |
1907 } | |
1908 | |
1909 static float getMaxWidthListMarker(const RenderBox* renderer) | |
1910 { | |
1911 #if ENABLE(ASSERT) | |
1912 ASSERT(renderer); | |
1913 Node* parentNode = renderer->generatingNode(); | |
1914 ASSERT(parentNode); | |
1915 ASSERT(isHTMLOListElement(parentNode) || isHTMLUListElement(parentNode)); | |
1916 ASSERT(renderer->style()->textAutosizingMultiplier() != 1); | |
1917 #endif | |
1918 float maxWidth = 0; | |
1919 for (LayoutObject* child = renderer->slowFirstChild(); child; child = child-
>nextSibling()) { | |
1920 if (!child->isListItem()) | |
1921 continue; | |
1922 | |
1923 RenderBox* listItem = toRenderBox(child); | |
1924 for (LayoutObject* itemChild = listItem->slowFirstChild(); itemChild; it
emChild = itemChild->nextSibling()) { | |
1925 if (!itemChild->isListMarker()) | |
1926 continue; | |
1927 RenderBox* itemMarker = toRenderBox(itemChild); | |
1928 // Make sure to compute the autosized width. | |
1929 if (itemMarker->needsLayout()) | |
1930 itemMarker->layout(); | |
1931 maxWidth = std::max<float>(maxWidth, toLayoutListMarker(itemMarker)-
>logicalWidth().toFloat()); | |
1932 break; | |
1933 } | |
1934 } | |
1935 return maxWidth; | |
1936 } | |
1937 | |
1938 void RenderBox::computeLogicalWidth(LogicalExtentComputedValues& computedValues)
const | |
1939 { | |
1940 computedValues.m_extent = logicalWidth(); | |
1941 computedValues.m_position = logicalLeft(); | |
1942 computedValues.m_margins.m_start = marginStart(); | |
1943 computedValues.m_margins.m_end = marginEnd(); | |
1944 | |
1945 if (isOutOfFlowPositioned()) { | |
1946 computePositionedLogicalWidth(computedValues); | |
1947 return; | |
1948 } | |
1949 | |
1950 // If layout is limited to a subtree, the subtree root's logical width does
not change. | |
1951 if (node() && view()->frameView() && view()->frameView()->layoutRoot(true) =
= this) | |
1952 return; | |
1953 | |
1954 // The parent box is flexing us, so it has increased or decreased our | |
1955 // width. Use the width from the style context. | |
1956 // FIXME: Account for writing-mode in flexible boxes. | |
1957 // https://bugs.webkit.org/show_bug.cgi?id=46418 | |
1958 if (hasOverrideWidth() && parent()->isFlexibleBoxIncludingDeprecated()) { | |
1959 computedValues.m_extent = overrideLogicalContentWidth() + borderAndPaddi
ngLogicalWidth(); | |
1960 return; | |
1961 } | |
1962 | |
1963 // FIXME: Account for writing-mode in flexible boxes. | |
1964 // https://bugs.webkit.org/show_bug.cgi?id=46418 | |
1965 bool inVerticalBox = parent()->isDeprecatedFlexibleBox() && (parent()->style
()->boxOrient() == VERTICAL); | |
1966 bool stretching = (parent()->style()->boxAlign() == BSTRETCH); | |
1967 bool treatAsReplaced = shouldComputeSizeAsReplaced() && (!inVerticalBox || !
stretching); | |
1968 | |
1969 const LayoutStyle& styleToUse = styleRef(); | |
1970 Length logicalWidthLength = treatAsReplaced ? Length(computeReplacedLogicalW
idth(), Fixed) : styleToUse.logicalWidth(); | |
1971 | |
1972 RenderBlock* cb = containingBlock(); | |
1973 LayoutUnit containerLogicalWidth = std::max(LayoutUnit(), containingBlockLog
icalWidthForContent()); | |
1974 bool hasPerpendicularContainingBlock = cb->isHorizontalWritingMode() != isHo
rizontalWritingMode(); | |
1975 | |
1976 if (isInline() && !isInlineBlockOrInlineTable()) { | |
1977 // just calculate margins | |
1978 computedValues.m_margins.m_start = minimumValueForLength(styleToUse.marg
inStart(), containerLogicalWidth); | |
1979 computedValues.m_margins.m_end = minimumValueForLength(styleToUse.margin
End(), containerLogicalWidth); | |
1980 if (treatAsReplaced) | |
1981 computedValues.m_extent = std::max<LayoutUnit>(floatValueForLength(l
ogicalWidthLength, 0) + borderAndPaddingLogicalWidth(), minPreferredLogicalWidth
()); | |
1982 return; | |
1983 } | |
1984 | |
1985 // Width calculations | |
1986 if (treatAsReplaced) | |
1987 computedValues.m_extent = logicalWidthLength.value() + borderAndPaddingL
ogicalWidth(); | |
1988 else { | |
1989 LayoutUnit containerWidthInInlineDirection = containerLogicalWidth; | |
1990 if (hasPerpendicularContainingBlock) | |
1991 containerWidthInInlineDirection = perpendicularContainingBlockLogica
lHeight(); | |
1992 LayoutUnit preferredWidth = computeLogicalWidthUsing(MainOrPreferredSize
, styleToUse.logicalWidth(), containerWidthInInlineDirection, cb); | |
1993 computedValues.m_extent = constrainLogicalWidthByMinMax(preferredWidth,
containerWidthInInlineDirection, cb); | |
1994 } | |
1995 | |
1996 // Margin calculations. | |
1997 computeMarginsForDirection(InlineDirection, cb, containerLogicalWidth, compu
tedValues.m_extent, computedValues.m_margins.m_start, | |
1998 computedValues.m_margins.m_end, style()->marginStart(), style()->marginE
nd()); | |
1999 | |
2000 if (!hasPerpendicularContainingBlock && containerLogicalWidth && containerLo
gicalWidth != (computedValues.m_extent + computedValues.m_margins.m_start + comp
utedValues.m_margins.m_end) | |
2001 && !isFloating() && !isInline() && !cb->isFlexibleBoxIncludingDeprecated
() && !cb->isRenderGrid()) { | |
2002 LayoutUnit newMargin = containerLogicalWidth - computedValues.m_extent -
cb->marginStartForChild(*this); | |
2003 bool hasInvertedDirection = cb->style()->isLeftToRightDirection() != sty
le()->isLeftToRightDirection(); | |
2004 if (hasInvertedDirection) | |
2005 computedValues.m_margins.m_start = newMargin; | |
2006 else | |
2007 computedValues.m_margins.m_end = newMargin; | |
2008 } | |
2009 | |
2010 if (styleToUse.textAutosizingMultiplier() != 1 && styleToUse.marginStart().t
ype() == Fixed) { | |
2011 Node* parentNode = generatingNode(); | |
2012 if (parentNode && (isHTMLOListElement(*parentNode) || isHTMLUListElement
(*parentNode))) { | |
2013 // Make sure the markers in a list are properly positioned (i.e. not
chopped off) when autosized. | |
2014 const float adjustedMargin = (1 - 1.0 / styleToUse.textAutosizingMul
tiplier()) * getMaxWidthListMarker(this); | |
2015 bool hasInvertedDirection = cb->style()->isLeftToRightDirection() !=
style()->isLeftToRightDirection(); | |
2016 if (hasInvertedDirection) | |
2017 computedValues.m_margins.m_end += adjustedMargin; | |
2018 else | |
2019 computedValues.m_margins.m_start += adjustedMargin; | |
2020 } | |
2021 } | |
2022 } | |
2023 | |
2024 LayoutUnit RenderBox::fillAvailableMeasure(LayoutUnit availableLogicalWidth) con
st | |
2025 { | |
2026 LayoutUnit marginStart = 0; | |
2027 LayoutUnit marginEnd = 0; | |
2028 return fillAvailableMeasure(availableLogicalWidth, marginStart, marginEnd); | |
2029 } | |
2030 | |
2031 LayoutUnit RenderBox::fillAvailableMeasure(LayoutUnit availableLogicalWidth, Lay
outUnit& marginStart, LayoutUnit& marginEnd) const | |
2032 { | |
2033 marginStart = minimumValueForLength(style()->marginStart(), availableLogical
Width); | |
2034 marginEnd = minimumValueForLength(style()->marginEnd(), availableLogicalWidt
h); | |
2035 return availableLogicalWidth - marginStart - marginEnd; | |
2036 } | |
2037 | |
2038 LayoutUnit RenderBox::computeIntrinsicLogicalWidthUsing(const Length& logicalWid
thLength, LayoutUnit availableLogicalWidth, LayoutUnit borderAndPadding) const | |
2039 { | |
2040 if (logicalWidthLength.type() == FillAvailable) | |
2041 return fillAvailableMeasure(availableLogicalWidth); | |
2042 | |
2043 LayoutUnit minLogicalWidth = 0; | |
2044 LayoutUnit maxLogicalWidth = 0; | |
2045 computeIntrinsicLogicalWidths(minLogicalWidth, maxLogicalWidth); | |
2046 | |
2047 if (logicalWidthLength.type() == MinContent) | |
2048 return minLogicalWidth + borderAndPadding; | |
2049 | |
2050 if (logicalWidthLength.type() == MaxContent) | |
2051 return maxLogicalWidth + borderAndPadding; | |
2052 | |
2053 if (logicalWidthLength.type() == FitContent) { | |
2054 minLogicalWidth += borderAndPadding; | |
2055 maxLogicalWidth += borderAndPadding; | |
2056 return std::max(minLogicalWidth, std::min(maxLogicalWidth, fillAvailable
Measure(availableLogicalWidth))); | |
2057 } | |
2058 | |
2059 ASSERT_NOT_REACHED(); | |
2060 return 0; | |
2061 } | |
2062 | |
2063 LayoutUnit RenderBox::computeLogicalWidthUsing(SizeType widthType, const Length&
logicalWidth, LayoutUnit availableLogicalWidth, const RenderBlock* cb) const | |
2064 { | |
2065 if (!logicalWidth.isIntrinsicOrAuto()) { | |
2066 // FIXME: If the containing block flow is perpendicular to our direction
we need to use the available logical height instead. | |
2067 return adjustBorderBoxLogicalWidthForBoxSizing(valueForLength(logicalWid
th, availableLogicalWidth)); | |
2068 } | |
2069 | |
2070 if (logicalWidth.isIntrinsic()) | |
2071 return computeIntrinsicLogicalWidthUsing(logicalWidth, availableLogicalW
idth, borderAndPaddingLogicalWidth()); | |
2072 | |
2073 LayoutUnit marginStart = 0; | |
2074 LayoutUnit marginEnd = 0; | |
2075 LayoutUnit logicalWidthResult = fillAvailableMeasure(availableLogicalWidth,
marginStart, marginEnd); | |
2076 | |
2077 if (shrinkToAvoidFloats() && cb->isRenderBlockFlow() && toRenderBlockFlow(cb
)->containsFloats()) | |
2078 logicalWidthResult = std::min(logicalWidthResult, shrinkLogicalWidthToAv
oidFloats(marginStart, marginEnd, toRenderBlockFlow(cb))); | |
2079 | |
2080 if (widthType == MainOrPreferredSize && sizesLogicalWidthToFitContent(logica
lWidth)) | |
2081 return std::max(minPreferredLogicalWidth(), std::min(maxPreferredLogical
Width(), logicalWidthResult)); | |
2082 return logicalWidthResult; | |
2083 } | |
2084 | |
2085 static bool columnFlexItemHasStretchAlignment(const LayoutObject* flexitem) | |
2086 { | |
2087 LayoutObject* parent = flexitem->parent(); | |
2088 // auto margins mean we don't stretch. Note that this function will only be
used for | |
2089 // widths, so we don't have to check marginBefore/marginAfter. | |
2090 ASSERT(parent->style()->isColumnFlexDirection()); | |
2091 if (flexitem->style()->marginStart().isAuto() || flexitem->style()->marginEn
d().isAuto()) | |
2092 return false; | |
2093 return flexitem->style()->alignSelf() == ItemPositionStretch || (flexitem->s
tyle()->alignSelf() == ItemPositionAuto && parent->style()->alignItems() == Item
PositionStretch); | |
2094 } | |
2095 | |
2096 static bool isStretchingColumnFlexItem(const LayoutObject* flexitem) | |
2097 { | |
2098 LayoutObject* parent = flexitem->parent(); | |
2099 if (parent->isDeprecatedFlexibleBox() && parent->style()->boxOrient() == VER
TICAL && parent->style()->boxAlign() == BSTRETCH) | |
2100 return true; | |
2101 | |
2102 // We don't stretch multiline flexboxes because they need to apply line spac
ing (align-content) first. | |
2103 if (parent->isFlexibleBox() && parent->style()->flexWrap() == FlexNoWrap &&
parent->style()->isColumnFlexDirection() && columnFlexItemHasStretchAlignment(fl
exitem)) | |
2104 return true; | |
2105 return false; | |
2106 } | |
2107 | |
2108 bool RenderBox::sizesLogicalWidthToFitContent(const Length& logicalWidth) const | |
2109 { | |
2110 if (isFloating() || isInlineBlockOrInlineTable()) | |
2111 return true; | |
2112 | |
2113 if (logicalWidth.type() == Intrinsic) | |
2114 return true; | |
2115 | |
2116 // Flexible box items should shrink wrap, so we lay them out at their intrin
sic widths. | |
2117 // In the case of columns that have a stretch alignment, we go ahead and lay
out at the | |
2118 // stretched size to avoid an extra layout when applying alignment. | |
2119 if (parent()->isFlexibleBox()) { | |
2120 // For multiline columns, we need to apply align-content first, so we ca
n't stretch now. | |
2121 if (!parent()->style()->isColumnFlexDirection() || parent()->style()->fl
exWrap() != FlexNoWrap) | |
2122 return true; | |
2123 if (!columnFlexItemHasStretchAlignment(this)) | |
2124 return true; | |
2125 } | |
2126 | |
2127 // Flexible horizontal boxes lay out children at their intrinsic widths. Al
so vertical boxes | |
2128 // that don't stretch their kids lay out their children at their intrinsic w
idths. | |
2129 // FIXME: Think about writing-mode here. | |
2130 // https://bugs.webkit.org/show_bug.cgi?id=46473 | |
2131 if (parent()->isDeprecatedFlexibleBox() && (parent()->style()->boxOrient() =
= HORIZONTAL || parent()->style()->boxAlign() != BSTRETCH)) | |
2132 return true; | |
2133 | |
2134 // Button, input, select, textarea, and legend treat width value of 'auto' a
s 'intrinsic' unless it's in a | |
2135 // stretching column flexbox. | |
2136 // FIXME: Think about writing-mode here. | |
2137 // https://bugs.webkit.org/show_bug.cgi?id=46473 | |
2138 if (logicalWidth.isAuto() && !isStretchingColumnFlexItem(this) && autoWidthS
houldFitContent()) | |
2139 return true; | |
2140 | |
2141 if (isHorizontalWritingMode() != containingBlock()->isHorizontalWritingMode(
)) | |
2142 return true; | |
2143 | |
2144 return false; | |
2145 } | |
2146 | |
2147 bool RenderBox::autoWidthShouldFitContent() const | |
2148 { | |
2149 return node() && (isHTMLInputElement(*node()) || isHTMLSelectElement(*node()
) || isHTMLButtonElement(*node()) | |
2150 || isHTMLTextAreaElement(*node()) || (isHTMLLegendElement(*node()) && !s
tyle()->hasOutOfFlowPosition())); | |
2151 } | |
2152 | |
2153 void RenderBox::computeMarginsForDirection(MarginDirection flowDirection, const
RenderBlock* containingBlock, LayoutUnit containerWidth, LayoutUnit childWidth,
LayoutUnit& marginStart, LayoutUnit& marginEnd, Length marginStartLength, Length
marginEndLength) const | |
2154 { | |
2155 if (flowDirection == BlockDirection || isFloating() || isInline()) { | |
2156 if (isTableCell() && flowDirection == BlockDirection) { | |
2157 // FIXME: Not right if we allow cells to have different directionali
ty than the table. If we do allow this, though, | |
2158 // we may just do it with an extra anonymous block inside the cell. | |
2159 marginStart = 0; | |
2160 marginEnd = 0; | |
2161 return; | |
2162 } | |
2163 | |
2164 // Margins are calculated with respect to the logical width of | |
2165 // the containing block (8.3) | |
2166 // Inline blocks/tables and floats don't have their margins increased. | |
2167 marginStart = minimumValueForLength(marginStartLength, containerWidth); | |
2168 marginEnd = minimumValueForLength(marginEndLength, containerWidth); | |
2169 return; | |
2170 } | |
2171 | |
2172 if (containingBlock->isFlexibleBox()) { | |
2173 // We need to let flexbox handle the margin adjustment - otherwise, flex
box | |
2174 // will think we're wider than we actually are and calculate line sizes
wrong. | |
2175 // See also http://dev.w3.org/csswg/css-flexbox/#auto-margins | |
2176 if (marginStartLength.isAuto()) | |
2177 marginStartLength.setValue(0); | |
2178 if (marginEndLength.isAuto()) | |
2179 marginEndLength.setValue(0); | |
2180 } | |
2181 | |
2182 LayoutUnit marginStartWidth = minimumValueForLength(marginStartLength, conta
inerWidth); | |
2183 LayoutUnit marginEndWidth = minimumValueForLength(marginEndLength, container
Width); | |
2184 | |
2185 LayoutUnit availableWidth = containerWidth; | |
2186 if (avoidsFloats() && containingBlock->isRenderBlockFlow() && toRenderBlockF
low(containingBlock)->containsFloats()) { | |
2187 availableWidth = containingBlockAvailableLineWidth(); | |
2188 if (shrinkToAvoidFloats() && availableWidth < containerWidth) { | |
2189 marginStart = std::max(LayoutUnit(), marginStartWidth); | |
2190 marginEnd = std::max(LayoutUnit(), marginEndWidth); | |
2191 } | |
2192 } | |
2193 | |
2194 // CSS 2.1 (10.3.3): "If 'width' is not 'auto' and 'border-left-width' + 'pa
dding-left' + 'width' + 'padding-right' + 'border-right-width' | |
2195 // (plus any of 'margin-left' or 'margin-right' that are not 'auto') is larg
er than the width of the containing block, then any 'auto' | |
2196 // values for 'margin-left' or 'margin-right' are, for the following rules,
treated as zero. | |
2197 LayoutUnit marginBoxWidth = childWidth + (!style()->width().isAuto() ? margi
nStartWidth + marginEndWidth : LayoutUnit()); | |
2198 | |
2199 if (marginBoxWidth < availableWidth) { | |
2200 // CSS 2.1: "If both 'margin-left' and 'margin-right' are 'auto', their
used values are equal. This horizontally centers the element | |
2201 // with respect to the edges of the containing block." | |
2202 const LayoutStyle& containingBlockStyle = containingBlock->styleRef(); | |
2203 if ((marginStartLength.isAuto() && marginEndLength.isAuto()) | |
2204 || (!marginStartLength.isAuto() && !marginEndLength.isAuto() && cont
ainingBlockStyle.textAlign() == WEBKIT_CENTER)) { | |
2205 // Other browsers center the margin box for align=center elements so
we match them here. | |
2206 LayoutUnit centeredMarginBoxStart = std::max(LayoutUnit(), (availabl
eWidth - childWidth - marginStartWidth - marginEndWidth) / 2); | |
2207 marginStart = centeredMarginBoxStart + marginStartWidth; | |
2208 marginEnd = availableWidth - childWidth - marginStart + marginEndWid
th; | |
2209 return; | |
2210 } | |
2211 | |
2212 // Adjust margins for the align attribute | |
2213 if ((!containingBlockStyle.isLeftToRightDirection() && containingBlockSt
yle.textAlign() == WEBKIT_LEFT) | |
2214 || (containingBlockStyle.isLeftToRightDirection() && containingBlock
Style.textAlign() == WEBKIT_RIGHT)) { | |
2215 if (containingBlockStyle.isLeftToRightDirection() != styleRef().isLe
ftToRightDirection()) { | |
2216 if (!marginStartLength.isAuto()) | |
2217 marginEndLength = Length(Auto); | |
2218 } else { | |
2219 if (!marginEndLength.isAuto()) | |
2220 marginStartLength = Length(Auto); | |
2221 } | |
2222 } | |
2223 | |
2224 // CSS 2.1: "If there is exactly one value specified as 'auto', its used
value follows from the equality." | |
2225 if (marginEndLength.isAuto()) { | |
2226 marginStart = marginStartWidth; | |
2227 marginEnd = availableWidth - childWidth - marginStart; | |
2228 return; | |
2229 } | |
2230 | |
2231 if (marginStartLength.isAuto()) { | |
2232 marginEnd = marginEndWidth; | |
2233 marginStart = availableWidth - childWidth - marginEnd; | |
2234 return; | |
2235 } | |
2236 } | |
2237 | |
2238 // Either no auto margins, or our margin box width is >= the container width
, auto margins will just turn into 0. | |
2239 marginStart = marginStartWidth; | |
2240 marginEnd = marginEndWidth; | |
2241 } | |
2242 | |
2243 void RenderBox::updateLogicalHeight() | |
2244 { | |
2245 m_intrinsicContentLogicalHeight = contentLogicalHeight(); | |
2246 | |
2247 LogicalExtentComputedValues computedValues; | |
2248 computeLogicalHeight(logicalHeight(), logicalTop(), computedValues); | |
2249 | |
2250 setLogicalHeight(computedValues.m_extent); | |
2251 setLogicalTop(computedValues.m_position); | |
2252 setMarginBefore(computedValues.m_margins.m_before); | |
2253 setMarginAfter(computedValues.m_margins.m_after); | |
2254 } | |
2255 | |
2256 void RenderBox::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logica
lTop, LogicalExtentComputedValues& computedValues) const | |
2257 { | |
2258 computedValues.m_extent = logicalHeight; | |
2259 computedValues.m_position = logicalTop; | |
2260 | |
2261 // Cell height is managed by the table and inline non-replaced elements do n
ot support a height property. | |
2262 if (isTableCell() || (isInline() && !isReplaced())) | |
2263 return; | |
2264 | |
2265 Length h; | |
2266 if (isOutOfFlowPositioned()) | |
2267 computePositionedLogicalHeight(computedValues); | |
2268 else { | |
2269 RenderBlock* cb = containingBlock(); | |
2270 | |
2271 // If we are perpendicular to our containing block then we need to resol
ve our block-start and block-end margins so that if they | |
2272 // are 'auto' we are centred or aligned within the inline flow containin
g block: this is done by computing the margins as though they are inline. | |
2273 // Note that as this is the 'sizing phase' we are using our own writing
mode rather than the containing block's. We use the containing block's | |
2274 // writing mode when figuring out the block-direction margins for positi
oning in |computeAndSetBlockDirectionMargins| (i.e. margin collapsing etc.). | |
2275 // See http://www.w3.org/TR/2014/CR-css-writing-modes-3-20140320/#orthog
onal-flows | |
2276 MarginDirection flowDirection = isHorizontalWritingMode() != cb->isHoriz
ontalWritingMode() ? InlineDirection : BlockDirection; | |
2277 | |
2278 // For tables, calculate margins only. | |
2279 if (isTable()) { | |
2280 computeMarginsForDirection(flowDirection, cb, containingBlockLogical
WidthForContent(), computedValues.m_extent, computedValues.m_margins.m_before, | |
2281 computedValues.m_margins.m_after, style()->marginBefore(), style
()->marginAfter()); | |
2282 return; | |
2283 } | |
2284 | |
2285 // FIXME: Account for writing-mode in flexible boxes. | |
2286 // https://bugs.webkit.org/show_bug.cgi?id=46418 | |
2287 bool inHorizontalBox = parent()->isDeprecatedFlexibleBox() && parent()->
style()->boxOrient() == HORIZONTAL; | |
2288 bool stretching = parent()->style()->boxAlign() == BSTRETCH; | |
2289 bool treatAsReplaced = shouldComputeSizeAsReplaced() && (!inHorizontalBo
x || !stretching); | |
2290 bool checkMinMaxHeight = false; | |
2291 | |
2292 // The parent box is flexing us, so it has increased or decreased our he
ight. We have to | |
2293 // grab our cached flexible height. | |
2294 // FIXME: Account for writing-mode in flexible boxes. | |
2295 // https://bugs.webkit.org/show_bug.cgi?id=46418 | |
2296 if (hasOverrideHeight() && (parent()->isFlexibleBoxIncludingDeprecated()
|| parent()->isRenderGrid())) | |
2297 h = Length(overrideLogicalContentHeight(), Fixed); | |
2298 else if (treatAsReplaced) | |
2299 h = Length(computeReplacedLogicalHeight(), Fixed); | |
2300 else { | |
2301 h = style()->logicalHeight(); | |
2302 checkMinMaxHeight = true; | |
2303 } | |
2304 | |
2305 // Block children of horizontal flexible boxes fill the height of the bo
x. | |
2306 // FIXME: Account for writing-mode in flexible boxes. | |
2307 // https://bugs.webkit.org/show_bug.cgi?id=46418 | |
2308 if (h.isAuto() && inHorizontalBox && toRenderDeprecatedFlexibleBox(paren
t())->isStretchingChildren()) { | |
2309 h = Length(parentBox()->contentLogicalHeight() - marginBefore() - ma
rginAfter() - borderAndPaddingLogicalHeight(), Fixed); | |
2310 checkMinMaxHeight = false; | |
2311 } | |
2312 | |
2313 LayoutUnit heightResult; | |
2314 if (checkMinMaxHeight) { | |
2315 heightResult = computeLogicalHeightUsing(style()->logicalHeight(), c
omputedValues.m_extent - borderAndPaddingLogicalHeight()); | |
2316 if (heightResult == -1) | |
2317 heightResult = computedValues.m_extent; | |
2318 heightResult = constrainLogicalHeightByMinMax(heightResult, computed
Values.m_extent - borderAndPaddingLogicalHeight()); | |
2319 } else { | |
2320 // The only times we don't check min/max height are when a fixed len
gth has | |
2321 // been given as an override. Just use that. The value has already
been adjusted | |
2322 // for box-sizing. | |
2323 ASSERT(h.isFixed()); | |
2324 heightResult = h.value() + borderAndPaddingLogicalHeight(); | |
2325 } | |
2326 | |
2327 computedValues.m_extent = heightResult; | |
2328 computeMarginsForDirection(flowDirection, cb, containingBlockLogicalWidt
hForContent(), computedValues.m_extent, computedValues.m_margins.m_before, | |
2329 computedValues.m_margins.m_after, style()->marginBefore(), style()->
marginAfter()); | |
2330 } | |
2331 | |
2332 // WinIE quirk: The <html> block always fills the entire canvas in quirks mo
de. The <body> always fills the | |
2333 // <html> block in quirks mode. Only apply this quirk if the block is norma
l flow and no height | |
2334 // is specified. When we're printing, we also need this quirk if the body or
root has a percentage | |
2335 // height since we don't set a height in RenderView when we're printing. So
without this quirk, the | |
2336 // height has nothing to be a percentage of, and it ends up being 0. That is
bad. | |
2337 bool paginatedContentNeedsBaseHeight = document().printing() && h.isPercent(
) | |
2338 && (isDocumentElement() || (isBody() && document().documentElement()->re
nderer()->style()->logicalHeight().isPercent())) && !isInline(); | |
2339 if (stretchesToViewport() || paginatedContentNeedsBaseHeight) { | |
2340 LayoutUnit margins = collapsedMarginBefore() + collapsedMarginAfter(); | |
2341 LayoutUnit visibleHeight = view()->viewLogicalHeightForPercentages(); | |
2342 if (isDocumentElement()) | |
2343 computedValues.m_extent = std::max(computedValues.m_extent, visibleH
eight - margins); | |
2344 else { | |
2345 LayoutUnit marginsBordersPadding = margins + parentBox()->marginBefo
re() + parentBox()->marginAfter() + parentBox()->borderAndPaddingLogicalHeight()
; | |
2346 computedValues.m_extent = std::max(computedValues.m_extent, visibleH
eight - marginsBordersPadding); | |
2347 } | |
2348 } | |
2349 } | |
2350 | |
2351 LayoutUnit RenderBox::computeLogicalHeightUsing(const Length& height, LayoutUnit
intrinsicContentHeight) const | |
2352 { | |
2353 LayoutUnit logicalHeight = computeContentAndScrollbarLogicalHeightUsing(heig
ht, intrinsicContentHeight); | |
2354 if (logicalHeight != -1) | |
2355 logicalHeight = adjustBorderBoxLogicalHeightForBoxSizing(logicalHeight); | |
2356 return logicalHeight; | |
2357 } | |
2358 | |
2359 LayoutUnit RenderBox::computeContentLogicalHeight(const Length& height, LayoutUn
it intrinsicContentHeight) const | |
2360 { | |
2361 LayoutUnit heightIncludingScrollbar = computeContentAndScrollbarLogicalHeigh
tUsing(height, intrinsicContentHeight); | |
2362 if (heightIncludingScrollbar == -1) | |
2363 return -1; | |
2364 return std::max(LayoutUnit(), adjustContentBoxLogicalHeightForBoxSizing(heig
htIncludingScrollbar) - scrollbarLogicalHeight()); | |
2365 } | |
2366 | |
2367 LayoutUnit RenderBox::computeIntrinsicLogicalContentHeightUsing(const Length& lo
gicalHeightLength, LayoutUnit intrinsicContentHeight, LayoutUnit borderAndPaddin
g) const | |
2368 { | |
2369 // FIXME(cbiesinger): The css-sizing spec is considering changing what min-c
ontent/max-content should resolve to. | |
2370 // If that happens, this code will have to change. | |
2371 if (logicalHeightLength.isMinContent() || logicalHeightLength.isMaxContent()
|| logicalHeightLength.isFitContent()) { | |
2372 if (isReplaced()) | |
2373 return intrinsicSize().height(); | |
2374 if (m_intrinsicContentLogicalHeight != -1) | |
2375 return m_intrinsicContentLogicalHeight; | |
2376 return intrinsicContentHeight; | |
2377 } | |
2378 if (logicalHeightLength.isFillAvailable()) | |
2379 return containingBlock()->availableLogicalHeight(ExcludeMarginBorderPadd
ing) - borderAndPadding; | |
2380 ASSERT_NOT_REACHED(); | |
2381 return 0; | |
2382 } | |
2383 | |
2384 LayoutUnit RenderBox::computeContentAndScrollbarLogicalHeightUsing(const Length&
height, LayoutUnit intrinsicContentHeight) const | |
2385 { | |
2386 // FIXME(cbiesinger): The css-sizing spec is considering changing what min-c
ontent/max-content should resolve to. | |
2387 // If that happens, this code will have to change. | |
2388 if (height.isIntrinsic()) { | |
2389 if (intrinsicContentHeight == -1) | |
2390 return -1; // Intrinsic height isn't available. | |
2391 return computeIntrinsicLogicalContentHeightUsing(height, intrinsicConten
tHeight, borderAndPaddingLogicalHeight()); | |
2392 } | |
2393 if (height.isFixed()) | |
2394 return height.value(); | |
2395 if (height.isPercent()) | |
2396 return computePercentageLogicalHeight(height); | |
2397 return -1; | |
2398 } | |
2399 | |
2400 bool RenderBox::skipContainingBlockForPercentHeightCalculation(const RenderBox*
containingBlock) const | |
2401 { | |
2402 // If the writing mode of the containing block is orthogonal to ours, it mea
ns that we shouldn't | |
2403 // skip anything, since we're going to resolve the percentage height against
a containing block *width*. | |
2404 if (isHorizontalWritingMode() != containingBlock->isHorizontalWritingMode()) | |
2405 return false; | |
2406 | |
2407 // Flow threads for multicol or paged overflow should be skipped. They are i
nvisible to the DOM, | |
2408 // and percent heights of children should be resolved against the multicol o
r paged container. | |
2409 if (containingBlock->isLayoutFlowThread()) | |
2410 return true; | |
2411 | |
2412 // For quirks mode and anonymous blocks, we skip auto-height containingBlock
s when computing percentages. | |
2413 // For standards mode, we treat the percentage as auto if it has an auto-hei
ght containing block. | |
2414 if (!document().inQuirksMode() && !containingBlock->isAnonymousBlock()) | |
2415 return false; | |
2416 | |
2417 return !containingBlock->isTableCell() && !containingBlock->isOutOfFlowPosit
ioned() && containingBlock->style()->logicalHeight().isAuto(); | |
2418 } | |
2419 | |
2420 LayoutUnit RenderBox::computePercentageLogicalHeight(const Length& height) const | |
2421 { | |
2422 LayoutUnit availableHeight = -1; | |
2423 | |
2424 bool skippedAutoHeightContainingBlock = false; | |
2425 RenderBlock* cb = containingBlock(); | |
2426 const RenderBox* containingBlockChild = this; | |
2427 LayoutUnit rootMarginBorderPaddingHeight = 0; | |
2428 while (!cb->isRenderView() && skipContainingBlockForPercentHeightCalculation
(cb)) { | |
2429 if (cb->isBody() || cb->isDocumentElement()) | |
2430 rootMarginBorderPaddingHeight += cb->marginBefore() + cb->marginAfte
r() + cb->borderAndPaddingLogicalHeight(); | |
2431 skippedAutoHeightContainingBlock = true; | |
2432 containingBlockChild = cb; | |
2433 cb = cb->containingBlock(); | |
2434 } | |
2435 cb->addPercentHeightDescendant(const_cast<RenderBox*>(this)); | |
2436 | |
2437 const LayoutStyle& cbstyle = cb->styleRef(); | |
2438 | |
2439 // A positioned element that specified both top/bottom or that specifies hei
ght should be treated as though it has a height | |
2440 // explicitly specified that can be used for any percentage computations. | |
2441 bool isOutOfFlowPositionedWithSpecifiedHeight = cb->isOutOfFlowPositioned()
&& (!cbstyle.logicalHeight().isAuto() || (!cbstyle.logicalTop().isAuto() && !cbs
tyle.logicalBottom().isAuto())); | |
2442 | |
2443 bool includeBorderPadding = isTable(); | |
2444 | |
2445 if (isHorizontalWritingMode() != cb->isHorizontalWritingMode()) | |
2446 availableHeight = containingBlockChild->containingBlockLogicalWidthForCo
ntent(); | |
2447 else if (hasOverrideContainingBlockLogicalHeight()) | |
2448 availableHeight = overrideContainingBlockContentLogicalHeight(); | |
2449 else if (cb->isTableCell()) { | |
2450 if (!skippedAutoHeightContainingBlock) { | |
2451 // Table cells violate what the CSS spec says to do with heights. Ba
sically we | |
2452 // don't care if the cell specified a height or not. We just always
make ourselves | |
2453 // be a percentage of the cell's current content height. | |
2454 if (!cb->hasOverrideHeight()) { | |
2455 // Normally we would let the cell size intrinsically, but scroll
ing overflow has to be | |
2456 // treated differently, since WinIE lets scrolled overflow regio
ns shrink as needed. | |
2457 // While we can't get all cases right, we can at least detect wh
en the cell has a specified | |
2458 // height or when the table has a specified height. In these cas
es we want to initially have | |
2459 // no size and allow the flexing of the table or the cell to its
specified height to cause us | |
2460 // to grow to fill the space. This could end up being wrong in s
ome cases, but it is | |
2461 // preferable to the alternative (sizing intrinsically and makin
g the row end up too big). | |
2462 LayoutTableCell* cell = toLayoutTableCell(cb); | |
2463 if (scrollsOverflowY() && (!cell->style()->logicalHeight().isAut
o() || !cell->table()->style()->logicalHeight().isAuto())) | |
2464 return LayoutUnit(); | |
2465 return -1; | |
2466 } | |
2467 availableHeight = cb->overrideLogicalContentHeight(); | |
2468 includeBorderPadding = true; | |
2469 } | |
2470 } else if (cbstyle.logicalHeight().isFixed()) { | |
2471 LayoutUnit contentBoxHeight = cb->adjustContentBoxLogicalHeightForBoxSiz
ing(cbstyle.logicalHeight().value()); | |
2472 availableHeight = std::max(LayoutUnit(), cb->constrainContentBoxLogicalH
eightByMinMax(contentBoxHeight - cb->scrollbarLogicalHeight(), -1)); | |
2473 } else if (cbstyle.logicalHeight().isPercent() && !isOutOfFlowPositionedWith
SpecifiedHeight) { | |
2474 // We need to recur and compute the percentage height for our containing
block. | |
2475 LayoutUnit heightWithScrollbar = cb->computePercentageLogicalHeight(cbst
yle.logicalHeight()); | |
2476 if (heightWithScrollbar != -1) { | |
2477 LayoutUnit contentBoxHeightWithScrollbar = cb->adjustContentBoxLogic
alHeightForBoxSizing(heightWithScrollbar); | |
2478 // We need to adjust for min/max height because this method does not | |
2479 // handle the min/max of the current block, its caller does. So the | |
2480 // return value from the recursive call will not have been adjusted | |
2481 // yet. | |
2482 LayoutUnit contentBoxHeight = cb->constrainContentBoxLogicalHeightBy
MinMax(contentBoxHeightWithScrollbar - cb->scrollbarLogicalHeight(), -1); | |
2483 availableHeight = std::max(LayoutUnit(), contentBoxHeight); | |
2484 } | |
2485 } else if (isOutOfFlowPositionedWithSpecifiedHeight) { | |
2486 // Don't allow this to affect the block' size() member variable, since t
his | |
2487 // can get called while the block is still laying out its kids. | |
2488 LogicalExtentComputedValues computedValues; | |
2489 cb->computeLogicalHeight(cb->logicalHeight(), 0, computedValues); | |
2490 availableHeight = computedValues.m_extent - cb->borderAndPaddingLogicalH
eight() - cb->scrollbarLogicalHeight(); | |
2491 } else if (cb->isRenderView()) | |
2492 availableHeight = view()->viewLogicalHeightForPercentages(); | |
2493 | |
2494 if (availableHeight == -1) | |
2495 return availableHeight; | |
2496 | |
2497 availableHeight -= rootMarginBorderPaddingHeight; | |
2498 | |
2499 if (isTable() && isOutOfFlowPositioned()) | |
2500 availableHeight += cb->paddingLogicalHeight(); | |
2501 | |
2502 LayoutUnit result = valueForLength(height, availableHeight); | |
2503 if (includeBorderPadding) { | |
2504 // FIXME: Table cells should default to box-sizing: border-box so we can
avoid this hack. | |
2505 // It is necessary to use the border-box to match WinIE's broken | |
2506 // box model. This is essential for sizing inside | |
2507 // table cells using percentage heights. | |
2508 result -= borderAndPaddingLogicalHeight(); | |
2509 return std::max(LayoutUnit(), result); | |
2510 } | |
2511 return result; | |
2512 } | |
2513 | |
2514 LayoutUnit RenderBox::computeReplacedLogicalWidth(ShouldComputePreferred shouldC
omputePreferred) const | |
2515 { | |
2516 return computeReplacedLogicalWidthRespectingMinMaxWidth(computeReplacedLogic
alWidthUsing(style()->logicalWidth()), shouldComputePreferred); | |
2517 } | |
2518 | |
2519 LayoutUnit RenderBox::computeReplacedLogicalWidthRespectingMinMaxWidth(LayoutUni
t logicalWidth, ShouldComputePreferred shouldComputePreferred) const | |
2520 { | |
2521 LayoutUnit minLogicalWidth = (shouldComputePreferred == ComputePreferred &&
style()->logicalMinWidth().isPercent()) || style()->logicalMinWidth().isMaxSizeN
one() ? logicalWidth : computeReplacedLogicalWidthUsing(style()->logicalMinWidth
()); | |
2522 LayoutUnit maxLogicalWidth = (shouldComputePreferred == ComputePreferred &&
style()->logicalMaxWidth().isPercent()) || style()->logicalMaxWidth().isMaxSizeN
one() ? logicalWidth : computeReplacedLogicalWidthUsing(style()->logicalMaxWidth
()); | |
2523 return std::max(minLogicalWidth, std::min(logicalWidth, maxLogicalWidth)); | |
2524 } | |
2525 | |
2526 LayoutUnit RenderBox::computeReplacedLogicalWidthUsing(const Length& logicalWidt
h) const | |
2527 { | |
2528 switch (logicalWidth.type()) { | |
2529 case Fixed: | |
2530 return adjustContentBoxLogicalWidthForBoxSizing(logicalWidth.value()
); | |
2531 case MinContent: | |
2532 case MaxContent: { | |
2533 // MinContent/MaxContent don't need the availableLogicalWidth argume
nt. | |
2534 LayoutUnit availableLogicalWidth = 0; | |
2535 return computeIntrinsicLogicalWidthUsing(logicalWidth, availableLogi
calWidth, borderAndPaddingLogicalWidth()) - borderAndPaddingLogicalWidth(); | |
2536 } | |
2537 case FitContent: | |
2538 case FillAvailable: | |
2539 case Percent: | |
2540 case Calculated: { | |
2541 // FIXME: containingBlockLogicalWidthForContent() is wrong if the re
placed element's writing-mode is perpendicular to the | |
2542 // containing block's writing-mode. | |
2543 // https://bugs.webkit.org/show_bug.cgi?id=46496 | |
2544 const LayoutUnit cw = isOutOfFlowPositioned() ? containingBlockLogic
alWidthForPositioned(toLayoutBoxModelObject(container())) : containingBlockLogic
alWidthForContent(); | |
2545 Length containerLogicalWidth = containingBlock()->style()->logicalWi
dth(); | |
2546 // FIXME: Handle cases when containing block width is calculated or
viewport percent. | |
2547 // https://bugs.webkit.org/show_bug.cgi?id=91071 | |
2548 if (logicalWidth.isIntrinsic()) | |
2549 return computeIntrinsicLogicalWidthUsing(logicalWidth, cw, borde
rAndPaddingLogicalWidth()) - borderAndPaddingLogicalWidth(); | |
2550 if (cw > 0 || (!cw && (containerLogicalWidth.isFixed() || containerL
ogicalWidth.isPercent()))) | |
2551 return adjustContentBoxLogicalWidthForBoxSizing(minimumValueForL
ength(logicalWidth, cw)); | |
2552 return LayoutUnit(); | |
2553 } | |
2554 case Intrinsic: | |
2555 case MinIntrinsic: | |
2556 case Auto: | |
2557 case MaxSizeNone: | |
2558 return intrinsicLogicalWidth(); | |
2559 case ExtendToZoom: | |
2560 case DeviceWidth: | |
2561 case DeviceHeight: | |
2562 break; | |
2563 } | |
2564 | |
2565 ASSERT_NOT_REACHED(); | |
2566 return 0; | |
2567 } | |
2568 | |
2569 LayoutUnit RenderBox::computeReplacedLogicalHeight() const | |
2570 { | |
2571 return computeReplacedLogicalHeightRespectingMinMaxHeight(computeReplacedLog
icalHeightUsing(style()->logicalHeight())); | |
2572 } | |
2573 | |
2574 bool RenderBox::logicalHeightComputesAsNone(SizeType sizeType) const | |
2575 { | |
2576 ASSERT(sizeType == MinSize || sizeType == MaxSize); | |
2577 Length logicalHeight = sizeType == MinSize ? style()->logicalMinHeight() : s
tyle()->logicalMaxHeight(); | |
2578 Length initialLogicalHeight = sizeType == MinSize ? LayoutStyle::initialMinS
ize() : LayoutStyle::initialMaxSize(); | |
2579 | |
2580 if (logicalHeight == initialLogicalHeight) | |
2581 return true; | |
2582 | |
2583 if (RenderBlock* cb = containingBlockForAutoHeightDetection(logicalHeight)) | |
2584 return cb->hasAutoHeightOrContainingBlockWithAutoHeight(); | |
2585 return false; | |
2586 } | |
2587 | |
2588 LayoutUnit RenderBox::computeReplacedLogicalHeightRespectingMinMaxHeight(LayoutU
nit logicalHeight) const | |
2589 { | |
2590 // If the height of the containing block is not specified explicitly (i.e.,
it depends on content height), and this element is not absolutely positioned, | |
2591 // the percentage value is treated as '0' (for 'min-height') or 'none' (for
'max-height'). | |
2592 LayoutUnit minLogicalHeight; | |
2593 if (!logicalHeightComputesAsNone(MinSize)) | |
2594 minLogicalHeight = computeReplacedLogicalHeightUsing(style()->logicalMin
Height()); | |
2595 LayoutUnit maxLogicalHeight = logicalHeight; | |
2596 if (!logicalHeightComputesAsNone(MaxSize)) | |
2597 maxLogicalHeight = computeReplacedLogicalHeightUsing(style()->logicalMa
xHeight()); | |
2598 return std::max(minLogicalHeight, std::min(logicalHeight, maxLogicalHeight))
; | |
2599 } | |
2600 | |
2601 LayoutUnit RenderBox::computeReplacedLogicalHeightUsing(const Length& logicalHei
ght) const | |
2602 { | |
2603 switch (logicalHeight.type()) { | |
2604 case Fixed: | |
2605 return adjustContentBoxLogicalHeightForBoxSizing(logicalHeight.value
()); | |
2606 case Percent: | |
2607 case Calculated: | |
2608 { | |
2609 LayoutObject* cb = isOutOfFlowPositioned() ? container() : containin
gBlock(); | |
2610 while (cb->isAnonymous()) | |
2611 cb = cb->containingBlock(); | |
2612 if (cb->isRenderBlock()) | |
2613 toRenderBlock(cb)->addPercentHeightDescendant(const_cast<RenderB
ox*>(this)); | |
2614 | |
2615 if (cb->isOutOfFlowPositioned() && cb->style()->height().isAuto() &&
!(cb->style()->top().isAuto() || cb->style()->bottom().isAuto())) { | |
2616 ASSERT_WITH_SECURITY_IMPLICATION(cb->isRenderBlock()); | |
2617 RenderBlock* block = toRenderBlock(cb); | |
2618 LogicalExtentComputedValues computedValues; | |
2619 block->computeLogicalHeight(block->logicalHeight(), 0, computedV
alues); | |
2620 LayoutUnit newContentHeight = computedValues.m_extent - block->b
orderAndPaddingLogicalHeight() - block->scrollbarLogicalHeight(); | |
2621 LayoutUnit newHeight = block->adjustContentBoxLogicalHeightForBo
xSizing(newContentHeight); | |
2622 return adjustContentBoxLogicalHeightForBoxSizing(valueForLength(
logicalHeight, newHeight)); | |
2623 } | |
2624 | |
2625 // FIXME: availableLogicalHeight() is wrong if the replaced element'
s writing-mode is perpendicular to the | |
2626 // containing block's writing-mode. | |
2627 // https://bugs.webkit.org/show_bug.cgi?id=46496 | |
2628 LayoutUnit availableHeight; | |
2629 if (isOutOfFlowPositioned()) | |
2630 availableHeight = containingBlockLogicalHeightForPositioned(toLa
youtBoxModelObject(cb)); | |
2631 else { | |
2632 availableHeight = containingBlockLogicalHeightForContent(Include
MarginBorderPadding); | |
2633 // It is necessary to use the border-box to match WinIE's broken | |
2634 // box model. This is essential for sizing inside | |
2635 // table cells using percentage heights. | |
2636 // FIXME: This needs to be made writing-mode-aware. If the cell
and image are perpendicular writing-modes, this isn't right. | |
2637 // https://bugs.webkit.org/show_bug.cgi?id=46997 | |
2638 while (cb && !cb->isRenderView() && (cb->style()->logicalHeight(
).isAuto() || cb->style()->logicalHeight().isPercent())) { | |
2639 if (cb->isTableCell()) { | |
2640 // Don't let table cells squeeze percent-height replaced
elements | |
2641 // <http://bugs.webkit.org/show_bug.cgi?id=15359> | |
2642 availableHeight = std::max(availableHeight, intrinsicLog
icalHeight()); | |
2643 return valueForLength(logicalHeight, availableHeight - b
orderAndPaddingLogicalHeight()); | |
2644 } | |
2645 toRenderBlock(cb)->addPercentHeightDescendant(const_cast<Ren
derBox*>(this)); | |
2646 cb = cb->containingBlock(); | |
2647 } | |
2648 } | |
2649 return adjustContentBoxLogicalHeightForBoxSizing(valueForLength(logi
calHeight, availableHeight)); | |
2650 } | |
2651 case MinContent: | |
2652 case MaxContent: | |
2653 case FitContent: | |
2654 case FillAvailable: | |
2655 return adjustContentBoxLogicalHeightForBoxSizing(computeIntrinsicLog
icalContentHeightUsing(logicalHeight, intrinsicLogicalHeight(), borderAndPadding
Height())); | |
2656 default: | |
2657 return intrinsicLogicalHeight(); | |
2658 } | |
2659 } | |
2660 | |
2661 LayoutUnit RenderBox::availableLogicalHeight(AvailableLogicalHeightType heightTy
pe) const | |
2662 { | |
2663 // http://www.w3.org/TR/CSS2/visudet.html#propdef-height - We are interested
in the content height. | |
2664 return constrainContentBoxLogicalHeightByMinMax(availableLogicalHeightUsing(
style()->logicalHeight(), heightType), -1); | |
2665 } | |
2666 | |
2667 LayoutUnit RenderBox::availableLogicalHeightUsing(const Length& h, AvailableLogi
calHeightType heightType) const | |
2668 { | |
2669 if (isRenderView()) | |
2670 return isHorizontalWritingMode() ? toRenderView(this)->frameView()->unsc
aledVisibleContentSize().height() : toRenderView(this)->frameView()->unscaledVis
ibleContentSize().width(); | |
2671 | |
2672 // We need to stop here, since we don't want to increase the height of the t
able | |
2673 // artificially. We're going to rely on this cell getting expanded to some
new | |
2674 // height, and then when we lay out again we'll use the calculation below. | |
2675 if (isTableCell() && (h.isAuto() || h.isPercent())) { | |
2676 if (hasOverrideHeight()) | |
2677 return overrideLogicalContentHeight(); | |
2678 return logicalHeight() - borderAndPaddingLogicalHeight(); | |
2679 } | |
2680 | |
2681 if (h.isPercent() && isOutOfFlowPositioned()) { | |
2682 // FIXME: This is wrong if the containingBlock has a perpendicular writi
ng mode. | |
2683 LayoutUnit availableHeight = containingBlockLogicalHeightForPositioned(c
ontainingBlock()); | |
2684 return adjustContentBoxLogicalHeightForBoxSizing(valueForLength(h, avail
ableHeight)); | |
2685 } | |
2686 | |
2687 LayoutUnit heightIncludingScrollbar = computeContentAndScrollbarLogicalHeigh
tUsing(h, -1); | |
2688 if (heightIncludingScrollbar != -1) | |
2689 return std::max(LayoutUnit(), adjustContentBoxLogicalHeightForBoxSizing(
heightIncludingScrollbar) - scrollbarLogicalHeight()); | |
2690 | |
2691 // FIXME: Check logicalTop/logicalBottom here to correctly handle vertical w
riting-mode. | |
2692 // https://bugs.webkit.org/show_bug.cgi?id=46500 | |
2693 if (isRenderBlock() && isOutOfFlowPositioned() && style()->height().isAuto()
&& !(style()->top().isAuto() || style()->bottom().isAuto())) { | |
2694 RenderBlock* block = const_cast<RenderBlock*>(toRenderBlock(this)); | |
2695 LogicalExtentComputedValues computedValues; | |
2696 block->computeLogicalHeight(block->logicalHeight(), 0, computedValues); | |
2697 LayoutUnit newContentHeight = computedValues.m_extent - block->borderAnd
PaddingLogicalHeight() - block->scrollbarLogicalHeight(); | |
2698 return adjustContentBoxLogicalHeightForBoxSizing(newContentHeight); | |
2699 } | |
2700 | |
2701 // FIXME: This is wrong if the containingBlock has a perpendicular writing m
ode. | |
2702 LayoutUnit availableHeight = containingBlockLogicalHeightForContent(heightTy
pe); | |
2703 if (heightType == ExcludeMarginBorderPadding) { | |
2704 // FIXME: Margin collapsing hasn't happened yet, so this incorrectly rem
oves collapsed margins. | |
2705 availableHeight -= marginBefore() + marginAfter() + borderAndPaddingLogi
calHeight(); | |
2706 } | |
2707 return availableHeight; | |
2708 } | |
2709 | |
2710 void RenderBox::computeAndSetBlockDirectionMargins(const RenderBlock* containing
Block) | |
2711 { | |
2712 LayoutUnit marginBefore; | |
2713 LayoutUnit marginAfter; | |
2714 computeMarginsForDirection(BlockDirection, containingBlock, containingBlockL
ogicalWidthForContent(), logicalHeight(), marginBefore, marginAfter, | |
2715 style()->marginBeforeUsing(containingBlock->style()), | |
2716 style()->marginAfterUsing(containingBlock->style())); | |
2717 // Note that in this 'positioning phase' of the layout we are using the cont
aining block's writing mode rather than our own when calculating margins. | |
2718 // See http://www.w3.org/TR/2014/CR-css-writing-modes-3-20140320/#orthogonal
-flows | |
2719 containingBlock->setMarginBeforeForChild(*this, marginBefore); | |
2720 containingBlock->setMarginAfterForChild(*this, marginAfter); | |
2721 } | |
2722 | |
2723 LayoutUnit RenderBox::containingBlockLogicalWidthForPositioned(const LayoutBoxMo
delObject* containingBlock, bool checkForPerpendicularWritingMode) const | |
2724 { | |
2725 if (checkForPerpendicularWritingMode && containingBlock->isHorizontalWriting
Mode() != isHorizontalWritingMode()) | |
2726 return containingBlockLogicalHeightForPositioned(containingBlock, false)
; | |
2727 | |
2728 // Use viewport as container for top-level fixed-position elements. | |
2729 if (style()->position() == FixedPosition && containingBlock->isRenderView())
{ | |
2730 const RenderView* view = toRenderView(containingBlock); | |
2731 if (FrameView* frameView = view->frameView()) { | |
2732 LayoutRect viewportRect = frameView->viewportConstrainedVisibleConte
ntRect(); | |
2733 return containingBlock->isHorizontalWritingMode() ? viewportRect.wid
th() : viewportRect.height(); | |
2734 } | |
2735 } | |
2736 | |
2737 if (hasOverrideContainingBlockLogicalWidth()) | |
2738 return overrideContainingBlockContentLogicalWidth(); | |
2739 | |
2740 if (containingBlock->isBox()) | |
2741 return toRenderBox(containingBlock)->clientLogicalWidth(); | |
2742 | |
2743 ASSERT(containingBlock->isRenderInline() && containingBlock->isRelPositioned
()); | |
2744 | |
2745 const RenderInline* flow = toRenderInline(containingBlock); | |
2746 InlineFlowBox* first = flow->firstLineBox(); | |
2747 InlineFlowBox* last = flow->lastLineBox(); | |
2748 | |
2749 // If the containing block is empty, return a width of 0. | |
2750 if (!first || !last) | |
2751 return LayoutUnit(); | |
2752 | |
2753 LayoutUnit fromLeft; | |
2754 LayoutUnit fromRight; | |
2755 if (containingBlock->style()->isLeftToRightDirection()) { | |
2756 fromLeft = first->logicalLeft() + first->borderLogicalLeft(); | |
2757 fromRight = last->logicalLeft() + last->logicalWidth() - last->borderLog
icalRight(); | |
2758 } else { | |
2759 fromRight = first->logicalLeft() + first->logicalWidth() - first->border
LogicalRight(); | |
2760 fromLeft = last->logicalLeft() + last->borderLogicalLeft(); | |
2761 } | |
2762 | |
2763 return std::max(LayoutUnit(), fromRight - fromLeft); | |
2764 } | |
2765 | |
2766 LayoutUnit RenderBox::containingBlockLogicalHeightForPositioned(const LayoutBoxM
odelObject* containingBlock, bool checkForPerpendicularWritingMode) const | |
2767 { | |
2768 if (checkForPerpendicularWritingMode && containingBlock->isHorizontalWriting
Mode() != isHorizontalWritingMode()) | |
2769 return containingBlockLogicalWidthForPositioned(containingBlock, false); | |
2770 | |
2771 // Use viewport as container for top-level fixed-position elements. | |
2772 if (style()->position() == FixedPosition && containingBlock->isRenderView())
{ | |
2773 const RenderView* view = toRenderView(containingBlock); | |
2774 if (FrameView* frameView = view->frameView()) { | |
2775 LayoutRect viewportRect = frameView->viewportConstrainedVisibleConte
ntRect(); | |
2776 return containingBlock->isHorizontalWritingMode() ? viewportRect.hei
ght() : viewportRect.width(); | |
2777 } | |
2778 } | |
2779 | |
2780 if (hasOverrideContainingBlockLogicalHeight()) | |
2781 return overrideContainingBlockContentLogicalHeight(); | |
2782 | |
2783 if (containingBlock->isBox()) { | |
2784 const RenderBlock* cb = containingBlock->isRenderBlock() ? | |
2785 toRenderBlock(containingBlock) : containingBlock->containingBlock(); | |
2786 return cb->clientLogicalHeight(); | |
2787 } | |
2788 | |
2789 ASSERT(containingBlock->isRenderInline() && containingBlock->isRelPositioned
()); | |
2790 | |
2791 const RenderInline* flow = toRenderInline(containingBlock); | |
2792 InlineFlowBox* first = flow->firstLineBox(); | |
2793 InlineFlowBox* last = flow->lastLineBox(); | |
2794 | |
2795 // If the containing block is empty, return a height of 0. | |
2796 if (!first || !last) | |
2797 return LayoutUnit(); | |
2798 | |
2799 LayoutUnit heightResult; | |
2800 LayoutRect boundingBox = flow->linesBoundingBox(); | |
2801 if (containingBlock->isHorizontalWritingMode()) | |
2802 heightResult = boundingBox.height(); | |
2803 else | |
2804 heightResult = boundingBox.width(); | |
2805 heightResult -= (containingBlock->borderBefore() + containingBlock->borderAf
ter()); | |
2806 return heightResult; | |
2807 } | |
2808 | |
2809 static void computeInlineStaticDistance(Length& logicalLeft, Length& logicalRigh
t, const RenderBox* child, const LayoutBoxModelObject* containerBlock, LayoutUni
t containerLogicalWidth) | |
2810 { | |
2811 if (!logicalLeft.isAuto() || !logicalRight.isAuto()) | |
2812 return; | |
2813 | |
2814 // FIXME: The static distance computation has not been patched for mixed wri
ting modes yet. | |
2815 if (child->parent()->style()->direction() == LTR) { | |
2816 LayoutUnit staticPosition = child->layer()->staticInlinePosition() - con
tainerBlock->borderLogicalLeft(); | |
2817 for (LayoutObject* curr = child->parent(); curr && curr != containerBloc
k; curr = curr->container()) { | |
2818 if (curr->isBox()) { | |
2819 staticPosition += toRenderBox(curr)->logicalLeft(); | |
2820 if (toRenderBox(curr)->isRelPositioned()) | |
2821 staticPosition += toRenderBox(curr)->relativePositionOffset(
).width(); | |
2822 } else if (curr->isInline()) { | |
2823 if (curr->isRelPositioned()) { | |
2824 if (!curr->style()->logicalLeft().isAuto()) | |
2825 staticPosition += valueForLength(curr->style()->logicalL
eft(), curr->containingBlock()->availableWidth()); | |
2826 else | |
2827 staticPosition -= valueForLength(curr->style()->logicalR
ight(), curr->containingBlock()->availableWidth()); | |
2828 } | |
2829 } | |
2830 } | |
2831 logicalLeft.setValue(Fixed, staticPosition); | |
2832 } else { | |
2833 RenderBox* enclosingBox = child->parent()->enclosingBox(); | |
2834 LayoutUnit staticPosition = child->layer()->staticInlinePosition() + con
tainerLogicalWidth + containerBlock->borderLogicalLeft(); | |
2835 for (LayoutObject* curr = child->parent(); curr; curr = curr->container(
)) { | |
2836 if (curr->isBox()) { | |
2837 if (curr != containerBlock) { | |
2838 staticPosition -= toRenderBox(curr)->logicalLeft(); | |
2839 if (toRenderBox(curr)->isRelPositioned()) | |
2840 staticPosition -= toRenderBox(curr)->relativePositionOff
set().width(); | |
2841 } | |
2842 if (curr == enclosingBox) | |
2843 staticPosition -= enclosingBox->logicalWidth(); | |
2844 } else if (curr->isInline()) { | |
2845 if (curr->isRelPositioned()) { | |
2846 if (!curr->style()->logicalLeft().isAuto()) | |
2847 staticPosition -= valueForLength(curr->style()->logicalL
eft(), curr->containingBlock()->availableWidth()); | |
2848 else | |
2849 staticPosition += valueForLength(curr->style()->logicalR
ight(), curr->containingBlock()->availableWidth()); | |
2850 } | |
2851 } | |
2852 if (curr == containerBlock) | |
2853 break; | |
2854 } | |
2855 logicalRight.setValue(Fixed, staticPosition); | |
2856 } | |
2857 } | |
2858 | |
2859 void RenderBox::computePositionedLogicalWidth(LogicalExtentComputedValues& compu
tedValues) const | |
2860 { | |
2861 if (isReplaced()) { | |
2862 computePositionedLogicalWidthReplaced(computedValues); | |
2863 return; | |
2864 } | |
2865 | |
2866 // QUESTIONS | |
2867 // FIXME 1: Should we still deal with these the cases of 'left' or 'right' h
aving | |
2868 // the type 'static' in determining whether to calculate the static distance
? | |
2869 // NOTE: 'static' is not a legal value for 'left' or 'right' as of CSS 2.1. | |
2870 | |
2871 // FIXME 2: Can perhaps optimize out cases when max-width/min-width are grea
ter | |
2872 // than or less than the computed width(). Be careful of box-sizing and | |
2873 // percentage issues. | |
2874 | |
2875 // The following is based off of the W3C Working Draft from April 11, 2006 o
f | |
2876 // CSS 2.1: Section 10.3.7 "Absolutely positioned, non-replaced elements" | |
2877 // <http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width> | |
2878 // (block-style-comments in this function and in computePositionedLogicalWid
thUsing() | |
2879 // correspond to text from the spec) | |
2880 | |
2881 | |
2882 // We don't use containingBlock(), since we may be positioned by an enclosin
g | |
2883 // relative positioned inline. | |
2884 const LayoutBoxModelObject* containerBlock = toLayoutBoxModelObject(containe
r()); | |
2885 | |
2886 const LayoutUnit containerLogicalWidth = containingBlockLogicalWidthForPosit
ioned(containerBlock); | |
2887 | |
2888 // Use the container block's direction except when calculating the static di
stance | |
2889 // This conforms with the reference results for abspos-replaced-width-margin
-000.htm | |
2890 // of the CSS 2.1 test suite | |
2891 TextDirection containerDirection = containerBlock->style()->direction(); | |
2892 | |
2893 bool isHorizontal = isHorizontalWritingMode(); | |
2894 const LayoutUnit bordersPlusPadding = borderAndPaddingLogicalWidth(); | |
2895 const Length marginLogicalLeft = isHorizontal ? style()->marginLeft() : styl
e()->marginTop(); | |
2896 const Length marginLogicalRight = isHorizontal ? style()->marginRight() : st
yle()->marginBottom(); | |
2897 | |
2898 Length logicalLeftLength = style()->logicalLeft(); | |
2899 Length logicalRightLength = style()->logicalRight(); | |
2900 | |
2901 /*--------------------------------------------------------------------------
-*\ | |
2902 * For the purposes of this section and the next, the term "static position" | |
2903 * (of an element) refers, roughly, to the position an element would have ha
d | |
2904 * in the normal flow. More precisely: | |
2905 * | |
2906 * * The static position for 'left' is the distance from the left edge of th
e | |
2907 * containing block to the left margin edge of a hypothetical box that wou
ld | |
2908 * have been the first box of the element if its 'position' property had | |
2909 * been 'static' and 'float' had been 'none'. The value is negative if the | |
2910 * hypothetical box is to the left of the containing block. | |
2911 * * The static position for 'right' is the distance from the right edge of
the | |
2912 * containing block to the right margin edge of the same hypothetical box
as | |
2913 * above. The value is positive if the hypothetical box is to the left of
the | |
2914 * containing block's edge. | |
2915 * | |
2916 * But rather than actually calculating the dimensions of that hypothetical
box, | |
2917 * user agents are free to make a guess at its probable position. | |
2918 * | |
2919 * For the purposes of calculating the static position, the containing block
of | |
2920 * fixed positioned elements is the initial containing block instead of the | |
2921 * viewport, and all scrollable boxes should be assumed to be scrolled to th
eir | |
2922 * origin. | |
2923 \*--------------------------------------------------------------------------
-*/ | |
2924 | |
2925 // see FIXME 1 | |
2926 // Calculate the static distance if needed. | |
2927 computeInlineStaticDistance(logicalLeftLength, logicalRightLength, this, con
tainerBlock, containerLogicalWidth); | |
2928 | |
2929 // Calculate constraint equation values for 'width' case. | |
2930 computePositionedLogicalWidthUsing(style()->logicalWidth(), containerBlock,
containerDirection, | |
2931 containerLogicalWidth, bordersPlusPadding
, | |
2932 logicalLeftLength, logicalRightLength, ma
rginLogicalLeft, marginLogicalRight, | |
2933 computedValues); | |
2934 | |
2935 // Calculate constraint equation values for 'max-width' case. | |
2936 if (!style()->logicalMaxWidth().isMaxSizeNone()) { | |
2937 LogicalExtentComputedValues maxValues; | |
2938 | |
2939 computePositionedLogicalWidthUsing(style()->logicalMaxWidth(), container
Block, containerDirection, | |
2940 containerLogicalWidth, bordersPlusPad
ding, | |
2941 logicalLeftLength, logicalRightLength
, marginLogicalLeft, marginLogicalRight, | |
2942 maxValues); | |
2943 | |
2944 if (computedValues.m_extent > maxValues.m_extent) { | |
2945 computedValues.m_extent = maxValues.m_extent; | |
2946 computedValues.m_position = maxValues.m_position; | |
2947 computedValues.m_margins.m_start = maxValues.m_margins.m_start; | |
2948 computedValues.m_margins.m_end = maxValues.m_margins.m_end; | |
2949 } | |
2950 } | |
2951 | |
2952 // Calculate constraint equation values for 'min-width' case. | |
2953 if (!style()->logicalMinWidth().isZero() || style()->logicalMinWidth().isInt
rinsic()) { | |
2954 LogicalExtentComputedValues minValues; | |
2955 | |
2956 computePositionedLogicalWidthUsing(style()->logicalMinWidth(), container
Block, containerDirection, | |
2957 containerLogicalWidth, bordersPlusPad
ding, | |
2958 logicalLeftLength, logicalRightLength
, marginLogicalLeft, marginLogicalRight, | |
2959 minValues); | |
2960 | |
2961 if (computedValues.m_extent < minValues.m_extent) { | |
2962 computedValues.m_extent = minValues.m_extent; | |
2963 computedValues.m_position = minValues.m_position; | |
2964 computedValues.m_margins.m_start = minValues.m_margins.m_start; | |
2965 computedValues.m_margins.m_end = minValues.m_margins.m_end; | |
2966 } | |
2967 } | |
2968 | |
2969 if (!style()->hasStaticInlinePosition(isHorizontal)) | |
2970 computedValues.m_position += extraInlineOffset(); | |
2971 | |
2972 computedValues.m_extent += bordersPlusPadding; | |
2973 } | |
2974 | |
2975 static void computeLogicalLeftPositionedOffset(LayoutUnit& logicalLeftPos, const
RenderBox* child, LayoutUnit logicalWidthValue, const LayoutBoxModelObject* con
tainerBlock, LayoutUnit containerLogicalWidth) | |
2976 { | |
2977 // Deal with differing writing modes here. Our offset needs to be in the co
ntaining block's coordinate space. If the containing block is flipped | |
2978 // along this axis, then we need to flip the coordinate. This can only happ
en if the containing block is both a flipped mode and perpendicular to us. | |
2979 if (containerBlock->isHorizontalWritingMode() != child->isHorizontalWritingM
ode() && containerBlock->style()->isFlippedBlocksWritingMode()) { | |
2980 logicalLeftPos = containerLogicalWidth - logicalWidthValue - logicalLeft
Pos; | |
2981 logicalLeftPos += (child->isHorizontalWritingMode() ? containerBlock->bo
rderRight() : containerBlock->borderBottom()); | |
2982 } else { | |
2983 logicalLeftPos += (child->isHorizontalWritingMode() ? containerBlock->bo
rderLeft() : containerBlock->borderTop()); | |
2984 } | |
2985 } | |
2986 | |
2987 LayoutUnit RenderBox::shrinkToFitLogicalWidth(LayoutUnit availableLogicalWidth,
LayoutUnit bordersPlusPadding) const | |
2988 { | |
2989 LayoutUnit preferredLogicalWidth = maxPreferredLogicalWidth() - bordersPlusP
adding; | |
2990 LayoutUnit preferredMinLogicalWidth = minPreferredLogicalWidth() - bordersPl
usPadding; | |
2991 return std::min(std::max(preferredMinLogicalWidth, availableLogicalWidth), p
referredLogicalWidth); | |
2992 } | |
2993 | |
2994 void RenderBox::computePositionedLogicalWidthUsing(Length logicalWidth, const La
youtBoxModelObject* containerBlock, TextDirection containerDirection, | |
2995 LayoutUnit containerLogicalWi
dth, LayoutUnit bordersPlusPadding, | |
2996 const Length& logicalLeft, co
nst Length& logicalRight, const Length& marginLogicalLeft, | |
2997 const Length& marginLogicalRi
ght, LogicalExtentComputedValues& computedValues) const | |
2998 { | |
2999 if (logicalWidth.isIntrinsic()) | |
3000 logicalWidth = Length(computeIntrinsicLogicalWidthUsing(logicalWidth, co
ntainerLogicalWidth, bordersPlusPadding) - bordersPlusPadding, Fixed); | |
3001 | |
3002 // 'left' and 'right' cannot both be 'auto' because one would of been | |
3003 // converted to the static position already | |
3004 ASSERT(!(logicalLeft.isAuto() && logicalRight.isAuto())); | |
3005 | |
3006 // minimumValueForLength will convert 'auto' to 0 so that it doesn't impact
the available space computation below. | |
3007 LayoutUnit logicalLeftValue = minimumValueForLength(logicalLeft, containerLo
gicalWidth); | |
3008 LayoutUnit logicalRightValue = minimumValueForLength(logicalRight, container
LogicalWidth); | |
3009 | |
3010 const LayoutUnit containerRelativeLogicalWidth = containingBlockLogicalWidth
ForPositioned(containerBlock, false); | |
3011 | |
3012 bool logicalWidthIsAuto = logicalWidth.isIntrinsicOrAuto(); | |
3013 bool logicalLeftIsAuto = logicalLeft.isAuto(); | |
3014 bool logicalRightIsAuto = logicalRight.isAuto(); | |
3015 LayoutUnit& marginLogicalLeftValue = style()->isLeftToRightDirection() ? com
putedValues.m_margins.m_start : computedValues.m_margins.m_end; | |
3016 LayoutUnit& marginLogicalRightValue = style()->isLeftToRightDirection() ? co
mputedValues.m_margins.m_end : computedValues.m_margins.m_start; | |
3017 if (!logicalLeftIsAuto && !logicalWidthIsAuto && !logicalRightIsAuto) { | |
3018 /*----------------------------------------------------------------------
-*\ | |
3019 * If none of the three is 'auto': If both 'margin-left' and 'margin- | |
3020 * right' are 'auto', solve the equation under the extra constraint that | |
3021 * the two margins get equal values, unless this would make them negativ
e, | |
3022 * in which case when direction of the containing block is 'ltr' ('rtl')
, | |
3023 * set 'margin-left' ('margin-right') to zero and solve for 'margin-righ
t' | |
3024 * ('margin-left'). If one of 'margin-left' or 'margin-right' is 'auto', | |
3025 * solve the equation for that value. If the values are over-constrained
, | |
3026 * ignore the value for 'left' (in case the 'direction' property of the | |
3027 * containing block is 'rtl') or 'right' (in case 'direction' is 'ltr') | |
3028 * and solve for that value. | |
3029 \*----------------------------------------------------------------------
-*/ | |
3030 // NOTE: It is not necessary to solve for 'right' in the over constrain
ed | |
3031 // case because the value is not used for any further calculations. | |
3032 | |
3033 computedValues.m_extent = adjustContentBoxLogicalWidthForBoxSizing(value
ForLength(logicalWidth, containerLogicalWidth)); | |
3034 | |
3035 const LayoutUnit availableSpace = containerLogicalWidth - (logicalLeftVa
lue + computedValues.m_extent + logicalRightValue + bordersPlusPadding); | |
3036 | |
3037 // Margins are now the only unknown | |
3038 if (marginLogicalLeft.isAuto() && marginLogicalRight.isAuto()) { | |
3039 // Both margins auto, solve for equality | |
3040 if (availableSpace >= 0) { | |
3041 marginLogicalLeftValue = availableSpace / 2; // split the differ
ence | |
3042 marginLogicalRightValue = availableSpace - marginLogicalLeftValu
e; // account for odd valued differences | |
3043 } else { | |
3044 // Use the containing block's direction rather than the parent b
lock's | |
3045 // per CSS 2.1 reference test abspos-non-replaced-width-margin-0
00. | |
3046 if (containerDirection == LTR) { | |
3047 marginLogicalLeftValue = 0; | |
3048 marginLogicalRightValue = availableSpace; // will be negativ
e | |
3049 } else { | |
3050 marginLogicalLeftValue = availableSpace; // will be negative | |
3051 marginLogicalRightValue = 0; | |
3052 } | |
3053 } | |
3054 } else if (marginLogicalLeft.isAuto()) { | |
3055 // Solve for left margin | |
3056 marginLogicalRightValue = valueForLength(marginLogicalRight, contain
erRelativeLogicalWidth); | |
3057 marginLogicalLeftValue = availableSpace - marginLogicalRightValue; | |
3058 } else if (marginLogicalRight.isAuto()) { | |
3059 // Solve for right margin | |
3060 marginLogicalLeftValue = valueForLength(marginLogicalLeft, container
RelativeLogicalWidth); | |
3061 marginLogicalRightValue = availableSpace - marginLogicalLeftValue; | |
3062 } else { | |
3063 // Over-constrained, solve for left if direction is RTL | |
3064 marginLogicalLeftValue = valueForLength(marginLogicalLeft, container
RelativeLogicalWidth); | |
3065 marginLogicalRightValue = valueForLength(marginLogicalRight, contain
erRelativeLogicalWidth); | |
3066 | |
3067 // Use the containing block's direction rather than the parent block
's | |
3068 // per CSS 2.1 reference test abspos-non-replaced-width-margin-000. | |
3069 if (containerDirection == RTL) | |
3070 logicalLeftValue = (availableSpace + logicalLeftValue) - marginL
ogicalLeftValue - marginLogicalRightValue; | |
3071 } | |
3072 } else { | |
3073 /*--------------------------------------------------------------------*\ | |
3074 * Otherwise, set 'auto' values for 'margin-left' and 'margin-right' | |
3075 * to 0, and pick the one of the following six rules that applies. | |
3076 * | |
3077 * 1. 'left' and 'width' are 'auto' and 'right' is not 'auto', then the | |
3078 * width is shrink-to-fit. Then solve for 'left' | |
3079 * | |
3080 * OMIT RULE 2 AS IT SHOULD NEVER BE HIT | |
3081 * ------------------------------------------------------------------ | |
3082 * 2. 'left' and 'right' are 'auto' and 'width' is not 'auto', then if | |
3083 * the 'direction' property of the containing block is 'ltr' set | |
3084 * 'left' to the static position, otherwise set 'right' to the | |
3085 * static position. Then solve for 'left' (if 'direction is 'rtl') | |
3086 * or 'right' (if 'direction' is 'ltr'). | |
3087 * ------------------------------------------------------------------ | |
3088 * | |
3089 * 3. 'width' and 'right' are 'auto' and 'left' is not 'auto', then the | |
3090 * width is shrink-to-fit . Then solve for 'right' | |
3091 * 4. 'left' is 'auto', 'width' and 'right' are not 'auto', then solve | |
3092 * for 'left' | |
3093 * 5. 'width' is 'auto', 'left' and 'right' are not 'auto', then solve | |
3094 * for 'width' | |
3095 * 6. 'right' is 'auto', 'left' and 'width' are not 'auto', then solve | |
3096 * for 'right' | |
3097 * | |
3098 * Calculation of the shrink-to-fit width is similar to calculating the | |
3099 * width of a table cell using the automatic table layout algorithm. | |
3100 * Roughly: calculate the preferred width by formatting the content | |
3101 * without breaking lines other than where explicit line breaks occur, | |
3102 * and also calculate the preferred minimum width, e.g., by trying all | |
3103 * possible line breaks. CSS 2.1 does not define the exact algorithm. | |
3104 * Thirdly, calculate the available width: this is found by solving | |
3105 * for 'width' after setting 'left' (in case 1) or 'right' (in case 3) | |
3106 * to 0. | |
3107 * | |
3108 * Then the shrink-to-fit width is: | |
3109 * min(max(preferred minimum width, available width), preferred width). | |
3110 \*--------------------------------------------------------------------*/ | |
3111 // NOTE: For rules 3 and 6 it is not necessary to solve for 'right' | |
3112 // because the value is not used for any further calculations. | |
3113 | |
3114 // Calculate margins, 'auto' margins are ignored. | |
3115 marginLogicalLeftValue = minimumValueForLength(marginLogicalLeft, contai
nerRelativeLogicalWidth); | |
3116 marginLogicalRightValue = minimumValueForLength(marginLogicalRight, cont
ainerRelativeLogicalWidth); | |
3117 | |
3118 const LayoutUnit availableSpace = containerLogicalWidth - (marginLogical
LeftValue + marginLogicalRightValue + logicalLeftValue + logicalRightValue + bor
dersPlusPadding); | |
3119 | |
3120 // FIXME: Is there a faster way to find the correct case? | |
3121 // Use rule/case that applies. | |
3122 if (logicalLeftIsAuto && logicalWidthIsAuto && !logicalRightIsAuto) { | |
3123 // RULE 1: (use shrink-to-fit for width, and solve of left) | |
3124 computedValues.m_extent = shrinkToFitLogicalWidth(availableSpace, bo
rdersPlusPadding); | |
3125 logicalLeftValue = availableSpace - computedValues.m_extent; | |
3126 } else if (!logicalLeftIsAuto && logicalWidthIsAuto && logicalRightIsAut
o) { | |
3127 // RULE 3: (use shrink-to-fit for width, and no need solve of right) | |
3128 computedValues.m_extent = shrinkToFitLogicalWidth(availableSpace, bo
rdersPlusPadding); | |
3129 } else if (logicalLeftIsAuto && !logicalWidthIsAuto && !logicalRightIsAu
to) { | |
3130 // RULE 4: (solve for left) | |
3131 computedValues.m_extent = adjustContentBoxLogicalWidthForBoxSizing(v
alueForLength(logicalWidth, containerLogicalWidth)); | |
3132 logicalLeftValue = availableSpace - computedValues.m_extent; | |
3133 } else if (!logicalLeftIsAuto && logicalWidthIsAuto && !logicalRightIsAu
to) { | |
3134 // RULE 5: (solve for width) | |
3135 if (autoWidthShouldFitContent()) | |
3136 computedValues.m_extent = shrinkToFitLogicalWidth(availableSpace
, bordersPlusPadding); | |
3137 else | |
3138 computedValues.m_extent = std::max(LayoutUnit(), availableSpace)
; | |
3139 } else if (!logicalLeftIsAuto && !logicalWidthIsAuto && logicalRightIsAu
to) { | |
3140 // RULE 6: (no need solve for right) | |
3141 computedValues.m_extent = adjustContentBoxLogicalWidthForBoxSizing(v
alueForLength(logicalWidth, containerLogicalWidth)); | |
3142 } | |
3143 } | |
3144 | |
3145 // Use computed values to calculate the horizontal position. | |
3146 | |
3147 // FIXME: This hack is needed to calculate the logical left position for a
'rtl' relatively | |
3148 // positioned, inline because right now, it is using the logical left positi
on | |
3149 // of the first line box when really it should use the last line box. When | |
3150 // this is fixed elsewhere, this block should be removed. | |
3151 if (containerBlock->isRenderInline() && !containerBlock->style()->isLeftToRi
ghtDirection()) { | |
3152 const RenderInline* flow = toRenderInline(containerBlock); | |
3153 InlineFlowBox* firstLine = flow->firstLineBox(); | |
3154 InlineFlowBox* lastLine = flow->lastLineBox(); | |
3155 if (firstLine && lastLine && firstLine != lastLine) { | |
3156 computedValues.m_position = logicalLeftValue + marginLogicalLeftValu
e + lastLine->borderLogicalLeft() + (lastLine->logicalLeft() - firstLine->logica
lLeft()); | |
3157 return; | |
3158 } | |
3159 } | |
3160 | |
3161 if (containerBlock->isBox() && toRenderBox(containerBlock)->scrollsOverflowY
() && containerBlock->style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()
) { | |
3162 logicalLeftValue = logicalLeftValue + toRenderBox(containerBlock)->verti
calScrollbarWidth(); | |
3163 } | |
3164 | |
3165 computedValues.m_position = logicalLeftValue + marginLogicalLeftValue; | |
3166 computeLogicalLeftPositionedOffset(computedValues.m_position, this, computed
Values.m_extent, containerBlock, containerLogicalWidth); | |
3167 } | |
3168 | |
3169 static void computeBlockStaticDistance(Length& logicalTop, Length& logicalBottom
, const RenderBox* child, const LayoutBoxModelObject* containerBlock) | |
3170 { | |
3171 if (!logicalTop.isAuto() || !logicalBottom.isAuto()) | |
3172 return; | |
3173 | |
3174 // FIXME: The static distance computation has not been patched for mixed wri
ting modes. | |
3175 LayoutUnit staticLogicalTop = child->layer()->staticBlockPosition() - contai
nerBlock->borderBefore(); | |
3176 for (LayoutObject* curr = child->parent(); curr && curr != containerBlock; c
urr = curr->container()) { | |
3177 if (curr->isBox() && !curr->isTableRow()) | |
3178 staticLogicalTop += toRenderBox(curr)->logicalTop(); | |
3179 } | |
3180 logicalTop.setValue(Fixed, staticLogicalTop); | |
3181 } | |
3182 | |
3183 void RenderBox::computePositionedLogicalHeight(LogicalExtentComputedValues& comp
utedValues) const | |
3184 { | |
3185 if (isReplaced()) { | |
3186 computePositionedLogicalHeightReplaced(computedValues); | |
3187 return; | |
3188 } | |
3189 | |
3190 // The following is based off of the W3C Working Draft from April 11, 2006 o
f | |
3191 // CSS 2.1: Section 10.6.4 "Absolutely positioned, non-replaced elements" | |
3192 // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-non-replace
d-height> | |
3193 // (block-style-comments in this function and in computePositionedLogicalHei
ghtUsing() | |
3194 // correspond to text from the spec) | |
3195 | |
3196 | |
3197 // We don't use containingBlock(), since we may be positioned by an enclosin
g relpositioned inline. | |
3198 const LayoutBoxModelObject* containerBlock = toLayoutBoxModelObject(containe
r()); | |
3199 | |
3200 const LayoutUnit containerLogicalHeight = containingBlockLogicalHeightForPos
itioned(containerBlock); | |
3201 | |
3202 const LayoutStyle& styleToUse = styleRef(); | |
3203 const LayoutUnit bordersPlusPadding = borderAndPaddingLogicalHeight(); | |
3204 const Length marginBefore = styleToUse.marginBefore(); | |
3205 const Length marginAfter = styleToUse.marginAfter(); | |
3206 Length logicalTopLength = styleToUse.logicalTop(); | |
3207 Length logicalBottomLength = styleToUse.logicalBottom(); | |
3208 | |
3209 /*--------------------------------------------------------------------------
-*\ | |
3210 * For the purposes of this section and the next, the term "static position" | |
3211 * (of an element) refers, roughly, to the position an element would have ha
d | |
3212 * in the normal flow. More precisely, the static position for 'top' is the | |
3213 * distance from the top edge of the containing block to the top margin edge | |
3214 * of a hypothetical box that would have been the first box of the element i
f | |
3215 * its 'position' property had been 'static' and 'float' had been 'none'. Th
e | |
3216 * value is negative if the hypothetical box is above the containing block. | |
3217 * | |
3218 * But rather than actually calculating the dimensions of that hypothetical | |
3219 * box, user agents are free to make a guess at its probable position. | |
3220 * | |
3221 * For the purposes of calculating the static position, the containing block | |
3222 * of fixed positioned elements is the initial containing block instead of | |
3223 * the viewport. | |
3224 \*--------------------------------------------------------------------------
-*/ | |
3225 | |
3226 // see FIXME 1 | |
3227 // Calculate the static distance if needed. | |
3228 computeBlockStaticDistance(logicalTopLength, logicalBottomLength, this, cont
ainerBlock); | |
3229 | |
3230 // Calculate constraint equation values for 'height' case. | |
3231 LayoutUnit logicalHeight = computedValues.m_extent; | |
3232 computePositionedLogicalHeightUsing(styleToUse.logicalHeight(), containerBlo
ck, containerLogicalHeight, bordersPlusPadding, logicalHeight, | |
3233 logicalTopLength, logicalBottomLength, m
arginBefore, marginAfter, | |
3234 computedValues); | |
3235 | |
3236 // Avoid doing any work in the common case (where the values of min-height a
nd max-height are their defaults). | |
3237 // see FIXME 2 | |
3238 | |
3239 // Calculate constraint equation values for 'max-height' case. | |
3240 if (!styleToUse.logicalMaxHeight().isMaxSizeNone()) { | |
3241 LogicalExtentComputedValues maxValues; | |
3242 | |
3243 computePositionedLogicalHeightUsing(styleToUse.logicalMaxHeight(), conta
inerBlock, containerLogicalHeight, bordersPlusPadding, logicalHeight, | |
3244 logicalTopLength, logicalBottomLengt
h, marginBefore, marginAfter, | |
3245 maxValues); | |
3246 | |
3247 if (computedValues.m_extent > maxValues.m_extent) { | |
3248 computedValues.m_extent = maxValues.m_extent; | |
3249 computedValues.m_position = maxValues.m_position; | |
3250 computedValues.m_margins.m_before = maxValues.m_margins.m_before; | |
3251 computedValues.m_margins.m_after = maxValues.m_margins.m_after; | |
3252 } | |
3253 } | |
3254 | |
3255 // Calculate constraint equation values for 'min-height' case. | |
3256 if (!styleToUse.logicalMinHeight().isZero() || styleToUse.logicalMinHeight()
.isIntrinsic()) { | |
3257 LogicalExtentComputedValues minValues; | |
3258 | |
3259 computePositionedLogicalHeightUsing(styleToUse.logicalMinHeight(), conta
inerBlock, containerLogicalHeight, bordersPlusPadding, logicalHeight, | |
3260 logicalTopLength, logicalBottomLengt
h, marginBefore, marginAfter, | |
3261 minValues); | |
3262 | |
3263 if (computedValues.m_extent < minValues.m_extent) { | |
3264 computedValues.m_extent = minValues.m_extent; | |
3265 computedValues.m_position = minValues.m_position; | |
3266 computedValues.m_margins.m_before = minValues.m_margins.m_before; | |
3267 computedValues.m_margins.m_after = minValues.m_margins.m_after; | |
3268 } | |
3269 } | |
3270 | |
3271 if (!style()->hasStaticBlockPosition(isHorizontalWritingMode())) | |
3272 computedValues.m_position += extraBlockOffset(); | |
3273 | |
3274 // Set final height value. | |
3275 computedValues.m_extent += bordersPlusPadding; | |
3276 } | |
3277 | |
3278 static void computeLogicalTopPositionedOffset(LayoutUnit& logicalTopPos, const R
enderBox* child, LayoutUnit logicalHeightValue, const LayoutBoxModelObject* cont
ainerBlock, LayoutUnit containerLogicalHeight) | |
3279 { | |
3280 // Deal with differing writing modes here. Our offset needs to be in the co
ntaining block's coordinate space. If the containing block is flipped | |
3281 // along this axis, then we need to flip the coordinate. This can only happ
en if the containing block is both a flipped mode and perpendicular to us. | |
3282 if ((child->style()->isFlippedBlocksWritingMode() && child->isHorizontalWrit
ingMode() != containerBlock->isHorizontalWritingMode()) | |
3283 || (child->style()->isFlippedBlocksWritingMode() != containerBlock->styl
e()->isFlippedBlocksWritingMode() && child->isHorizontalWritingMode() == contain
erBlock->isHorizontalWritingMode())) | |
3284 logicalTopPos = containerLogicalHeight - logicalHeightValue - logicalTop
Pos; | |
3285 | |
3286 // Our offset is from the logical bottom edge in a flipped environment, e.g.
, right for vertical-rl and bottom for horizontal-bt. | |
3287 if (containerBlock->style()->isFlippedBlocksWritingMode() && child->isHorizo
ntalWritingMode() == containerBlock->isHorizontalWritingMode()) { | |
3288 if (child->isHorizontalWritingMode()) | |
3289 logicalTopPos += containerBlock->borderBottom(); | |
3290 else | |
3291 logicalTopPos += containerBlock->borderRight(); | |
3292 } else { | |
3293 if (child->isHorizontalWritingMode()) | |
3294 logicalTopPos += containerBlock->borderTop(); | |
3295 else | |
3296 logicalTopPos += containerBlock->borderLeft(); | |
3297 } | |
3298 } | |
3299 | |
3300 void RenderBox::computePositionedLogicalHeightUsing(Length logicalHeightLength,
const LayoutBoxModelObject* containerBlock, | |
3301 LayoutUnit containerLogicalH
eight, LayoutUnit bordersPlusPadding, LayoutUnit logicalHeight, | |
3302 const Length& logicalTop, co
nst Length& logicalBottom, const Length& marginBefore, | |
3303 const Length& marginAfter, L
ogicalExtentComputedValues& computedValues) const | |
3304 { | |
3305 // 'top' and 'bottom' cannot both be 'auto' because 'top would of been | |
3306 // converted to the static position in computePositionedLogicalHeight() | |
3307 ASSERT(!(logicalTop.isAuto() && logicalBottom.isAuto())); | |
3308 | |
3309 LayoutUnit logicalHeightValue; | |
3310 LayoutUnit contentLogicalHeight = logicalHeight - bordersPlusPadding; | |
3311 | |
3312 const LayoutUnit containerRelativeLogicalWidth = containingBlockLogicalWidth
ForPositioned(containerBlock, false); | |
3313 | |
3314 LayoutUnit logicalTopValue = 0; | |
3315 | |
3316 bool logicalHeightIsAuto = logicalHeightLength.isAuto(); | |
3317 bool logicalTopIsAuto = logicalTop.isAuto(); | |
3318 bool logicalBottomIsAuto = logicalBottom.isAuto(); | |
3319 | |
3320 LayoutUnit resolvedLogicalHeight; | |
3321 // Height is never unsolved for tables. | |
3322 if (isTable()) { | |
3323 resolvedLogicalHeight = contentLogicalHeight; | |
3324 logicalHeightIsAuto = false; | |
3325 } else { | |
3326 if (logicalHeightLength.isIntrinsic()) | |
3327 resolvedLogicalHeight = computeIntrinsicLogicalContentHeightUsing(lo
gicalHeightLength, contentLogicalHeight, bordersPlusPadding); | |
3328 else | |
3329 resolvedLogicalHeight = adjustContentBoxLogicalHeightForBoxSizing(va
lueForLength(logicalHeightLength, containerLogicalHeight)); | |
3330 } | |
3331 | |
3332 if (!logicalTopIsAuto && !logicalHeightIsAuto && !logicalBottomIsAuto) { | |
3333 /*----------------------------------------------------------------------
-*\ | |
3334 * If none of the three are 'auto': If both 'margin-top' and 'margin- | |
3335 * bottom' are 'auto', solve the equation under the extra constraint tha
t | |
3336 * the two margins get equal values. If one of 'margin-top' or 'margin- | |
3337 * bottom' is 'auto', solve the equation for that value. If the values | |
3338 * are over-constrained, ignore the value for 'bottom' and solve for tha
t | |
3339 * value. | |
3340 \*----------------------------------------------------------------------
-*/ | |
3341 // NOTE: It is not necessary to solve for 'bottom' in the over constrai
ned | |
3342 // case because the value is not used for any further calculations. | |
3343 | |
3344 logicalHeightValue = resolvedLogicalHeight; | |
3345 logicalTopValue = valueForLength(logicalTop, containerLogicalHeight); | |
3346 | |
3347 const LayoutUnit availableSpace = containerLogicalHeight - (logicalTopVa
lue + logicalHeightValue + valueForLength(logicalBottom, containerLogicalHeight)
+ bordersPlusPadding); | |
3348 | |
3349 // Margins are now the only unknown | |
3350 if (marginBefore.isAuto() && marginAfter.isAuto()) { | |
3351 // Both margins auto, solve for equality | |
3352 // NOTE: This may result in negative values. | |
3353 computedValues.m_margins.m_before = availableSpace / 2; // split the
difference | |
3354 computedValues.m_margins.m_after = availableSpace - computedValues.m
_margins.m_before; // account for odd valued differences | |
3355 } else if (marginBefore.isAuto()) { | |
3356 // Solve for top margin | |
3357 computedValues.m_margins.m_after = valueForLength(marginAfter, conta
inerRelativeLogicalWidth); | |
3358 computedValues.m_margins.m_before = availableSpace - computedValues.
m_margins.m_after; | |
3359 } else if (marginAfter.isAuto()) { | |
3360 // Solve for bottom margin | |
3361 computedValues.m_margins.m_before = valueForLength(marginBefore, con
tainerRelativeLogicalWidth); | |
3362 computedValues.m_margins.m_after = availableSpace - computedValues.m
_margins.m_before; | |
3363 } else { | |
3364 // Over-constrained, (no need solve for bottom) | |
3365 computedValues.m_margins.m_before = valueForLength(marginBefore, con
tainerRelativeLogicalWidth); | |
3366 computedValues.m_margins.m_after = valueForLength(marginAfter, conta
inerRelativeLogicalWidth); | |
3367 } | |
3368 } else { | |
3369 /*--------------------------------------------------------------------*\ | |
3370 * Otherwise, set 'auto' values for 'margin-top' and 'margin-bottom' | |
3371 * to 0, and pick the one of the following six rules that applies. | |
3372 * | |
3373 * 1. 'top' and 'height' are 'auto' and 'bottom' is not 'auto', then | |
3374 * the height is based on the content, and solve for 'top'. | |
3375 * | |
3376 * OMIT RULE 2 AS IT SHOULD NEVER BE HIT | |
3377 * ------------------------------------------------------------------ | |
3378 * 2. 'top' and 'bottom' are 'auto' and 'height' is not 'auto', then | |
3379 * set 'top' to the static position, and solve for 'bottom'. | |
3380 * ------------------------------------------------------------------ | |
3381 * | |
3382 * 3. 'height' and 'bottom' are 'auto' and 'top' is not 'auto', then | |
3383 * the height is based on the content, and solve for 'bottom'. | |
3384 * 4. 'top' is 'auto', 'height' and 'bottom' are not 'auto', and | |
3385 * solve for 'top'. | |
3386 * 5. 'height' is 'auto', 'top' and 'bottom' are not 'auto', and | |
3387 * solve for 'height'. | |
3388 * 6. 'bottom' is 'auto', 'top' and 'height' are not 'auto', and | |
3389 * solve for 'bottom'. | |
3390 \*--------------------------------------------------------------------*/ | |
3391 // NOTE: For rules 3 and 6 it is not necessary to solve for 'bottom' | |
3392 // because the value is not used for any further calculations. | |
3393 | |
3394 // Calculate margins, 'auto' margins are ignored. | |
3395 computedValues.m_margins.m_before = minimumValueForLength(marginBefore,
containerRelativeLogicalWidth); | |
3396 computedValues.m_margins.m_after = minimumValueForLength(marginAfter, co
ntainerRelativeLogicalWidth); | |
3397 | |
3398 const LayoutUnit availableSpace = containerLogicalHeight - (computedValu
es.m_margins.m_before + computedValues.m_margins.m_after + bordersPlusPadding); | |
3399 | |
3400 // Use rule/case that applies. | |
3401 if (logicalTopIsAuto && logicalHeightIsAuto && !logicalBottomIsAuto) { | |
3402 // RULE 1: (height is content based, solve of top) | |
3403 logicalHeightValue = contentLogicalHeight; | |
3404 logicalTopValue = availableSpace - (logicalHeightValue + valueForLen
gth(logicalBottom, containerLogicalHeight)); | |
3405 } else if (!logicalTopIsAuto && logicalHeightIsAuto && logicalBottomIsAu
to) { | |
3406 // RULE 3: (height is content based, no need solve of bottom) | |
3407 logicalTopValue = valueForLength(logicalTop, containerLogicalHeight)
; | |
3408 logicalHeightValue = contentLogicalHeight; | |
3409 } else if (logicalTopIsAuto && !logicalHeightIsAuto && !logicalBottomIsA
uto) { | |
3410 // RULE 4: (solve of top) | |
3411 logicalHeightValue = resolvedLogicalHeight; | |
3412 logicalTopValue = availableSpace - (logicalHeightValue + valueForLen
gth(logicalBottom, containerLogicalHeight)); | |
3413 } else if (!logicalTopIsAuto && logicalHeightIsAuto && !logicalBottomIsA
uto) { | |
3414 // RULE 5: (solve of height) | |
3415 logicalTopValue = valueForLength(logicalTop, containerLogicalHeight)
; | |
3416 logicalHeightValue = std::max(LayoutUnit(), availableSpace - (logica
lTopValue + valueForLength(logicalBottom, containerLogicalHeight))); | |
3417 } else if (!logicalTopIsAuto && !logicalHeightIsAuto && logicalBottomIsA
uto) { | |
3418 // RULE 6: (no need solve of bottom) | |
3419 logicalHeightValue = resolvedLogicalHeight; | |
3420 logicalTopValue = valueForLength(logicalTop, containerLogicalHeight)
; | |
3421 } | |
3422 } | |
3423 computedValues.m_extent = logicalHeightValue; | |
3424 | |
3425 // Use computed values to calculate the vertical position. | |
3426 computedValues.m_position = logicalTopValue + computedValues.m_margins.m_bef
ore; | |
3427 computeLogicalTopPositionedOffset(computedValues.m_position, this, logicalHe
ightValue, containerBlock, containerLogicalHeight); | |
3428 } | |
3429 | |
3430 void RenderBox::computePositionedLogicalWidthReplaced(LogicalExtentComputedValue
s& computedValues) const | |
3431 { | |
3432 // The following is based off of the W3C Working Draft from April 11, 2006 o
f | |
3433 // CSS 2.1: Section 10.3.8 "Absolutely positioned, replaced elements" | |
3434 // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-replaced-wi
dth> | |
3435 // (block-style-comments in this function correspond to text from the spec a
nd | |
3436 // the numbers correspond to numbers in spec) | |
3437 | |
3438 // We don't use containingBlock(), since we may be positioned by an enclosin
g | |
3439 // relative positioned inline. | |
3440 const LayoutBoxModelObject* containerBlock = toLayoutBoxModelObject(containe
r()); | |
3441 | |
3442 const LayoutUnit containerLogicalWidth = containingBlockLogicalWidthForPosit
ioned(containerBlock); | |
3443 const LayoutUnit containerRelativeLogicalWidth = containingBlockLogicalWidth
ForPositioned(containerBlock, false); | |
3444 | |
3445 // To match WinIE, in quirks mode use the parent's 'direction' property | |
3446 // instead of the the container block's. | |
3447 TextDirection containerDirection = containerBlock->style()->direction(); | |
3448 | |
3449 // Variables to solve. | |
3450 bool isHorizontal = isHorizontalWritingMode(); | |
3451 Length logicalLeft = style()->logicalLeft(); | |
3452 Length logicalRight = style()->logicalRight(); | |
3453 Length marginLogicalLeft = isHorizontal ? style()->marginLeft() : style()->m
arginTop(); | |
3454 Length marginLogicalRight = isHorizontal ? style()->marginRight() : style()-
>marginBottom(); | |
3455 LayoutUnit& marginLogicalLeftAlias = style()->isLeftToRightDirection() ? com
putedValues.m_margins.m_start : computedValues.m_margins.m_end; | |
3456 LayoutUnit& marginLogicalRightAlias = style()->isLeftToRightDirection() ? co
mputedValues.m_margins.m_end : computedValues.m_margins.m_start; | |
3457 | |
3458 /*-----------------------------------------------------------------------*\ | |
3459 * 1. The used value of 'width' is determined as for inline replaced | |
3460 * elements. | |
3461 \*-----------------------------------------------------------------------*/ | |
3462 // NOTE: This value of width is final in that the min/max width calculations | |
3463 // are dealt with in computeReplacedWidth(). This means that the steps to p
roduce | |
3464 // correct max/min in the non-replaced version, are not necessary. | |
3465 computedValues.m_extent = computeReplacedLogicalWidth() + borderAndPaddingLo
gicalWidth(); | |
3466 | |
3467 const LayoutUnit availableSpace = containerLogicalWidth - computedValues.m_e
xtent; | |
3468 | |
3469 /*-----------------------------------------------------------------------*\ | |
3470 * 2. If both 'left' and 'right' have the value 'auto', then if 'direction' | |
3471 * of the containing block is 'ltr', set 'left' to the static position; | |
3472 * else if 'direction' is 'rtl', set 'right' to the static position. | |
3473 \*-----------------------------------------------------------------------*/ | |
3474 // see FIXME 1 | |
3475 computeInlineStaticDistance(logicalLeft, logicalRight, this, containerBlock,
containerLogicalWidth); | |
3476 | |
3477 /*-----------------------------------------------------------------------*\ | |
3478 * 3. If 'left' or 'right' are 'auto', replace any 'auto' on 'margin-left' | |
3479 * or 'margin-right' with '0'. | |
3480 \*-----------------------------------------------------------------------*/ | |
3481 if (logicalLeft.isAuto() || logicalRight.isAuto()) { | |
3482 if (marginLogicalLeft.isAuto()) | |
3483 marginLogicalLeft.setValue(Fixed, 0); | |
3484 if (marginLogicalRight.isAuto()) | |
3485 marginLogicalRight.setValue(Fixed, 0); | |
3486 } | |
3487 | |
3488 /*-----------------------------------------------------------------------*\ | |
3489 * 4. If at this point both 'margin-left' and 'margin-right' are still | |
3490 * 'auto', solve the equation under the extra constraint that the two | |
3491 * margins must get equal values, unless this would make them negative, | |
3492 * in which case when the direction of the containing block is 'ltr' | |
3493 * ('rtl'), set 'margin-left' ('margin-right') to zero and solve for | |
3494 * 'margin-right' ('margin-left'). | |
3495 \*-----------------------------------------------------------------------*/ | |
3496 LayoutUnit logicalLeftValue = 0; | |
3497 LayoutUnit logicalRightValue = 0; | |
3498 | |
3499 if (marginLogicalLeft.isAuto() && marginLogicalRight.isAuto()) { | |
3500 // 'left' and 'right' cannot be 'auto' due to step 3 | |
3501 ASSERT(!(logicalLeft.isAuto() && logicalRight.isAuto())); | |
3502 | |
3503 logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth); | |
3504 logicalRightValue = valueForLength(logicalRight, containerLogicalWidth); | |
3505 | |
3506 LayoutUnit difference = availableSpace - (logicalLeftValue + logicalRigh
tValue); | |
3507 if (difference > 0) { | |
3508 marginLogicalLeftAlias = difference / 2; // split the difference | |
3509 marginLogicalRightAlias = difference - marginLogicalLeftAlias; // ac
count for odd valued differences | |
3510 } else { | |
3511 // Use the containing block's direction rather than the parent block
's | |
3512 // per CSS 2.1 reference test abspos-replaced-width-margin-000. | |
3513 if (containerDirection == LTR) { | |
3514 marginLogicalLeftAlias = 0; | |
3515 marginLogicalRightAlias = difference; // will be negative | |
3516 } else { | |
3517 marginLogicalLeftAlias = difference; // will be negative | |
3518 marginLogicalRightAlias = 0; | |
3519 } | |
3520 } | |
3521 | |
3522 /*-----------------------------------------------------------------------*\ | |
3523 * 5. If at this point there is an 'auto' left, solve the equation for | |
3524 * that value. | |
3525 \*-----------------------------------------------------------------------*/ | |
3526 } else if (logicalLeft.isAuto()) { | |
3527 marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerRela
tiveLogicalWidth); | |
3528 marginLogicalRightAlias = valueForLength(marginLogicalRight, containerRe
lativeLogicalWidth); | |
3529 logicalRightValue = valueForLength(logicalRight, containerLogicalWidth); | |
3530 | |
3531 // Solve for 'left' | |
3532 logicalLeftValue = availableSpace - (logicalRightValue + marginLogicalLe
ftAlias + marginLogicalRightAlias); | |
3533 } else if (logicalRight.isAuto()) { | |
3534 marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerRela
tiveLogicalWidth); | |
3535 marginLogicalRightAlias = valueForLength(marginLogicalRight, containerRe
lativeLogicalWidth); | |
3536 logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth); | |
3537 | |
3538 // Solve for 'right' | |
3539 logicalRightValue = availableSpace - (logicalLeftValue + marginLogicalLe
ftAlias + marginLogicalRightAlias); | |
3540 } else if (marginLogicalLeft.isAuto()) { | |
3541 marginLogicalRightAlias = valueForLength(marginLogicalRight, containerRe
lativeLogicalWidth); | |
3542 logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth); | |
3543 logicalRightValue = valueForLength(logicalRight, containerLogicalWidth); | |
3544 | |
3545 // Solve for 'margin-left' | |
3546 marginLogicalLeftAlias = availableSpace - (logicalLeftValue + logicalRig
htValue + marginLogicalRightAlias); | |
3547 } else if (marginLogicalRight.isAuto()) { | |
3548 marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerRela
tiveLogicalWidth); | |
3549 logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth); | |
3550 logicalRightValue = valueForLength(logicalRight, containerLogicalWidth); | |
3551 | |
3552 // Solve for 'margin-right' | |
3553 marginLogicalRightAlias = availableSpace - (logicalLeftValue + logicalRi
ghtValue + marginLogicalLeftAlias); | |
3554 } else { | |
3555 // Nothing is 'auto', just calculate the values. | |
3556 marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerRela
tiveLogicalWidth); | |
3557 marginLogicalRightAlias = valueForLength(marginLogicalRight, containerRe
lativeLogicalWidth); | |
3558 logicalRightValue = valueForLength(logicalRight, containerLogicalWidth); | |
3559 logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth); | |
3560 // If the containing block is right-to-left, then push the left position
as far to the right as possible | |
3561 if (containerDirection == RTL) { | |
3562 int totalLogicalWidth = computedValues.m_extent + logicalLeftValue +
logicalRightValue + marginLogicalLeftAlias + marginLogicalRightAlias; | |
3563 logicalLeftValue = containerLogicalWidth - (totalLogicalWidth - logi
calLeftValue); | |
3564 } | |
3565 } | |
3566 | |
3567 /*-----------------------------------------------------------------------*\ | |
3568 * 6. If at this point the values are over-constrained, ignore the value | |
3569 * for either 'left' (in case the 'direction' property of the | |
3570 * containing block is 'rtl') or 'right' (in case 'direction' is | |
3571 * 'ltr') and solve for that value. | |
3572 \*-----------------------------------------------------------------------*/ | |
3573 // NOTE: Constraints imposed by the width of the containing block and its co
ntent have already been accounted for above. | |
3574 | |
3575 // FIXME: Deal with differing writing modes here. Our offset needs to be in
the containing block's coordinate space, so that | |
3576 // can make the result here rather complicated to compute. | |
3577 | |
3578 // Use computed values to calculate the horizontal position. | |
3579 | |
3580 // FIXME: This hack is needed to calculate the logical left position for a '
rtl' relatively | |
3581 // positioned, inline containing block because right now, it is using the lo
gical left position | |
3582 // of the first line box when really it should use the last line box. When | |
3583 // this is fixed elsewhere, this block should be removed. | |
3584 if (containerBlock->isRenderInline() && !containerBlock->style()->isLeftToRi
ghtDirection()) { | |
3585 const RenderInline* flow = toRenderInline(containerBlock); | |
3586 InlineFlowBox* firstLine = flow->firstLineBox(); | |
3587 InlineFlowBox* lastLine = flow->lastLineBox(); | |
3588 if (firstLine && lastLine && firstLine != lastLine) { | |
3589 computedValues.m_position = logicalLeftValue + marginLogicalLeftAlia
s + lastLine->borderLogicalLeft() + (lastLine->logicalLeft() - firstLine->logica
lLeft()); | |
3590 return; | |
3591 } | |
3592 } | |
3593 | |
3594 LayoutUnit logicalLeftPos = logicalLeftValue + marginLogicalLeftAlias; | |
3595 computeLogicalLeftPositionedOffset(logicalLeftPos, this, computedValues.m_ex
tent, containerBlock, containerLogicalWidth); | |
3596 computedValues.m_position = logicalLeftPos; | |
3597 } | |
3598 | |
3599 void RenderBox::computePositionedLogicalHeightReplaced(LogicalExtentComputedValu
es& computedValues) const | |
3600 { | |
3601 // The following is based off of the W3C Working Draft from April 11, 2006 o
f | |
3602 // CSS 2.1: Section 10.6.5 "Absolutely positioned, replaced elements" | |
3603 // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-replaced-he
ight> | |
3604 // (block-style-comments in this function correspond to text from the spec a
nd | |
3605 // the numbers correspond to numbers in spec) | |
3606 | |
3607 // We don't use containingBlock(), since we may be positioned by an enclosin
g relpositioned inline. | |
3608 const LayoutBoxModelObject* containerBlock = toLayoutBoxModelObject(containe
r()); | |
3609 | |
3610 const LayoutUnit containerLogicalHeight = containingBlockLogicalHeightForPos
itioned(containerBlock); | |
3611 const LayoutUnit containerRelativeLogicalWidth = containingBlockLogicalWidth
ForPositioned(containerBlock, false); | |
3612 | |
3613 // Variables to solve. | |
3614 Length marginBefore = style()->marginBefore(); | |
3615 Length marginAfter = style()->marginAfter(); | |
3616 LayoutUnit& marginBeforeAlias = computedValues.m_margins.m_before; | |
3617 LayoutUnit& marginAfterAlias = computedValues.m_margins.m_after; | |
3618 | |
3619 Length logicalTop = style()->logicalTop(); | |
3620 Length logicalBottom = style()->logicalBottom(); | |
3621 | |
3622 /*-----------------------------------------------------------------------*\ | |
3623 * 1. The used value of 'height' is determined as for inline replaced | |
3624 * elements. | |
3625 \*-----------------------------------------------------------------------*/ | |
3626 // NOTE: This value of height is final in that the min/max height calculatio
ns | |
3627 // are dealt with in computeReplacedHeight(). This means that the steps to
produce | |
3628 // correct max/min in the non-replaced version, are not necessary. | |
3629 computedValues.m_extent = computeReplacedLogicalHeight() + borderAndPaddingL
ogicalHeight(); | |
3630 const LayoutUnit availableSpace = containerLogicalHeight - computedValues.m_
extent; | |
3631 | |
3632 /*-----------------------------------------------------------------------*\ | |
3633 * 2. If both 'top' and 'bottom' have the value 'auto', replace 'top' | |
3634 * with the element's static position. | |
3635 \*-----------------------------------------------------------------------*/ | |
3636 // see FIXME 1 | |
3637 computeBlockStaticDistance(logicalTop, logicalBottom, this, containerBlock); | |
3638 | |
3639 /*-----------------------------------------------------------------------*\ | |
3640 * 3. If 'bottom' is 'auto', replace any 'auto' on 'margin-top' or | |
3641 * 'margin-bottom' with '0'. | |
3642 \*-----------------------------------------------------------------------*/ | |
3643 // FIXME: The spec. says that this step should only be taken when bottom is | |
3644 // auto, but if only top is auto, this makes step 4 impossible. | |
3645 if (logicalTop.isAuto() || logicalBottom.isAuto()) { | |
3646 if (marginBefore.isAuto()) | |
3647 marginBefore.setValue(Fixed, 0); | |
3648 if (marginAfter.isAuto()) | |
3649 marginAfter.setValue(Fixed, 0); | |
3650 } | |
3651 | |
3652 /*-----------------------------------------------------------------------*\ | |
3653 * 4. If at this point both 'margin-top' and 'margin-bottom' are still | |
3654 * 'auto', solve the equation under the extra constraint that the two | |
3655 * margins must get equal values. | |
3656 \*-----------------------------------------------------------------------*/ | |
3657 LayoutUnit logicalTopValue = 0; | |
3658 LayoutUnit logicalBottomValue = 0; | |
3659 | |
3660 if (marginBefore.isAuto() && marginAfter.isAuto()) { | |
3661 // 'top' and 'bottom' cannot be 'auto' due to step 2 and 3 combined. | |
3662 ASSERT(!(logicalTop.isAuto() || logicalBottom.isAuto())); | |
3663 | |
3664 logicalTopValue = valueForLength(logicalTop, containerLogicalHeight); | |
3665 logicalBottomValue = valueForLength(logicalBottom, containerLogicalHeigh
t); | |
3666 | |
3667 LayoutUnit difference = availableSpace - (logicalTopValue + logicalBotto
mValue); | |
3668 // NOTE: This may result in negative values. | |
3669 marginBeforeAlias = difference / 2; // split the difference | |
3670 marginAfterAlias = difference - marginBeforeAlias; // account for odd va
lued differences | |
3671 | |
3672 /*-----------------------------------------------------------------------*\ | |
3673 * 5. If at this point there is only one 'auto' left, solve the equation | |
3674 * for that value. | |
3675 \*-----------------------------------------------------------------------*/ | |
3676 } else if (logicalTop.isAuto()) { | |
3677 marginBeforeAlias = valueForLength(marginBefore, containerRelativeLogica
lWidth); | |
3678 marginAfterAlias = valueForLength(marginAfter, containerRelativeLogicalW
idth); | |
3679 logicalBottomValue = valueForLength(logicalBottom, containerLogicalHeigh
t); | |
3680 | |
3681 // Solve for 'top' | |
3682 logicalTopValue = availableSpace - (logicalBottomValue + marginBeforeAli
as + marginAfterAlias); | |
3683 } else if (logicalBottom.isAuto()) { | |
3684 marginBeforeAlias = valueForLength(marginBefore, containerRelativeLogica
lWidth); | |
3685 marginAfterAlias = valueForLength(marginAfter, containerRelativeLogicalW
idth); | |
3686 logicalTopValue = valueForLength(logicalTop, containerLogicalHeight); | |
3687 | |
3688 // Solve for 'bottom' | |
3689 // NOTE: It is not necessary to solve for 'bottom' because we don't ever | |
3690 // use the value. | |
3691 } else if (marginBefore.isAuto()) { | |
3692 marginAfterAlias = valueForLength(marginAfter, containerRelativeLogicalW
idth); | |
3693 logicalTopValue = valueForLength(logicalTop, containerLogicalHeight); | |
3694 logicalBottomValue = valueForLength(logicalBottom, containerLogicalHeigh
t); | |
3695 | |
3696 // Solve for 'margin-top' | |
3697 marginBeforeAlias = availableSpace - (logicalTopValue + logicalBottomVal
ue + marginAfterAlias); | |
3698 } else if (marginAfter.isAuto()) { | |
3699 marginBeforeAlias = valueForLength(marginBefore, containerRelativeLogica
lWidth); | |
3700 logicalTopValue = valueForLength(logicalTop, containerLogicalHeight); | |
3701 logicalBottomValue = valueForLength(logicalBottom, containerLogicalHeigh
t); | |
3702 | |
3703 // Solve for 'margin-bottom' | |
3704 marginAfterAlias = availableSpace - (logicalTopValue + logicalBottomValu
e + marginBeforeAlias); | |
3705 } else { | |
3706 // Nothing is 'auto', just calculate the values. | |
3707 marginBeforeAlias = valueForLength(marginBefore, containerRelativeLogica
lWidth); | |
3708 marginAfterAlias = valueForLength(marginAfter, containerRelativeLogicalW
idth); | |
3709 logicalTopValue = valueForLength(logicalTop, containerLogicalHeight); | |
3710 // NOTE: It is not necessary to solve for 'bottom' because we don't ever | |
3711 // use the value. | |
3712 } | |
3713 | |
3714 /*-----------------------------------------------------------------------*\ | |
3715 * 6. If at this point the values are over-constrained, ignore the value | |
3716 * for 'bottom' and solve for that value. | |
3717 \*-----------------------------------------------------------------------*/ | |
3718 // NOTE: It is not necessary to do this step because we don't end up using | |
3719 // the value of 'bottom' regardless of whether the values are over-constrain
ed | |
3720 // or not. | |
3721 | |
3722 // Use computed values to calculate the vertical position. | |
3723 LayoutUnit logicalTopPos = logicalTopValue + marginBeforeAlias; | |
3724 computeLogicalTopPositionedOffset(logicalTopPos, this, computedValues.m_exte
nt, containerBlock, containerLogicalHeight); | |
3725 computedValues.m_position = logicalTopPos; | |
3726 } | |
3727 | |
3728 LayoutRect RenderBox::localCaretRect(InlineBox* box, int caretOffset, LayoutUnit
* extraWidthToEndOfLine) | |
3729 { | |
3730 // VisiblePositions at offsets inside containers either a) refer to the posi
tions before/after | |
3731 // those containers (tables and select elements) or b) refer to the position
inside an empty block. | |
3732 // They never refer to children. | |
3733 // FIXME: Paint the carets inside empty blocks differently than the carets b
efore/after elements. | |
3734 | |
3735 LayoutRect rect(location(), LayoutSize(caretWidth, size().height())); | |
3736 bool ltr = box ? box->isLeftToRightDirection() : style()->isLeftToRightDirec
tion(); | |
3737 | |
3738 if ((!caretOffset) ^ ltr) | |
3739 rect.move(LayoutSize(size().width() - caretWidth, 0)); | |
3740 | |
3741 if (box) { | |
3742 RootInlineBox& rootBox = box->root(); | |
3743 LayoutUnit top = rootBox.lineTop(); | |
3744 rect.setY(top); | |
3745 rect.setHeight(rootBox.lineBottom() - top); | |
3746 } | |
3747 | |
3748 // If height of box is smaller than font height, use the latter one, | |
3749 // otherwise the caret might become invisible. | |
3750 // | |
3751 // Also, if the box is not a replaced element, always use the font height. | |
3752 // This prevents the "big caret" bug described in: | |
3753 // <rdar://problem/3777804> Deleting all content in a document can result in
giant tall-as-window insertion point | |
3754 // | |
3755 // FIXME: ignoring :first-line, missing good reason to take care of | |
3756 LayoutUnit fontHeight = style()->fontMetrics().height(); | |
3757 if (fontHeight > rect.height() || (!isReplaced() && !isTable())) | |
3758 rect.setHeight(fontHeight); | |
3759 | |
3760 if (extraWidthToEndOfLine) | |
3761 *extraWidthToEndOfLine = location().x() + size().width() - rect.maxX(); | |
3762 | |
3763 // Move to local coords | |
3764 rect.moveBy(-location()); | |
3765 | |
3766 // FIXME: Border/padding should be added for all elements but this workaroun
d | |
3767 // is needed because we use offsets inside an "atomic" element to represent | |
3768 // positions before and after the element in deprecated editing offsets. | |
3769 if (node() && !(editingIgnoresContent(node()) || isRenderedTableElement(node
()))) { | |
3770 rect.setX(rect.x() + borderLeft() + paddingLeft()); | |
3771 rect.setY(rect.y() + paddingTop() + borderTop()); | |
3772 } | |
3773 | |
3774 if (!isHorizontalWritingMode()) | |
3775 return rect.transposedRect(); | |
3776 | |
3777 return rect; | |
3778 } | |
3779 | |
3780 PositionWithAffinity RenderBox::positionForPoint(const LayoutPoint& point) | |
3781 { | |
3782 // no children...return this render object's element, if there is one, and o
ffset 0 | |
3783 LayoutObject* firstChild = slowFirstChild(); | |
3784 if (!firstChild) | |
3785 return createPositionWithAffinity(nonPseudoNode() ? firstPositionInOrBef
oreNode(nonPseudoNode()) : Position()); | |
3786 | |
3787 if (isTable() && nonPseudoNode()) { | |
3788 LayoutUnit right = size().width() - verticalScrollbarWidth(); | |
3789 LayoutUnit bottom = size().height() - horizontalScrollbarHeight(); | |
3790 | |
3791 if (point.x() < 0 || point.x() > right || point.y() < 0 || point.y() > b
ottom) { | |
3792 if (point.x() <= right / 2) | |
3793 return createPositionWithAffinity(firstPositionInOrBeforeNode(no
nPseudoNode())); | |
3794 return createPositionWithAffinity(lastPositionInOrAfterNode(nonPseud
oNode())); | |
3795 } | |
3796 } | |
3797 | |
3798 // Pass off to the closest child. | |
3799 LayoutUnit minDist = LayoutUnit::max(); | |
3800 RenderBox* closestRenderer = 0; | |
3801 LayoutPoint adjustedPoint = point; | |
3802 if (isTableRow()) | |
3803 adjustedPoint.moveBy(location()); | |
3804 | |
3805 for (LayoutObject* layoutObject = firstChild; layoutObject; layoutObject = l
ayoutObject->nextSibling()) { | |
3806 if ((!layoutObject->slowFirstChild() && !layoutObject->isInline() && !la
youtObject->isRenderBlockFlow() ) | |
3807 || layoutObject->style()->visibility() != VISIBLE) | |
3808 continue; | |
3809 | |
3810 if (!layoutObject->isBox()) | |
3811 continue; | |
3812 | |
3813 RenderBox* renderer = toRenderBox(layoutObject); | |
3814 | |
3815 LayoutUnit top = renderer->borderTop() + renderer->paddingTop() + (isTab
leRow() ? LayoutUnit() : renderer->location().y()); | |
3816 LayoutUnit bottom = top + renderer->contentHeight(); | |
3817 LayoutUnit left = renderer->borderLeft() + renderer->paddingLeft() + (is
TableRow() ? LayoutUnit() : renderer->location().x()); | |
3818 LayoutUnit right = left + renderer->contentWidth(); | |
3819 | |
3820 if (point.x() <= right && point.x() >= left && point.y() <= top && point
.y() >= bottom) { | |
3821 if (renderer->isTableRow()) | |
3822 return renderer->positionForPoint(point + adjustedPoint - render
er->locationOffset()); | |
3823 return renderer->positionForPoint(point - renderer->locationOffset()
); | |
3824 } | |
3825 | |
3826 // Find the distance from (x, y) to the box. Split the space around the
box into 8 pieces | |
3827 // and use a different compare depending on which piece (x, y) is in. | |
3828 LayoutPoint cmp; | |
3829 if (point.x() > right) { | |
3830 if (point.y() < top) | |
3831 cmp = LayoutPoint(right, top); | |
3832 else if (point.y() > bottom) | |
3833 cmp = LayoutPoint(right, bottom); | |
3834 else | |
3835 cmp = LayoutPoint(right, point.y()); | |
3836 } else if (point.x() < left) { | |
3837 if (point.y() < top) | |
3838 cmp = LayoutPoint(left, top); | |
3839 else if (point.y() > bottom) | |
3840 cmp = LayoutPoint(left, bottom); | |
3841 else | |
3842 cmp = LayoutPoint(left, point.y()); | |
3843 } else { | |
3844 if (point.y() < top) | |
3845 cmp = LayoutPoint(point.x(), top); | |
3846 else | |
3847 cmp = LayoutPoint(point.x(), bottom); | |
3848 } | |
3849 | |
3850 LayoutSize difference = cmp - point; | |
3851 | |
3852 LayoutUnit dist = difference.width() * difference.width() + difference.h
eight() * difference.height(); | |
3853 if (dist < minDist) { | |
3854 closestRenderer = renderer; | |
3855 minDist = dist; | |
3856 } | |
3857 } | |
3858 | |
3859 if (closestRenderer) | |
3860 return closestRenderer->positionForPoint(adjustedPoint - closestRenderer
->locationOffset()); | |
3861 return createPositionWithAffinity(firstPositionInOrBeforeNode(nonPseudoNode(
))); | |
3862 } | |
3863 | |
3864 bool RenderBox::shrinkToAvoidFloats() const | |
3865 { | |
3866 // Floating objects don't shrink. Objects that don't avoid floats don't shr
ink. | |
3867 if (isInline() || !avoidsFloats() || isFloating()) | |
3868 return false; | |
3869 | |
3870 // Only auto width objects can possibly shrink to avoid floats. | |
3871 return style()->width().isAuto(); | |
3872 } | |
3873 | |
3874 static bool isReplacedElement(Node* node) | |
3875 { | |
3876 // Checkboxes and radioboxes are not isReplaced() nor do they have their own
renderer in which to override avoidFloats(). | |
3877 return node && node->isElementNode() && (toElement(node)->isFormControlEleme
nt() || isHTMLImageElement(toElement(node))); | |
3878 } | |
3879 | |
3880 bool RenderBox::avoidsFloats() const | |
3881 { | |
3882 return isReplaced() || isReplacedElement(node()) || hasOverflowClip() || isH
R() || isLegend() || isWritingModeRoot() || isFlexItemIncludingDeprecated(); | |
3883 } | |
3884 | |
3885 bool RenderBox::hasNonCompositedScrollbars() const | |
3886 { | |
3887 if (Layer* layer = this->layer()) { | |
3888 if (LayerScrollableArea* scrollableArea = layer->scrollableArea()) { | |
3889 if (scrollableArea->hasHorizontalScrollbar() && !scrollableArea->lay
erForHorizontalScrollbar()) | |
3890 return true; | |
3891 if (scrollableArea->hasVerticalScrollbar() && !scrollableArea->layer
ForVerticalScrollbar()) | |
3892 return true; | |
3893 } | |
3894 } | |
3895 return false; | |
3896 } | |
3897 | |
3898 PaintInvalidationReason RenderBox::paintInvalidationReason(const LayoutBoxModelO
bject& paintInvalidationContainer, | |
3899 const LayoutRect& oldBounds, const LayoutPoint& oldLocation, const LayoutRec
t& newBounds, const LayoutPoint& newLocation) const | |
3900 { | |
3901 PaintInvalidationReason invalidationReason = LayoutBoxModelObject::paintInva
lidationReason(paintInvalidationContainer, oldBounds, oldLocation, newBounds, ne
wLocation); | |
3902 if (isFullPaintInvalidationReason(invalidationReason)) | |
3903 return invalidationReason; | |
3904 | |
3905 // If the transform is not identity or translation, incremental invalidation
is not applicable | |
3906 // because the difference between oldBounds and newBounds doesn't cover all
area needing invalidation. | |
3907 // FIXME: Should also consider ancestor transforms since paintInvalidationCo
ntainer. crbug.com/426111. | |
3908 if (invalidationReason == PaintInvalidationIncremental | |
3909 && paintInvalidationContainer != this | |
3910 && hasLayer() && layer()->transform() && !layer()->transform()->isIdenti
tyOrTranslation()) | |
3911 return PaintInvalidationBoundsChange; | |
3912 | |
3913 if (!style()->hasBackground() && !style()->hasBoxDecorations()) { | |
3914 // We could let incremental invalidation cover non-composited scrollbars
, but just | |
3915 // do a full invalidation because incremental invalidation will go away
with slimming paint. | |
3916 if (invalidationReason == PaintInvalidationIncremental && hasNonComposit
edScrollbars()) | |
3917 return PaintInvalidationBorderBoxChange; | |
3918 return invalidationReason; | |
3919 } | |
3920 | |
3921 LayoutSize oldBorderBoxSize = computePreviousBorderBoxSize(oldBounds.size())
; | |
3922 LayoutSize newBorderBoxSize = size(); | |
3923 | |
3924 if (oldBorderBoxSize == newBorderBoxSize) | |
3925 return invalidationReason; | |
3926 | |
3927 // See another hasNonCompositedScrollbars() callsite above. | |
3928 if (hasNonCompositedScrollbars()) | |
3929 return PaintInvalidationBorderBoxChange; | |
3930 | |
3931 if (style()->hasVisualOverflowingEffect() || style()->hasAppearance() || sty
le()->hasFilter() || style()->resize() != RESIZE_NONE) | |
3932 return PaintInvalidationBorderBoxChange; | |
3933 | |
3934 if (style()->hasBorderRadius()) { | |
3935 // If a border-radius exists and width/height is smaller than radius wid
th/height, | |
3936 // we need to fully invalidate to cover the changed radius. | |
3937 FloatRoundedRect oldRoundedRect = style()->getRoundedBorderFor(LayoutRec
t(LayoutPoint(0, 0), oldBorderBoxSize)); | |
3938 FloatRoundedRect newRoundedRect = style()->getRoundedBorderFor(LayoutRec
t(LayoutPoint(0, 0), newBorderBoxSize)); | |
3939 if (oldRoundedRect.radii() != newRoundedRect.radii()) | |
3940 return PaintInvalidationBorderBoxChange; | |
3941 } | |
3942 | |
3943 if (oldBorderBoxSize.width() != newBorderBoxSize.width() && mustInvalidateBa
ckgroundOrBorderPaintOnWidthChange()) | |
3944 return PaintInvalidationBorderBoxChange; | |
3945 if (oldBorderBoxSize.height() != newBorderBoxSize.height() && mustInvalidate
BackgroundOrBorderPaintOnHeightChange()) | |
3946 return PaintInvalidationBorderBoxChange; | |
3947 | |
3948 return PaintInvalidationIncremental; | |
3949 } | |
3950 | |
3951 void RenderBox::incrementallyInvalidatePaint(const LayoutBoxModelObject& paintIn
validationContainer, const LayoutRect& oldBounds, const LayoutRect& newBounds, c
onst LayoutPoint& positionFromPaintInvalidationBacking) | |
3952 { | |
3953 LayoutObject::incrementallyInvalidatePaint(paintInvalidationContainer, oldBo
unds, newBounds, positionFromPaintInvalidationBacking); | |
3954 | |
3955 bool hasBoxDecorations = style()->hasBoxDecorations(); | |
3956 if (!style()->hasBackground() && !hasBoxDecorations) | |
3957 return; | |
3958 | |
3959 LayoutSize oldBorderBoxSize = computePreviousBorderBoxSize(oldBounds.size())
; | |
3960 LayoutSize newBorderBoxSize = size(); | |
3961 | |
3962 // If border box size didn't change, RenderObject's incrementallyInvalidateP
aint() is good. | |
3963 if (oldBorderBoxSize == newBorderBoxSize) | |
3964 return; | |
3965 | |
3966 // If size of the paint invalidation rect equals to size of border box, Layo
utObject::incrementallyInvalidatePaint() | |
3967 // is good for boxes having background without box decorations. | |
3968 ASSERT(oldBounds.location() == newBounds.location()); // Otherwise we won't
do incremental invalidation. | |
3969 if (!hasBoxDecorations | |
3970 && positionFromPaintInvalidationBacking == newBounds.location() | |
3971 && oldBorderBoxSize == oldBounds.size() | |
3972 && newBorderBoxSize == newBounds.size()) | |
3973 return; | |
3974 | |
3975 // Invalidate the right delta part and the right border of the old or new bo
x which has smaller width. | |
3976 LayoutUnit deltaWidth = absoluteValue(oldBorderBoxSize.width() - newBorderBo
xSize.width()); | |
3977 if (deltaWidth) { | |
3978 LayoutUnit smallerWidth = std::min(oldBorderBoxSize.width(), newBorderBo
xSize.width()); | |
3979 LayoutUnit borderTopRightRadiusWidth = valueForLength(style()->borderTop
RightRadius().width(), smallerWidth); | |
3980 LayoutUnit borderBottomRightRadiusWidth = valueForLength(style()->border
BottomRightRadius().width(), smallerWidth); | |
3981 LayoutUnit borderWidth = std::max<LayoutUnit>(borderRight(), std::max(bo
rderTopRightRadiusWidth, borderBottomRightRadiusWidth)); | |
3982 LayoutRect rightDeltaRect(positionFromPaintInvalidationBacking.x() + sma
llerWidth - borderWidth, | |
3983 positionFromPaintInvalidationBacking.y(), | |
3984 deltaWidth + borderWidth, | |
3985 std::max(oldBorderBoxSize.height(), newBorderBoxSize.height())); | |
3986 invalidatePaintRectClippedByOldAndNewBounds(paintInvalidationContainer,
rightDeltaRect, oldBounds, newBounds); | |
3987 } | |
3988 | |
3989 // Invalidate the bottom delta part and the bottom border of the old or new
box which has smaller height. | |
3990 LayoutUnit deltaHeight = absoluteValue(oldBorderBoxSize.height() - newBorder
BoxSize.height()); | |
3991 if (deltaHeight) { | |
3992 LayoutUnit smallerHeight = std::min(oldBorderBoxSize.height(), newBorder
BoxSize.height()); | |
3993 LayoutUnit borderBottomLeftRadiusHeight = valueForLength(style()->border
BottomLeftRadius().height(), smallerHeight); | |
3994 LayoutUnit borderBottomRightRadiusHeight = valueForLength(style()->borde
rBottomRightRadius().height(), smallerHeight); | |
3995 LayoutUnit borderHeight = std::max<LayoutUnit>(borderBottom(), std::max(
borderBottomLeftRadiusHeight, borderBottomRightRadiusHeight)); | |
3996 LayoutRect bottomDeltaRect(positionFromPaintInvalidationBacking.x(), | |
3997 positionFromPaintInvalidationBacking.y() + smallerHeight - borderHei
ght, | |
3998 std::max(oldBorderBoxSize.width(), newBorderBoxSize.width()), | |
3999 deltaHeight + borderHeight); | |
4000 invalidatePaintRectClippedByOldAndNewBounds(paintInvalidationContainer,
bottomDeltaRect, oldBounds, newBounds); | |
4001 } | |
4002 } | |
4003 | |
4004 void RenderBox::invalidatePaintRectClippedByOldAndNewBounds(const LayoutBoxModel
Object& paintInvalidationContainer, const LayoutRect& rect, const LayoutRect& ol
dBounds, const LayoutRect& newBounds) | |
4005 { | |
4006 if (rect.isEmpty()) | |
4007 return; | |
4008 LayoutRect rectClippedByOldBounds = intersection(rect, oldBounds); | |
4009 LayoutRect rectClippedByNewBounds = intersection(rect, newBounds); | |
4010 // Invalidate only once if the clipped rects equal. | |
4011 if (rectClippedByOldBounds == rectClippedByNewBounds) { | |
4012 invalidatePaintUsingContainer(&paintInvalidationContainer, rectClippedBy
OldBounds, PaintInvalidationIncremental); | |
4013 return; | |
4014 } | |
4015 // Invalidate the bigger one if one contains another. Otherwise invalidate b
oth. | |
4016 if (!rectClippedByNewBounds.contains(rectClippedByOldBounds)) | |
4017 invalidatePaintUsingContainer(&paintInvalidationContainer, rectClippedBy
OldBounds, PaintInvalidationIncremental); | |
4018 if (!rectClippedByOldBounds.contains(rectClippedByNewBounds)) | |
4019 invalidatePaintUsingContainer(&paintInvalidationContainer, rectClippedBy
NewBounds, PaintInvalidationIncremental); | |
4020 } | |
4021 | |
4022 void RenderBox::markForPaginationRelayoutIfNeeded(SubtreeLayoutScope& layoutScop
e) | |
4023 { | |
4024 ASSERT(!needsLayout()); | |
4025 // If fragmentation height has changed, we need to lay out. No need to enter
the renderer if it | |
4026 // is childless, though. | |
4027 if (view()->layoutState()->pageLogicalHeightChanged() && slowFirstChild()) | |
4028 layoutScope.setChildNeedsLayout(this); | |
4029 } | |
4030 | |
4031 void RenderBox::addVisualEffectOverflow() | |
4032 { | |
4033 if (!style()->hasVisualOverflowingEffect()) | |
4034 return; | |
4035 | |
4036 // Add in the final overflow with shadows, outsets and outline combined. | |
4037 LayoutRect visualEffectOverflow = borderBoxRect(); | |
4038 visualEffectOverflow.expand(computeVisualEffectOverflowOutsets()); | |
4039 addVisualOverflow(visualEffectOverflow); | |
4040 } | |
4041 | |
4042 LayoutRectOutsets RenderBox::computeVisualEffectOverflowOutsets() const | |
4043 { | |
4044 ASSERT(style()->hasVisualOverflowingEffect()); | |
4045 | |
4046 LayoutUnit top; | |
4047 LayoutUnit right; | |
4048 LayoutUnit bottom; | |
4049 LayoutUnit left; | |
4050 | |
4051 if (const ShadowList* boxShadow = style()->boxShadow()) { | |
4052 // FIXME: Use LayoutUnit edge outsets, and then simplify this. | |
4053 FloatRectOutsets outsets = boxShadow->rectOutsetsIncludingOriginal(); | |
4054 top = outsets.top(); | |
4055 right = outsets.right(); | |
4056 bottom = outsets.bottom(); | |
4057 left = outsets.left(); | |
4058 } | |
4059 | |
4060 if (style()->hasBorderImageOutsets()) { | |
4061 LayoutRectOutsets borderOutsets = style()->borderImageOutsets(); | |
4062 top = std::max(top, borderOutsets.top()); | |
4063 right = std::max(right, borderOutsets.right()); | |
4064 bottom = std::max(bottom, borderOutsets.bottom()); | |
4065 left = std::max(left, borderOutsets.left()); | |
4066 } | |
4067 | |
4068 if (style()->hasOutline()) { | |
4069 if (style()->outlineStyleIsAuto()) { | |
4070 // The result focus ring rects are in coordinates of this object's b
order box. | |
4071 Vector<LayoutRect> focusRingRects; | |
4072 addFocusRingRects(focusRingRects, LayoutPoint()); | |
4073 LayoutRect rect = unionRect(focusRingRects); | |
4074 | |
4075 int outlineSize = GraphicsContext::focusRingOutsetExtent(style()->ou
tlineOffset(), style()->outlineWidth()); | |
4076 top = std::max(top, -rect.y() + outlineSize); | |
4077 right = std::max(right, rect.maxX() - size().width() + outlineSize); | |
4078 bottom = std::max(bottom, rect.maxY() - size().height() + outlineSiz
e); | |
4079 left = std::max(left, -rect.x() + outlineSize); | |
4080 } else { | |
4081 LayoutUnit outlineSize = style()->outlineSize(); | |
4082 top = std::max(top, outlineSize); | |
4083 right = std::max(right, outlineSize); | |
4084 bottom = std::max(bottom, outlineSize); | |
4085 left = std::max(left, outlineSize); | |
4086 } | |
4087 } | |
4088 | |
4089 return LayoutRectOutsets(top, right, bottom, left); | |
4090 } | |
4091 | |
4092 void RenderBox::addOverflowFromChild(RenderBox* child, const LayoutSize& delta) | |
4093 { | |
4094 // Never allow flow threads to propagate overflow up to a parent. | |
4095 if (child->isLayoutFlowThread()) | |
4096 return; | |
4097 | |
4098 // Only propagate layout overflow from the child if the child isn't clipping
its overflow. If it is, then | |
4099 // its overflow is internal to it, and we don't care about it. layoutOverfl
owRectForPropagation takes care of this | |
4100 // and just propagates the border box rect instead. | |
4101 LayoutRect childLayoutOverflowRect = child->layoutOverflowRectForPropagation
(styleRef()); | |
4102 childLayoutOverflowRect.move(delta); | |
4103 addLayoutOverflow(childLayoutOverflowRect); | |
4104 | |
4105 // Add in visual overflow from the child. Even if the child clips its overf
low, it may still | |
4106 // have visual overflow of its own set from box shadows or reflections. It
is unnecessary to propagate this | |
4107 // overflow if we are clipping our own overflow. | |
4108 if (child->hasSelfPaintingLayer()) | |
4109 return; | |
4110 LayoutRect childVisualOverflowRect = child->visualOverflowRectForPropagation
(styleRef()); | |
4111 childVisualOverflowRect.move(delta); | |
4112 addContentsVisualOverflow(childVisualOverflowRect); | |
4113 } | |
4114 | |
4115 void RenderBox::addLayoutOverflow(const LayoutRect& rect) | |
4116 { | |
4117 LayoutRect clientBox = noOverflowRect(); | |
4118 if (clientBox.contains(rect) || rect.isEmpty()) | |
4119 return; | |
4120 | |
4121 // For overflow clip objects, we don't want to propagate overflow into unrea
chable areas. | |
4122 LayoutRect overflowRect(rect); | |
4123 if (hasOverflowClip() || isRenderView()) { | |
4124 // Overflow is in the block's coordinate space and thus is flipped for h
orizontal-bt and vertical-rl | |
4125 // writing modes. At this stage that is actually a simplification, sinc
e we can treat horizontal-tb/bt as the same | |
4126 // and vertical-lr/rl as the same. | |
4127 bool hasTopOverflow = !style()->isLeftToRightDirection() && !isHorizonta
lWritingMode(); | |
4128 bool hasLeftOverflow = !style()->isLeftToRightDirection() && isHorizonta
lWritingMode(); | |
4129 if (isFlexibleBox() && style()->isReverseFlexDirection()) { | |
4130 RenderFlexibleBox* flexibleBox = toRenderFlexibleBox(this); | |
4131 if (flexibleBox->isHorizontalFlow()) | |
4132 hasLeftOverflow = true; | |
4133 else | |
4134 hasTopOverflow = true; | |
4135 } | |
4136 | |
4137 if (!hasTopOverflow) | |
4138 overflowRect.shiftYEdgeTo(std::max(overflowRect.y(), clientBox.y()))
; | |
4139 else | |
4140 overflowRect.shiftMaxYEdgeTo(std::min(overflowRect.maxY(), clientBox
.maxY())); | |
4141 if (!hasLeftOverflow) | |
4142 overflowRect.shiftXEdgeTo(std::max(overflowRect.x(), clientBox.x()))
; | |
4143 else | |
4144 overflowRect.shiftMaxXEdgeTo(std::min(overflowRect.maxX(), clientBox
.maxX())); | |
4145 | |
4146 // Now re-test with the adjusted rectangle and see if it has become unre
achable or fully | |
4147 // contained. | |
4148 if (clientBox.contains(overflowRect) || overflowRect.isEmpty()) | |
4149 return; | |
4150 } | |
4151 | |
4152 if (!m_overflow) | |
4153 m_overflow = adoptPtr(new RenderOverflow(clientBox, borderBoxRect())); | |
4154 | |
4155 m_overflow->addLayoutOverflow(overflowRect); | |
4156 } | |
4157 | |
4158 void RenderBox::addVisualOverflow(const LayoutRect& rect) | |
4159 { | |
4160 LayoutRect borderBox = borderBoxRect(); | |
4161 if (borderBox.contains(rect) || rect.isEmpty()) | |
4162 return; | |
4163 | |
4164 if (!m_overflow) | |
4165 m_overflow = adoptPtr(new RenderOverflow(noOverflowRect(), borderBox)); | |
4166 | |
4167 m_overflow->addVisualOverflow(rect); | |
4168 } | |
4169 | |
4170 void RenderBox::addContentsVisualOverflow(const LayoutRect& rect) | |
4171 { | |
4172 if (!hasOverflowClip()) { | |
4173 addVisualOverflow(rect); | |
4174 return; | |
4175 } | |
4176 | |
4177 if (!m_overflow) | |
4178 m_overflow = adoptPtr(new RenderOverflow(noOverflowRect(), borderBoxRect
())); | |
4179 m_overflow->addContentsVisualOverflow(rect); | |
4180 } | |
4181 | |
4182 void RenderBox::clearLayoutOverflow() | |
4183 { | |
4184 if (!m_overflow) | |
4185 return; | |
4186 | |
4187 if (!hasVisualOverflow() && contentsVisualOverflowRect().isEmpty()) { | |
4188 clearAllOverflows(); | |
4189 return; | |
4190 } | |
4191 | |
4192 m_overflow->setLayoutOverflow(noOverflowRect()); | |
4193 } | |
4194 | |
4195 bool RenderBox::logicalWidthIsResolvableFromBlock(const RenderBlock* containingB
lock) | |
4196 { | |
4197 const RenderBlock* cb = containingBlock; | |
4198 while (!cb->isRenderView() && !cb->isOutOfFlowPositioned() && (cb->style()->
logicalWidth().isAuto() || cb->isAnonymousBlock())) | |
4199 cb = cb->containingBlock(); | |
4200 | |
4201 if (cb->style()->logicalWidth().isFixed()) | |
4202 return true; | |
4203 if (cb->isRenderView()) | |
4204 return true; | |
4205 if (cb->isOutOfFlowPositioned()) | |
4206 return true; | |
4207 if (cb->style()->logicalWidth().isPercent()) | |
4208 return logicalWidthIsResolvableFromBlock(cb->containingBlock()); | |
4209 | |
4210 return false; | |
4211 } | |
4212 | |
4213 bool RenderBox::hasDefiniteLogicalWidth() const | |
4214 { | |
4215 const Length& logicalWidth = style()->logicalWidth(); | |
4216 if (logicalWidth.isIntrinsic() || logicalWidth.isLegacyIntrinsic()) | |
4217 return false; | |
4218 if (logicalWidth.isFixed()) | |
4219 return true; | |
4220 // The size of the containing block of an absolutely positioned element is a
lways definite with respect to that | |
4221 // element (http://dev.w3.org/csswg/css-sizing-3/#definite). | |
4222 if (isOutOfFlowPositioned()) | |
4223 return true; | |
4224 | |
4225 return RenderBox::logicalWidthIsResolvableFromBlock(containingBlock()); | |
4226 } | |
4227 | |
4228 inline static bool percentageLogicalHeightIsResolvable(const RenderBox* box) | |
4229 { | |
4230 return RenderBox::percentageLogicalHeightIsResolvableFromBlock(box->containi
ngBlock(), box->isOutOfFlowPositioned()); | |
4231 } | |
4232 | |
4233 bool RenderBox::percentageLogicalHeightIsResolvableFromBlock(const RenderBlock*
containingBlock, bool isOutOfFlowPositioned) | |
4234 { | |
4235 // In quirks mode, blocks with auto height are skipped, and we keep looking
for an enclosing | |
4236 // block that may have a specified height and then use it. In strict mode, t
his violates the | |
4237 // specification, which states that percentage heights just revert to auto i
f the containing | |
4238 // block has an auto height. We still skip anonymous containing blocks in bo
th modes, though, and look | |
4239 // only at explicit containers. | |
4240 const RenderBlock* cb = containingBlock; | |
4241 bool inQuirksMode = cb->document().inQuirksMode(); | |
4242 while (!cb->isRenderView() && !cb->isBody() && !cb->isTableCell() && !cb->is
OutOfFlowPositioned() && cb->style()->logicalHeight().isAuto()) { | |
4243 if (!inQuirksMode && !cb->isAnonymousBlock()) | |
4244 break; | |
4245 cb = cb->containingBlock(); | |
4246 } | |
4247 | |
4248 // A positioned element that specified both top/bottom or that specifies hei
ght should be treated as though it has a height | |
4249 // explicitly specified that can be used for any percentage computations. | |
4250 // FIXME: We can't just check top/bottom here. | |
4251 // https://bugs.webkit.org/show_bug.cgi?id=46500 | |
4252 bool isOutOfFlowPositionedWithSpecifiedHeight = cb->isOutOfFlowPositioned()
&& (!cb->style()->logicalHeight().isAuto() || (!cb->style()->top().isAuto() && !
cb->style()->bottom().isAuto())); | |
4253 | |
4254 // Table cells violate what the CSS spec says to do with heights. Basically
we | |
4255 // don't care if the cell specified a height or not. We just always make ou
rselves | |
4256 // be a percentage of the cell's current content height. | |
4257 if (cb->isTableCell()) | |
4258 return true; | |
4259 | |
4260 // Otherwise we only use our percentage height if our containing block had a
specified | |
4261 // height. | |
4262 if (cb->style()->logicalHeight().isFixed()) | |
4263 return true; | |
4264 if (cb->style()->logicalHeight().isPercent() && !isOutOfFlowPositionedWithSp
ecifiedHeight) | |
4265 return percentageLogicalHeightIsResolvableFromBlock(cb->containingBlock(
), cb->isOutOfFlowPositioned()); | |
4266 if (cb->isRenderView() || inQuirksMode || isOutOfFlowPositionedWithSpecified
Height) | |
4267 return true; | |
4268 if (cb->isDocumentElement() && isOutOfFlowPositioned) { | |
4269 // Match the positioned objects behavior, which is that positioned objec
ts will fill their viewport | |
4270 // always. Note we could only hit this case by recurring into computePe
rcentageLogicalHeight on a positioned containing block. | |
4271 return true; | |
4272 } | |
4273 | |
4274 return false; | |
4275 } | |
4276 | |
4277 bool RenderBox::hasDefiniteLogicalHeight() const | |
4278 { | |
4279 const Length& logicalHeight = style()->logicalHeight(); | |
4280 if (logicalHeight.isIntrinsicOrAuto()) | |
4281 return false; | |
4282 if (logicalHeight.isFixed()) | |
4283 return true; | |
4284 // The size of the containing block of an absolutely positioned element is a
lways definite with respect to that | |
4285 // element (http://dev.w3.org/csswg/css-sizing-3/#definite). | |
4286 if (isOutOfFlowPositioned()) | |
4287 return true; | |
4288 | |
4289 return percentageLogicalHeightIsResolvable(this); | |
4290 } | |
4291 | |
4292 bool RenderBox::hasUnsplittableScrollingOverflow() const | |
4293 { | |
4294 // We will paginate as long as we don't scroll overflow in the pagination di
rection. | |
4295 bool isHorizontal = isHorizontalWritingMode(); | |
4296 if ((isHorizontal && !scrollsOverflowY()) || (!isHorizontal && !scrollsOverf
lowX())) | |
4297 return false; | |
4298 | |
4299 // We do have overflow. We'll still be willing to paginate as long as the bl
ock | |
4300 // has auto logical height, auto or undefined max-logical-height and a zero
or auto min-logical-height. | |
4301 // Note this is just a heuristic, and it's still possible to have overflow u
nder these | |
4302 // conditions, but it should work out to be good enough for common cases. Pa
ginating overflow | |
4303 // with scrollbars present is not the end of the world and is what we used t
o do in the old model anyway. | |
4304 return !style()->logicalHeight().isIntrinsicOrAuto() | |
4305 || (!style()->logicalMaxHeight().isIntrinsicOrAuto() && !style()->logica
lMaxHeight().isMaxSizeNone() && (!style()->logicalMaxHeight().isPercent() || per
centageLogicalHeightIsResolvable(this))) | |
4306 || (!style()->logicalMinHeight().isIntrinsicOrAuto() && style()->logical
MinHeight().isPositive() && (!style()->logicalMinHeight().isPercent() || percent
ageLogicalHeightIsResolvable(this))); | |
4307 } | |
4308 | |
4309 bool RenderBox::isUnsplittableForPagination() const | |
4310 { | |
4311 return isReplaced() || hasUnsplittableScrollingOverflow() || (parent() && is
WritingModeRoot()); | |
4312 } | |
4313 | |
4314 LayoutUnit RenderBox::lineHeight(bool /*firstLine*/, LineDirectionMode direction
, LinePositionMode /*linePositionMode*/) const | |
4315 { | |
4316 if (isReplaced()) | |
4317 return direction == HorizontalLine ? marginHeight() + size().height() :
marginWidth() + size().width(); | |
4318 return LayoutUnit(); | |
4319 } | |
4320 | |
4321 int RenderBox::baselinePosition(FontBaseline baselineType, bool /*firstLine*/, L
ineDirectionMode direction, LinePositionMode linePositionMode) const | |
4322 { | |
4323 ASSERT(linePositionMode == PositionOnContainingLine); | |
4324 if (isReplaced()) { | |
4325 int result = direction == HorizontalLine ? marginHeight() + size().heigh
t() : marginWidth() + size().width(); | |
4326 if (baselineType == AlphabeticBaseline) | |
4327 return result; | |
4328 return result - result / 2; | |
4329 } | |
4330 return 0; | |
4331 } | |
4332 | |
4333 | |
4334 Layer* RenderBox::enclosingFloatPaintingLayer() const | |
4335 { | |
4336 const LayoutObject* curr = this; | |
4337 while (curr) { | |
4338 Layer* layer = curr->hasLayer() && curr->isBox() ? toRenderBox(curr)->la
yer() : 0; | |
4339 if (layer && layer->isSelfPaintingLayer()) | |
4340 return layer; | |
4341 curr = curr->parent(); | |
4342 } | |
4343 return 0; | |
4344 } | |
4345 | |
4346 LayoutRect RenderBox::logicalVisualOverflowRectForPropagation(const LayoutStyle&
parentStyle) const | |
4347 { | |
4348 LayoutRect rect = visualOverflowRectForPropagation(parentStyle); | |
4349 if (!parentStyle.isHorizontalWritingMode()) | |
4350 return rect.transposedRect(); | |
4351 return rect; | |
4352 } | |
4353 | |
4354 LayoutRect RenderBox::visualOverflowRectForPropagation(const LayoutStyle& parent
Style) const | |
4355 { | |
4356 // If the writing modes of the child and parent match, then we don't have to | |
4357 // do anything fancy. Just return the result. | |
4358 LayoutRect rect = visualOverflowRect(); | |
4359 if (parentStyle.writingMode() == style()->writingMode()) | |
4360 return rect; | |
4361 | |
4362 // We are putting ourselves into our parent's coordinate space. If there is
a flipped block mismatch | |
4363 // in a particular axis, then we have to flip the rect along that axis. | |
4364 if (style()->writingMode() == RightToLeftWritingMode || parentStyle.writingM
ode() == RightToLeftWritingMode) | |
4365 rect.setX(size().width() - rect.maxX()); | |
4366 else if (style()->writingMode() == BottomToTopWritingMode || parentStyle.wri
tingMode() == BottomToTopWritingMode) | |
4367 rect.setY(size().height() - rect.maxY()); | |
4368 | |
4369 return rect; | |
4370 } | |
4371 | |
4372 LayoutRect RenderBox::logicalLayoutOverflowRectForPropagation(const LayoutStyle&
parentStyle) const | |
4373 { | |
4374 LayoutRect rect = layoutOverflowRectForPropagation(parentStyle); | |
4375 if (!parentStyle.isHorizontalWritingMode()) | |
4376 return rect.transposedRect(); | |
4377 return rect; | |
4378 } | |
4379 | |
4380 LayoutRect RenderBox::layoutOverflowRectForPropagation(const LayoutStyle& parent
Style) const | |
4381 { | |
4382 // Only propagate interior layout overflow if we don't clip it. | |
4383 LayoutRect rect = borderBoxRect(); | |
4384 // We want to include the margin, but only when it adds height. Quirky margi
ns don't contribute height | |
4385 // nor do the margins of self-collapsing blocks. | |
4386 if (!styleRef().hasMarginAfterQuirk() && !isSelfCollapsingBlock()) | |
4387 rect.expand(isHorizontalWritingMode() ? LayoutSize(LayoutUnit(), marginA
fter()) : LayoutSize(marginAfter(), LayoutUnit())); | |
4388 | |
4389 if (!hasOverflowClip()) | |
4390 rect.unite(layoutOverflowRect()); | |
4391 | |
4392 bool hasTransform = hasLayer() && layer()->transform(); | |
4393 if (isRelPositioned() || hasTransform) { | |
4394 // If we are relatively positioned or if we have a transform, then we ha
ve to convert | |
4395 // this rectangle into physical coordinates, apply relative positioning
and transforms | |
4396 // to it, and then convert it back. | |
4397 flipForWritingMode(rect); | |
4398 | |
4399 if (hasTransform) | |
4400 rect = layer()->currentTransform().mapRect(rect); | |
4401 | |
4402 if (isRelPositioned()) | |
4403 rect.move(offsetForInFlowPosition()); | |
4404 | |
4405 // Now we need to flip back. | |
4406 flipForWritingMode(rect); | |
4407 } | |
4408 | |
4409 // If the writing modes of the child and parent match, then we don't have to | |
4410 // do anything fancy. Just return the result. | |
4411 if (parentStyle.writingMode() == style()->writingMode()) | |
4412 return rect; | |
4413 | |
4414 // We are putting ourselves into our parent's coordinate space. If there is
a flipped block mismatch | |
4415 // in a particular axis, then we have to flip the rect along that axis. | |
4416 if (style()->writingMode() == RightToLeftWritingMode || parentStyle.writingM
ode() == RightToLeftWritingMode) | |
4417 rect.setX(size().width() - rect.maxX()); | |
4418 else if (style()->writingMode() == BottomToTopWritingMode || parentStyle.wri
tingMode() == BottomToTopWritingMode) | |
4419 rect.setY(size().height() - rect.maxY()); | |
4420 | |
4421 return rect; | |
4422 } | |
4423 | |
4424 LayoutRect RenderBox::noOverflowRect() const | |
4425 { | |
4426 // Because of the special coordinate system used for overflow rectangles and
many other | |
4427 // rectangles (not quite logical, not quite physical), we need to flip the b
lock progression | |
4428 // coordinate in vertical-rl and horizontal-bt writing modes. In other words
, the rectangle | |
4429 // returned is physical, except for the block direction progression coordina
te (y in horizontal | |
4430 // writing modes, x in vertical writing modes), which is always "logical top
". Apart from the | |
4431 // flipping, this method does the same as clientBoxRect(). | |
4432 | |
4433 const int scrollBarWidth = verticalScrollbarWidth(); | |
4434 const int scrollBarHeight = horizontalScrollbarHeight(); | |
4435 LayoutUnit left = borderLeft() + (style()->shouldPlaceBlockDirectionScrollba
rOnLogicalLeft() ? scrollBarWidth : 0); | |
4436 LayoutUnit top = borderTop(); | |
4437 LayoutUnit right = borderRight(); | |
4438 LayoutUnit bottom = borderBottom(); | |
4439 LayoutRect rect(left, top, size().width() - left - right, size().height() -
top - bottom); | |
4440 flipForWritingMode(rect); | |
4441 // Subtract space occupied by scrollbars. Order is important here: first fli
p, then subtract | |
4442 // scrollbars. This may seem backwards and weird, since one would think that
a horizontal | |
4443 // scrollbar at the physical bottom in horizontal-bt ought to be at the logi
cal top (physical | |
4444 // bottom), between the logical top (physical bottom) border and the logical
top (physical | |
4445 // bottom) padding. But this is how the rest of the code expects us to behav
e. This is highly | |
4446 // related to https://bugs.webkit.org/show_bug.cgi?id=76129 | |
4447 // FIXME: when the above mentioned bug is fixed, it should hopefully be poss
ible to call | |
4448 // clientBoxRect() or paddingBoxRect() in this method, rather than fiddling
with the edges on | |
4449 // our own. | |
4450 if (style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) | |
4451 rect.contract(0, scrollBarHeight); | |
4452 else | |
4453 rect.contract(scrollBarWidth, scrollBarHeight); | |
4454 return rect; | |
4455 } | |
4456 | |
4457 LayoutUnit RenderBox::offsetLeft() const | |
4458 { | |
4459 return adjustedPositionRelativeToOffsetParent(topLeftLocation()).x(); | |
4460 } | |
4461 | |
4462 LayoutUnit RenderBox::offsetTop() const | |
4463 { | |
4464 return adjustedPositionRelativeToOffsetParent(topLeftLocation()).y(); | |
4465 } | |
4466 | |
4467 LayoutPoint RenderBox::flipForWritingModeForChild(const RenderBox* child, const
LayoutPoint& point) const | |
4468 { | |
4469 if (!style()->isFlippedBlocksWritingMode()) | |
4470 return point; | |
4471 | |
4472 // The child is going to add in its x() and y(), so we have to make sure it
ends up in | |
4473 // the right place. | |
4474 if (isHorizontalWritingMode()) | |
4475 return LayoutPoint(point.x(), point.y() + size().height() - child->size(
).height() - (2 * child->location().y())); | |
4476 return LayoutPoint(point.x() + size().width() - child->size().width() - (2 *
child->location().x()), point.y()); | |
4477 } | |
4478 | |
4479 LayoutPoint RenderBox::flipForWritingModeIncludingColumns(const LayoutPoint& poi
nt) const | |
4480 { | |
4481 if (!hasColumns() || !style()->isFlippedBlocksWritingMode()) | |
4482 return flipForWritingMode(point); | |
4483 return toRenderBlock(this)->flipForWritingModeIncludingColumns(point); | |
4484 } | |
4485 | |
4486 LayoutPoint RenderBox::topLeftLocation() const | |
4487 { | |
4488 RenderBlock* containerBlock = containingBlock(); | |
4489 if (!containerBlock || containerBlock == this) | |
4490 return location(); | |
4491 return containerBlock->flipForWritingModeForChild(this, location()); | |
4492 } | |
4493 | |
4494 bool RenderBox::hasRelativeLogicalHeight() const | |
4495 { | |
4496 return style()->logicalHeight().isPercent() | |
4497 || style()->logicalMinHeight().isPercent() | |
4498 || style()->logicalMaxHeight().isPercent(); | |
4499 } | |
4500 | |
4501 static void markBoxForRelayoutAfterSplit(RenderBox* box) | |
4502 { | |
4503 // FIXME: The table code should handle that automatically. If not, | |
4504 // we should fix it and remove the table part checks. | |
4505 if (box->isTable()) { | |
4506 // Because we may have added some sections with already computed column
structures, we need to | |
4507 // sync the table structure with them now. This avoids crashes when addi
ng new cells to the table. | |
4508 toLayoutTable(box)->forceSectionsRecalc(); | |
4509 } else if (box->isTableSection()) { | |
4510 toLayoutTableSection(box)->setNeedsCellRecalc(); | |
4511 } | |
4512 | |
4513 box->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(); | |
4514 } | |
4515 | |
4516 LayoutObject* RenderBox::splitAnonymousBoxesAroundChild(LayoutObject* beforeChil
d) | |
4517 { | |
4518 bool didSplitParentAnonymousBoxes = false; | |
4519 | |
4520 while (beforeChild->parent() != this) { | |
4521 RenderBox* boxToSplit = toRenderBox(beforeChild->parent()); | |
4522 if (boxToSplit->slowFirstChild() != beforeChild && boxToSplit->isAnonymo
us()) { | |
4523 didSplitParentAnonymousBoxes = true; | |
4524 | |
4525 // We have to split the parent box into two boxes and move children | |
4526 // from |beforeChild| to end into the new post box. | |
4527 RenderBox* postBox = boxToSplit->createAnonymousBoxWithSameTypeAs(th
is); | |
4528 postBox->setChildrenInline(boxToSplit->childrenInline()); | |
4529 RenderBox* parentBox = toRenderBox(boxToSplit->parent()); | |
4530 // We need to invalidate the |parentBox| before inserting the new no
de | |
4531 // so that the table paint invalidation logic knows the structure is
dirty. | |
4532 // See for example LayoutTableCell:clippedOverflowRectForPaintInvali
dation. | |
4533 markBoxForRelayoutAfterSplit(parentBox); | |
4534 parentBox->virtualChildren()->insertChildNode(parentBox, postBox, bo
xToSplit->nextSibling()); | |
4535 boxToSplit->moveChildrenTo(postBox, beforeChild, 0, true); | |
4536 | |
4537 markBoxForRelayoutAfterSplit(boxToSplit); | |
4538 markBoxForRelayoutAfterSplit(postBox); | |
4539 | |
4540 beforeChild = postBox; | |
4541 } else | |
4542 beforeChild = boxToSplit; | |
4543 } | |
4544 | |
4545 if (didSplitParentAnonymousBoxes) | |
4546 markBoxForRelayoutAfterSplit(this); | |
4547 | |
4548 ASSERT(beforeChild->parent() == this); | |
4549 return beforeChild; | |
4550 } | |
4551 | |
4552 LayoutUnit RenderBox::offsetFromLogicalTopOfFirstPage() const | |
4553 { | |
4554 LayoutState* layoutState = view()->layoutState(); | |
4555 if (layoutState && !layoutState->isPaginated()) | |
4556 return LayoutUnit(); | |
4557 | |
4558 if (!layoutState && !flowThreadContainingBlock()) | |
4559 return LayoutUnit(); | |
4560 | |
4561 RenderBlock* containerBlock = containingBlock(); | |
4562 return containerBlock->offsetFromLogicalTopOfFirstPage() + logicalTop(); | |
4563 } | |
4564 | |
4565 void RenderBox::savePreviousBorderBoxSizeIfNeeded() | |
4566 { | |
4567 // If m_rareData is already created, always save. | |
4568 if (!m_rareData) { | |
4569 LayoutSize paintInvalidationSize = previousPaintInvalidationRect().size(
); | |
4570 | |
4571 // Don't save old border box size if the paint rect is empty because we'
ll | |
4572 // full invalidate once the paint rect becomes non-empty. | |
4573 if (paintInvalidationSize.isEmpty()) | |
4574 return; | |
4575 | |
4576 // Don't save old border box size if we can use size of the old paint re
ct | |
4577 // as the old border box size in the next invalidation. | |
4578 if (paintInvalidationSize == size()) | |
4579 return; | |
4580 | |
4581 // We need the old border box size only when the box has background or b
ox decorations. | |
4582 if (!style()->hasBackground() && !style()->hasBoxDecorations()) | |
4583 return; | |
4584 } | |
4585 | |
4586 ensureRareData().m_previousBorderBoxSize = size(); | |
4587 } | |
4588 | |
4589 LayoutSize RenderBox::computePreviousBorderBoxSize(const LayoutSize& previousBou
ndsSize) const | |
4590 { | |
4591 // PreviousBorderBoxSize is only valid when there is background or box decor
ations. | |
4592 ASSERT(style()->hasBackground() || style()->hasBoxDecorations()); | |
4593 | |
4594 if (m_rareData && m_rareData->m_previousBorderBoxSize.width() != -1) | |
4595 return m_rareData->m_previousBorderBoxSize; | |
4596 | |
4597 // We didn't save the old border box size because it was the same as the siz
e of oldBounds. | |
4598 return previousBoundsSize; | |
4599 } | |
4600 | |
4601 void RenderBox::logicalExtentAfterUpdatingLogicalWidth(const LayoutUnit& newLogi
calTop, RenderBox::LogicalExtentComputedValues& computedValues) | |
4602 { | |
4603 // FIXME: None of this is right for perpendicular writing-mode children. | |
4604 LayoutUnit oldLogicalWidth = logicalWidth(); | |
4605 LayoutUnit oldLogicalLeft = logicalLeft(); | |
4606 LayoutUnit oldMarginLeft = marginLeft(); | |
4607 LayoutUnit oldMarginRight = marginRight(); | |
4608 LayoutUnit oldLogicalTop = logicalTop(); | |
4609 | |
4610 setLogicalTop(newLogicalTop); | |
4611 updateLogicalWidth(); | |
4612 | |
4613 computedValues.m_extent = logicalWidth(); | |
4614 computedValues.m_position = logicalLeft(); | |
4615 computedValues.m_margins.m_start = marginStart(); | |
4616 computedValues.m_margins.m_end = marginEnd(); | |
4617 | |
4618 setLogicalTop(oldLogicalTop); | |
4619 setLogicalWidth(oldLogicalWidth); | |
4620 setLogicalLeft(oldLogicalLeft); | |
4621 setMarginLeft(oldMarginLeft); | |
4622 setMarginRight(oldMarginRight); | |
4623 } | |
4624 | |
4625 void RenderBox::invalidateDisplayItemClients(DisplayItemList* displayItemList) c
onst | |
4626 { | |
4627 LayoutBoxModelObject::invalidateDisplayItemClients(displayItemList); | |
4628 if (LayerScrollableArea* area = scrollableArea()) | |
4629 displayItemList->invalidate(area->displayItemClient()); | |
4630 } | |
4631 | |
4632 } // namespace blink | |
OLD | NEW |