| 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 |