| 1 | /* |
| 2 | * Copyright (C) 1999 Lars Knoll (knoll@kde.org) |
| 3 | * (C) 1999 Antti Koivisto (koivisto@kde.org) |
| 4 | * (C) 2007 David Smith (catfish.man@gmail.com) |
| 5 | * Copyright (C) 2003-2013, Apple Inc. All rights reserved. |
| 6 | * |
| 7 | * This library is free software; you can redistribute it and/or |
| 8 | * modify it under the terms of the GNU Library General Public |
| 9 | * License as published by the Free Software Foundation; either |
| 10 | * version 2 of the License, or (at your option) any later version. |
| 11 | * |
| 12 | * This library is distributed in the hope that it will be useful, |
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 15 | * Library General Public License for more details. |
| 16 | * |
| 17 | * You should have received a copy of the GNU Library General Public License |
| 18 | * along with this library; see the file COPYING.LIB. If not, write to |
| 19 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
| 20 | * Boston, MA 02110-1301, USA. |
| 21 | */ |
| 22 | |
| 23 | #pragma once |
| 24 | |
| 25 | #include "FloatingObjects.h" |
| 26 | #include "LineWidth.h" |
| 27 | #include "RenderBlock.h" |
| 28 | #include "RenderLineBoxList.h" |
| 29 | #include "SimpleLineLayout.h" |
| 30 | #include "TrailingObjects.h" |
| 31 | #include <memory> |
| 32 | |
| 33 | namespace WebCore { |
| 34 | |
| 35 | class FloatWithRect; |
| 36 | class LineBreaker; |
| 37 | class LineInfo; |
| 38 | class RenderMultiColumnFlow; |
| 39 | class RenderRubyRun; |
| 40 | |
| 41 | struct WordMeasurement; |
| 42 | |
| 43 | template <class Run> class BidiRunList; |
| 44 | typedef Vector<WordMeasurement, 64> WordMeasurements; |
| 45 | |
| 46 | #if ENABLE(TEXT_AUTOSIZING) |
| 47 | enum LineCount { |
| 48 | NOT_SET = 0, NO_LINE = 1, ONE_LINE = 2, MULTI_LINE = 3 |
| 49 | }; |
| 50 | #endif |
| 51 | |
| 52 | class RenderBlockFlow : public RenderBlock { |
| 53 | WTF_MAKE_ISO_ALLOCATED(RenderBlockFlow); |
| 54 | public: |
| 55 | RenderBlockFlow(Element&, RenderStyle&&); |
| 56 | RenderBlockFlow(Document&, RenderStyle&&); |
| 57 | virtual ~RenderBlockFlow(); |
| 58 | |
| 59 | void layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeight = 0_lu) override; |
| 60 | |
| 61 | protected: |
| 62 | void willBeDestroyed() override; |
| 63 | |
| 64 | // This method is called at the start of layout to wipe away all of the floats in our floating objects list. It also |
| 65 | // repopulates the list with any floats that intrude from previous siblings or parents. Floats that were added by |
| 66 | // descendants are gone when this call completes and will get added back later on after the children have gotten |
| 67 | // a relayout. |
| 68 | void rebuildFloatingObjectSetFromIntrudingFloats(); |
| 69 | |
| 70 | // RenderBlockFlow always contains either lines or paragraphs. When the children are all blocks (e.g. paragraphs), we call layoutBlockChildren. |
| 71 | // When the children are all inline (e.g., lines), we call layoutInlineChildren. |
| 72 | void layoutBlockChildren(bool relayoutChildren, LayoutUnit& maxFloatLogicalBottom); |
| 73 | void layoutInlineChildren(bool relayoutChildren, LayoutUnit& repaintLogicalTop, LayoutUnit& repaintLogicalBottom); |
| 74 | |
| 75 | // RenderBlockFlows override these methods, since they are the only class that supports margin collapsing. |
| 76 | LayoutUnit collapsedMarginBefore() const final { return maxPositiveMarginBefore() - maxNegativeMarginBefore(); } |
| 77 | LayoutUnit collapsedMarginAfter() const final { return maxPositiveMarginAfter() - maxNegativeMarginAfter(); } |
| 78 | |
| 79 | void dirtyLinesFromChangedChild(RenderObject& child) final { lineBoxes().dirtyLinesFromChangedChild(*this, child); } |
| 80 | |
| 81 | void paintColumnRules(PaintInfo&, const LayoutPoint&) override; |
| 82 | |
| 83 | public: |
| 84 | class MarginValues { |
| 85 | public: |
| 86 | MarginValues(LayoutUnit beforePos, LayoutUnit beforeNeg, LayoutUnit afterPos, LayoutUnit afterNeg) |
| 87 | : m_positiveMarginBefore(beforePos) |
| 88 | , m_negativeMarginBefore(beforeNeg) |
| 89 | , m_positiveMarginAfter(afterPos) |
| 90 | , m_negativeMarginAfter(afterNeg) |
| 91 | { |
| 92 | } |
| 93 | |
| 94 | LayoutUnit positiveMarginBefore() const { return m_positiveMarginBefore; } |
| 95 | LayoutUnit negativeMarginBefore() const { return m_negativeMarginBefore; } |
| 96 | LayoutUnit positiveMarginAfter() const { return m_positiveMarginAfter; } |
| 97 | LayoutUnit negativeMarginAfter() const { return m_negativeMarginAfter; } |
| 98 | |
| 99 | void setPositiveMarginBefore(LayoutUnit pos) { m_positiveMarginBefore = pos; } |
| 100 | void setNegativeMarginBefore(LayoutUnit neg) { m_negativeMarginBefore = neg; } |
| 101 | void setPositiveMarginAfter(LayoutUnit pos) { m_positiveMarginAfter = pos; } |
| 102 | void setNegativeMarginAfter(LayoutUnit neg) { m_negativeMarginAfter = neg; } |
| 103 | |
| 104 | private: |
| 105 | LayoutUnit m_positiveMarginBefore; |
| 106 | LayoutUnit m_negativeMarginBefore; |
| 107 | LayoutUnit m_positiveMarginAfter; |
| 108 | LayoutUnit m_negativeMarginAfter; |
| 109 | }; |
| 110 | MarginValues marginValuesForChild(RenderBox& child) const; |
| 111 | |
| 112 | // Allocated only when some of these fields have non-default values |
| 113 | struct RenderBlockFlowRareData { |
| 114 | WTF_MAKE_NONCOPYABLE(RenderBlockFlowRareData); WTF_MAKE_FAST_ALLOCATED; |
| 115 | public: |
| 116 | RenderBlockFlowRareData(const RenderBlockFlow& block) |
| 117 | : m_margins(positiveMarginBeforeDefault(block), negativeMarginBeforeDefault(block), positiveMarginAfterDefault(block), negativeMarginAfterDefault(block)) |
| 118 | , m_lineBreakToAvoidWidow(-1) |
| 119 | , m_discardMarginBefore(false) |
| 120 | , m_discardMarginAfter(false) |
| 121 | , m_didBreakAtLineToAvoidWidow(false) |
| 122 | { |
| 123 | } |
| 124 | |
| 125 | static LayoutUnit positiveMarginBeforeDefault(const RenderBlock& block) |
| 126 | { |
| 127 | return std::max<LayoutUnit>(block.marginBefore(), 0); |
| 128 | } |
| 129 | static LayoutUnit negativeMarginBeforeDefault(const RenderBlock& block) |
| 130 | { |
| 131 | return std::max<LayoutUnit>(-block.marginBefore(), 0); |
| 132 | } |
| 133 | static LayoutUnit positiveMarginAfterDefault(const RenderBlock& block) |
| 134 | { |
| 135 | return std::max<LayoutUnit>(block.marginAfter(), 0); |
| 136 | } |
| 137 | static LayoutUnit negativeMarginAfterDefault(const RenderBlock& block) |
| 138 | { |
| 139 | return std::max<LayoutUnit>(-block.marginAfter(), 0); |
| 140 | } |
| 141 | |
| 142 | MarginValues m_margins; |
| 143 | int m_lineBreakToAvoidWidow; |
| 144 | std::unique_ptr<RootInlineBox> m_lineGridBox; |
| 145 | |
| 146 | WeakPtr<RenderMultiColumnFlow> m_multiColumnFlow; |
| 147 | |
| 148 | bool m_discardMarginBefore : 1; |
| 149 | bool m_discardMarginAfter : 1; |
| 150 | bool m_didBreakAtLineToAvoidWidow : 1; |
| 151 | }; |
| 152 | |
| 153 | class MarginInfo { |
| 154 | // Collapsing flags for whether we can collapse our margins with our children's margins. |
| 155 | bool m_canCollapseWithChildren : 1; |
| 156 | bool m_canCollapseMarginBeforeWithChildren : 1; |
| 157 | bool m_canCollapseMarginAfterWithChildren : 1; |
| 158 | |
| 159 | // Whether or not we are a quirky container, i.e., do we collapse away top and bottom |
| 160 | // margins in our container. Table cells and the body are the common examples. We |
| 161 | // also have a custom style property for Safari RSS to deal with TypePad blog articles. |
| 162 | bool m_quirkContainer : 1; |
| 163 | |
| 164 | // This flag tracks whether we are still looking at child margins that can all collapse together at the beginning of a block. |
| 165 | // They may or may not collapse with the top margin of the block (|m_canCollapseTopWithChildren| tells us that), but they will |
| 166 | // always be collapsing with one another. This variable can remain set to true through multiple iterations |
| 167 | // as long as we keep encountering self-collapsing blocks. |
| 168 | bool m_atBeforeSideOfBlock : 1; |
| 169 | |
| 170 | // This flag is set when we know we're examining bottom margins and we know we're at the bottom of the block. |
| 171 | bool m_atAfterSideOfBlock : 1; |
| 172 | |
| 173 | // These variables are used to detect quirky margins that we need to collapse away (in table cells |
| 174 | // and in the body element). |
| 175 | bool m_hasMarginBeforeQuirk : 1; |
| 176 | bool m_hasMarginAfterQuirk : 1; |
| 177 | bool m_determinedMarginBeforeQuirk : 1; |
| 178 | |
| 179 | bool m_discardMargin : 1; |
| 180 | |
| 181 | // These flags track the previous maximal positive and negative margins. |
| 182 | LayoutUnit m_positiveMargin; |
| 183 | LayoutUnit m_negativeMargin; |
| 184 | |
| 185 | public: |
| 186 | MarginInfo(const RenderBlockFlow&, LayoutUnit beforeBorderPadding, LayoutUnit afterBorderPadding); |
| 187 | |
| 188 | void setAtBeforeSideOfBlock(bool b) { m_atBeforeSideOfBlock = b; } |
| 189 | void setAtAfterSideOfBlock(bool b) { m_atAfterSideOfBlock = b; } |
| 190 | void clearMargin() |
| 191 | { |
| 192 | m_positiveMargin = 0; |
| 193 | m_negativeMargin = 0; |
| 194 | } |
| 195 | void setHasMarginBeforeQuirk(bool b) { m_hasMarginBeforeQuirk = b; } |
| 196 | void setHasMarginAfterQuirk(bool b) { m_hasMarginAfterQuirk = b; } |
| 197 | void setDeterminedMarginBeforeQuirk(bool b) { m_determinedMarginBeforeQuirk = b; } |
| 198 | void setPositiveMargin(LayoutUnit p) { ASSERT(!m_discardMargin); m_positiveMargin = p; } |
| 199 | void setNegativeMargin(LayoutUnit n) { ASSERT(!m_discardMargin); m_negativeMargin = n; } |
| 200 | void setPositiveMarginIfLarger(LayoutUnit p) |
| 201 | { |
| 202 | ASSERT(!m_discardMargin); |
| 203 | if (p > m_positiveMargin) |
| 204 | m_positiveMargin = p; |
| 205 | } |
| 206 | void setNegativeMarginIfLarger(LayoutUnit n) |
| 207 | { |
| 208 | ASSERT(!m_discardMargin); |
| 209 | if (n > m_negativeMargin) |
| 210 | m_negativeMargin = n; |
| 211 | } |
| 212 | |
| 213 | void setMargin(LayoutUnit p, LayoutUnit n) { ASSERT(!m_discardMargin); m_positiveMargin = p; m_negativeMargin = n; } |
| 214 | void setCanCollapseMarginAfterWithChildren(bool collapse) { m_canCollapseMarginAfterWithChildren = collapse; } |
| 215 | void setDiscardMargin(bool value) { m_discardMargin = value; } |
| 216 | |
| 217 | bool atBeforeSideOfBlock() const { return m_atBeforeSideOfBlock; } |
| 218 | bool canCollapseWithMarginBefore() const { return m_atBeforeSideOfBlock && m_canCollapseMarginBeforeWithChildren; } |
| 219 | bool canCollapseWithMarginAfter() const { return m_atAfterSideOfBlock && m_canCollapseMarginAfterWithChildren; } |
| 220 | bool canCollapseMarginBeforeWithChildren() const { return m_canCollapseMarginBeforeWithChildren; } |
| 221 | bool canCollapseMarginAfterWithChildren() const { return m_canCollapseMarginAfterWithChildren; } |
| 222 | bool quirkContainer() const { return m_quirkContainer; } |
| 223 | bool determinedMarginBeforeQuirk() const { return m_determinedMarginBeforeQuirk; } |
| 224 | bool hasMarginBeforeQuirk() const { return m_hasMarginBeforeQuirk; } |
| 225 | bool hasMarginAfterQuirk() const { return m_hasMarginAfterQuirk; } |
| 226 | LayoutUnit positiveMargin() const { return m_positiveMargin; } |
| 227 | LayoutUnit negativeMargin() const { return m_negativeMargin; } |
| 228 | bool discardMargin() const { return m_discardMargin; } |
| 229 | LayoutUnit margin() const { return m_positiveMargin - m_negativeMargin; } |
| 230 | }; |
| 231 | LayoutUnit marginOffsetForSelfCollapsingBlock(); |
| 232 | |
| 233 | void layoutBlockChild(RenderBox& child, MarginInfo&, LayoutUnit& previousFloatLogicalBottom, LayoutUnit& maxFloatLogicalBottom); |
| 234 | void adjustPositionedBlock(RenderBox& child, const MarginInfo&); |
| 235 | void adjustFloatingBlock(const MarginInfo&); |
| 236 | |
| 237 | void setStaticInlinePositionForChild(RenderBox& child, LayoutUnit blockOffset, LayoutUnit inlinePosition); |
| 238 | void updateStaticInlinePositionForChild(RenderBox& child, LayoutUnit logicalTop, IndentTextOrNot shouldIndentText); |
| 239 | |
| 240 | LayoutUnit collapseMargins(RenderBox& child, MarginInfo&); |
| 241 | LayoutUnit collapseMarginsWithChildInfo(RenderBox* child, RenderObject* prevSibling, MarginInfo&); |
| 242 | |
| 243 | LayoutUnit clearFloatsIfNeeded(RenderBox& child, MarginInfo&, LayoutUnit oldTopPosMargin, LayoutUnit oldTopNegMargin, LayoutUnit yPos); |
| 244 | LayoutUnit estimateLogicalTopPosition(RenderBox& child, const MarginInfo&, LayoutUnit& ); |
| 245 | void marginBeforeEstimateForChild(RenderBox&, LayoutUnit&, LayoutUnit&, bool&) const; |
| 246 | void handleAfterSideOfBlock(LayoutUnit top, LayoutUnit bottom, MarginInfo&); |
| 247 | void setCollapsedBottomMargin(const MarginInfo&); |
| 248 | |
| 249 | bool childrenPreventSelfCollapsing() const final; |
| 250 | |
| 251 | bool shouldBreakAtLineToAvoidWidow() const { return hasRareBlockFlowData() && rareBlockFlowData()->m_lineBreakToAvoidWidow >= 0; } |
| 252 | void clearShouldBreakAtLineToAvoidWidow() const; |
| 253 | int lineBreakToAvoidWidow() const { return hasRareBlockFlowData() ? rareBlockFlowData()->m_lineBreakToAvoidWidow : -1; } |
| 254 | void setBreakAtLineToAvoidWidow(int); |
| 255 | void clearDidBreakAtLineToAvoidWidow(); |
| 256 | void setDidBreakAtLineToAvoidWidow(); |
| 257 | bool didBreakAtLineToAvoidWidow() const { return hasRareBlockFlowData() && rareBlockFlowData()->m_didBreakAtLineToAvoidWidow; } |
| 258 | bool relayoutToAvoidWidows(); |
| 259 | |
| 260 | RootInlineBox* lineGridBox() const { return hasRareBlockFlowData() ? rareBlockFlowData()->m_lineGridBox.get() : nullptr; } |
| 261 | void setLineGridBox(std::unique_ptr<RootInlineBox> box) |
| 262 | { |
| 263 | ensureRareBlockFlowData().m_lineGridBox = WTFMove(box); |
| 264 | } |
| 265 | void layoutLineGridBox(); |
| 266 | |
| 267 | RenderMultiColumnFlow* multiColumnFlow() const { return hasRareBlockFlowData() ? rareBlockFlowData()->m_multiColumnFlow.get() : nullptr; } |
| 268 | void setMultiColumnFlow(RenderMultiColumnFlow&); |
| 269 | void clearMultiColumnFlow(); |
| 270 | bool willCreateColumns(Optional<unsigned> desiredColumnCount = WTF::nullopt) const; |
| 271 | virtual bool requiresColumns(int) const; |
| 272 | |
| 273 | bool containsFloats() const override { return m_floatingObjects && !m_floatingObjects->set().isEmpty(); } |
| 274 | bool containsFloat(RenderBox&) const; |
| 275 | |
| 276 | void deleteLines() override; |
| 277 | void computeOverflow(LayoutUnit oldClientAfterEdge, bool recomputeFloats = false) override; |
| 278 | Position positionForPoint(const LayoutPoint&) override; |
| 279 | VisiblePosition positionForPoint(const LayoutPoint&, const RenderFragmentContainer*) override; |
| 280 | |
| 281 | LayoutUnit lowestFloatLogicalBottom(FloatingObject::Type = FloatingObject::FloatLeftRight) const; |
| 282 | |
| 283 | void removeFloatingObjects(); |
| 284 | void markAllDescendantsWithFloatsForLayout(RenderBox* floatToRemove = nullptr, bool inLayout = true); |
| 285 | void markSiblingsWithFloatsForLayout(RenderBox* floatToRemove = nullptr); |
| 286 | |
| 287 | const FloatingObjectSet* floatingObjectSet() const { return m_floatingObjects ? &m_floatingObjects->set() : nullptr; } |
| 288 | |
| 289 | LayoutUnit logicalTopForFloat(const FloatingObject& floatingObject) const { return isHorizontalWritingMode() ? floatingObject.y() : floatingObject.x(); } |
| 290 | LayoutUnit logicalBottomForFloat(const FloatingObject& floatingObject) const { return isHorizontalWritingMode() ? floatingObject.maxY() : floatingObject.maxX(); } |
| 291 | LayoutUnit logicalLeftForFloat(const FloatingObject& floatingObject) const { return isHorizontalWritingMode() ? floatingObject.x() : floatingObject.y(); } |
| 292 | LayoutUnit logicalRightForFloat(const FloatingObject& floatingObject) const { return isHorizontalWritingMode() ? floatingObject.maxX() : floatingObject.maxY(); } |
| 293 | LayoutUnit logicalWidthForFloat(const FloatingObject& floatingObject) const { return isHorizontalWritingMode() ? floatingObject.width() : floatingObject.height(); } |
| 294 | LayoutUnit logicalHeightForFloat(const FloatingObject& floatingObject) const { return isHorizontalWritingMode() ? floatingObject.height() : floatingObject.width(); } |
| 295 | |
| 296 | void setLogicalTopForFloat(FloatingObject& floatingObject, LayoutUnit logicalTop) |
| 297 | { |
| 298 | if (isHorizontalWritingMode()) |
| 299 | floatingObject.setY(logicalTop); |
| 300 | else |
| 301 | floatingObject.setX(logicalTop); |
| 302 | } |
| 303 | void setLogicalLeftForFloat(FloatingObject& floatingObject, LayoutUnit logicalLeft) |
| 304 | { |
| 305 | if (isHorizontalWritingMode()) |
| 306 | floatingObject.setX(logicalLeft); |
| 307 | else |
| 308 | floatingObject.setY(logicalLeft); |
| 309 | } |
| 310 | void setLogicalHeightForFloat(FloatingObject& floatingObject, LayoutUnit logicalHeight) |
| 311 | { |
| 312 | if (isHorizontalWritingMode()) |
| 313 | floatingObject.setHeight(logicalHeight); |
| 314 | else |
| 315 | floatingObject.setWidth(logicalHeight); |
| 316 | } |
| 317 | void setLogicalWidthForFloat(FloatingObject& floatingObject, LayoutUnit logicalWidth) |
| 318 | { |
| 319 | if (isHorizontalWritingMode()) |
| 320 | floatingObject.setWidth(logicalWidth); |
| 321 | else |
| 322 | floatingObject.setHeight(logicalWidth); |
| 323 | } |
| 324 | void setLogicalMarginsForFloat(FloatingObject& floatingObject, LayoutUnit logicalLeftMargin, LayoutUnit logicalBeforeMargin) |
| 325 | { |
| 326 | if (isHorizontalWritingMode()) |
| 327 | floatingObject.setMarginOffset(LayoutSize(logicalLeftMargin, logicalBeforeMargin)); |
| 328 | else |
| 329 | floatingObject.setMarginOffset(LayoutSize(logicalBeforeMargin, logicalLeftMargin)); |
| 330 | } |
| 331 | |
| 332 | LayoutPoint flipFloatForWritingModeForChild(const FloatingObject&, const LayoutPoint&) const; |
| 333 | |
| 334 | RenderLineBoxList& lineBoxes() { return m_lineBoxes; } |
| 335 | const RenderLineBoxList& lineBoxes() const { return m_lineBoxes; } |
| 336 | |
| 337 | RootInlineBox* firstRootBox() const { return downcast<RootInlineBox>(m_lineBoxes.firstLineBox()); } |
| 338 | RootInlineBox* lastRootBox() const { return downcast<RootInlineBox>(m_lineBoxes.lastLineBox()); } |
| 339 | |
| 340 | bool hasLines() const; |
| 341 | void invalidateLineLayoutPath() final; |
| 342 | |
| 343 | enum LineLayoutPath { UndeterminedPath = 0, SimpleLinesPath, LineBoxesPath, ForceLineBoxesPath }; |
| 344 | LineLayoutPath lineLayoutPath() const { return static_cast<LineLayoutPath>(renderBlockFlowLineLayoutPath()); } |
| 345 | void setLineLayoutPath(LineLayoutPath path) { setRenderBlockFlowLineLayoutPath(path); } |
| 346 | |
| 347 | // Helper methods for computing line counts and heights for line counts. |
| 348 | RootInlineBox* lineAtIndex(int) const; |
| 349 | int lineCount(const RootInlineBox* = nullptr, bool* = nullptr) const; |
| 350 | int heightForLineCount(int); |
| 351 | void clearTruncation(); |
| 352 | |
| 353 | void setHasMarkupTruncation(bool b) { setRenderBlockFlowHasMarkupTruncation(b); } |
| 354 | bool hasMarkupTruncation() const { return renderBlockFlowHasMarkupTruncation(); } |
| 355 | |
| 356 | bool containsNonZeroBidiLevel() const; |
| 357 | |
| 358 | const SimpleLineLayout::Layout* simpleLineLayout() const; |
| 359 | void deleteLineBoxesBeforeSimpleLineLayout(); |
| 360 | void ensureLineBoxes(); |
| 361 | void generateLineBoxTree(); |
| 362 | |
| 363 | #if ENABLE(TREE_DEBUGGING) |
| 364 | void outputLineTreeAndMark(WTF::TextStream&, const InlineBox* markedBox, int depth) const; |
| 365 | #endif |
| 366 | |
| 367 | // Returns the logicalOffset at the top of the next page. If the offset passed in is already at the top of the current page, |
| 368 | // then nextPageLogicalTop with ExcludePageBoundary will still move to the top of the next page. nextPageLogicalTop with |
| 369 | // IncludePageBoundary set will not. |
| 370 | // |
| 371 | // For a page height of 800px, the first rule will return 800 if the value passed in is 0. The second rule will simply return 0. |
| 372 | enum PageBoundaryRule { ExcludePageBoundary, IncludePageBoundary }; |
| 373 | LayoutUnit nextPageLogicalTop(LayoutUnit logicalOffset, PageBoundaryRule = ExcludePageBoundary) const; |
| 374 | LayoutUnit pageLogicalTopForOffset(LayoutUnit offset) const; |
| 375 | LayoutUnit pageLogicalHeightForOffset(LayoutUnit offset) const; |
| 376 | LayoutUnit pageRemainingLogicalHeightForOffset(LayoutUnit offset, PageBoundaryRule = IncludePageBoundary) const; |
| 377 | LayoutUnit logicalHeightForChildForFragmentation(const RenderBox& child) const; |
| 378 | bool hasNextPage(LayoutUnit logicalOffset, PageBoundaryRule = ExcludePageBoundary) const; |
| 379 | |
| 380 | void updateColumnProgressionFromStyle(RenderStyle&); |
| 381 | void updateStylesForColumnChildren(); |
| 382 | |
| 383 | bool needsLayoutAfterFragmentRangeChange() const override; |
| 384 | WEBCORE_EXPORT RenderText* findClosestTextAtAbsolutePoint(const FloatPoint&); |
| 385 | |
| 386 | // A page break is required at some offset due to space shortage in the current fragmentainer. |
| 387 | void setPageBreak(LayoutUnit offset, LayoutUnit spaceShortage); |
| 388 | // Update minimum page height required to avoid fragmentation where it shouldn't occur (inside |
| 389 | // unbreakable content, between orphans and widows, etc.). This will be used as a hint to the |
| 390 | // column balancer to help set a good minimum column height. |
| 391 | void updateMinimumPageHeight(LayoutUnit offset, LayoutUnit minHeight); |
| 392 | |
| 393 | void addFloatsToNewParent(RenderBlockFlow& toBlockFlow) const; |
| 394 | |
| 395 | protected: |
| 396 | void computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const override; |
| 397 | |
| 398 | bool pushToNextPageWithMinimumLogicalHeight(LayoutUnit& adjustment, LayoutUnit logicalOffset, LayoutUnit minimumLogicalHeight) const; |
| 399 | |
| 400 | // If the child is unsplittable and can't fit on the current page, return the top of the next page/column. |
| 401 | LayoutUnit adjustForUnsplittableChild(RenderBox& child, LayoutUnit logicalOffset, LayoutUnit beforeMargin = 0_lu, LayoutUnit afterMargin = 0_lu); |
| 402 | LayoutUnit (LayoutUnit logicalTopAfterClear, LayoutUnit , RenderBox& child, bool atBeforeSideOfBlock); |
| 403 | LayoutUnit applyBeforeBreak(RenderBox& child, LayoutUnit logicalOffset); // If the child has a before break, then return a new yPos that shifts to the top of the next page/column. |
| 404 | LayoutUnit applyAfterBreak(RenderBox& child, LayoutUnit logicalOffset, MarginInfo&); // If the child has an after break, then return a new offset that shifts to the top of the next page/column. |
| 405 | |
| 406 | LayoutUnit maxPositiveMarginBefore() const { return hasRareBlockFlowData() ? rareBlockFlowData()->m_margins.positiveMarginBefore() : RenderBlockFlowRareData::positiveMarginBeforeDefault(*this); } |
| 407 | LayoutUnit maxNegativeMarginBefore() const { return hasRareBlockFlowData() ? rareBlockFlowData()->m_margins.negativeMarginBefore() : RenderBlockFlowRareData::negativeMarginBeforeDefault(*this); } |
| 408 | LayoutUnit maxPositiveMarginAfter() const { return hasRareBlockFlowData() ? rareBlockFlowData()->m_margins.positiveMarginAfter() : RenderBlockFlowRareData::positiveMarginAfterDefault(*this); } |
| 409 | LayoutUnit maxNegativeMarginAfter() const { return hasRareBlockFlowData() ? rareBlockFlowData()->m_margins.negativeMarginAfter() : RenderBlockFlowRareData::negativeMarginAfterDefault(*this); } |
| 410 | |
| 411 | void initMaxMarginValues() |
| 412 | { |
| 413 | if (!hasRareBlockFlowData()) |
| 414 | return; |
| 415 | |
| 416 | rareBlockFlowData()->m_margins = MarginValues(RenderBlockFlowRareData::positiveMarginBeforeDefault(*this) , RenderBlockFlowRareData::negativeMarginBeforeDefault(*this), |
| 417 | RenderBlockFlowRareData::positiveMarginAfterDefault(*this), RenderBlockFlowRareData::negativeMarginAfterDefault(*this)); |
| 418 | rareBlockFlowData()->m_discardMarginBefore = false; |
| 419 | rareBlockFlowData()->m_discardMarginAfter = false; |
| 420 | } |
| 421 | |
| 422 | void setMaxMarginBeforeValues(LayoutUnit pos, LayoutUnit neg); |
| 423 | void setMaxMarginAfterValues(LayoutUnit pos, LayoutUnit neg); |
| 424 | |
| 425 | void setMustDiscardMarginBefore(bool = true); |
| 426 | void setMustDiscardMarginAfter(bool = true); |
| 427 | |
| 428 | bool mustDiscardMarginBefore() const; |
| 429 | bool mustDiscardMarginAfter() const; |
| 430 | |
| 431 | bool mustDiscardMarginBeforeForChild(const RenderBox&) const; |
| 432 | bool mustDiscardMarginAfterForChild(const RenderBox&) const; |
| 433 | bool mustSeparateMarginBeforeForChild(const RenderBox&) const; |
| 434 | bool mustSeparateMarginAfterForChild(const RenderBox&) const; |
| 435 | |
| 436 | void styleWillChange(StyleDifference, const RenderStyle& newStyle) override; |
| 437 | void styleDidChange(StyleDifference, const RenderStyle* oldStyle) override; |
| 438 | |
| 439 | void createFloatingObjects(); |
| 440 | |
| 441 | Optional<int> firstLineBaseline() const override; |
| 442 | Optional<int> inlineBlockBaseline(LineDirectionMode) const override; |
| 443 | |
| 444 | bool isMultiColumnBlockFlow() const override { return multiColumnFlow(); } |
| 445 | |
| 446 | void setComputedColumnCountAndWidth(int, LayoutUnit); |
| 447 | |
| 448 | LayoutUnit computedColumnWidth() const; |
| 449 | unsigned computedColumnCount() const; |
| 450 | |
| 451 | bool isTopLayoutOverflowAllowed() const override; |
| 452 | bool isLeftLayoutOverflowAllowed() const override; |
| 453 | |
| 454 | virtual void computeColumnCountAndWidth(); |
| 455 | |
| 456 | virtual void cachePriorCharactersIfNeeded(const LazyLineBreakIterator&) {}; |
| 457 | |
| 458 | protected: |
| 459 | // Called to lay out the legend for a fieldset or the ruby text of a ruby run. Also used by multi-column layout to handle |
| 460 | // the flow thread child. |
| 461 | void layoutExcludedChildren(bool relayoutChildren) override; |
| 462 | void addOverflowFromFloats(); |
| 463 | |
| 464 | private: |
| 465 | bool recomputeLogicalWidthAndColumnWidth(); |
| 466 | LayoutUnit columnGap() const; |
| 467 | |
| 468 | RenderBlockFlow* previousSiblingWithOverhangingFloats(bool& parentHasFloats) const; |
| 469 | |
| 470 | void (bool& relayoutChildren, LayoutUnit& pageLogicalHeight, bool& pageLogicalHeightChanged); |
| 471 | |
| 472 | void paintInlineChildren(PaintInfo&, const LayoutPoint&) override; |
| 473 | void paintFloats(PaintInfo&, const LayoutPoint&, bool preservePhase = false) override; |
| 474 | |
| 475 | void repaintOverhangingFloats(bool paintAllDescendants) final; |
| 476 | void clipOutFloatingObjects(RenderBlock&, const PaintInfo*, const LayoutPoint&, const LayoutSize&) override; |
| 477 | |
| 478 | FloatingObject* insertFloatingObject(RenderBox&); |
| 479 | void removeFloatingObject(RenderBox&); |
| 480 | void removeFloatingObjectsBelow(FloatingObject*, int logicalOffset); |
| 481 | void computeLogicalLocationForFloat(FloatingObject&, LayoutUnit& logicalTopOffset); |
| 482 | |
| 483 | // Called from lineWidth, to position the floats added in the last line. |
| 484 | // Returns true if and only if it has positioned any floats. |
| 485 | bool positionNewFloats(); |
| 486 | |
| 487 | void clearFloats(Clear); |
| 488 | |
| 489 | LayoutUnit logicalRightFloatOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, LayoutUnit logicalHeight) const override; |
| 490 | LayoutUnit logicalLeftFloatOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, LayoutUnit logicalHeight) const override; |
| 491 | |
| 492 | LayoutUnit logicalRightOffsetForPositioningFloat(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit* heightRemaining) const; |
| 493 | LayoutUnit logicalLeftOffsetForPositioningFloat(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit* heightRemaining) const; |
| 494 | |
| 495 | LayoutUnit lowestInitialLetterLogicalBottom() const; |
| 496 | |
| 497 | LayoutUnit nextFloatLogicalBottomBelow(LayoutUnit) const; |
| 498 | LayoutUnit nextFloatLogicalBottomBelowForBlock(LayoutUnit) const; |
| 499 | |
| 500 | LayoutUnit addOverhangingFloats(RenderBlockFlow& child, bool makeChildPaintOtherFloats); |
| 501 | bool hasOverhangingFloat(RenderBox&); |
| 502 | void addIntrudingFloats(RenderBlockFlow* prev, RenderBlockFlow* container, LayoutUnit xoffset, LayoutUnit yoffset); |
| 503 | bool hasOverhangingFloats() { return parent() && containsFloats() && lowestFloatLogicalBottom() > logicalHeight(); } |
| 504 | LayoutUnit getClearDelta(RenderBox& child, LayoutUnit yPos); |
| 505 | |
| 506 | void determineLogicalLeftPositionForChild(RenderBox& child, ApplyLayoutDeltaMode = DoNotApplyLayoutDelta); |
| 507 | |
| 508 | bool hitTestFloats(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset) override; |
| 509 | bool hitTestInlineChildren(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) override; |
| 510 | |
| 511 | void addOverflowFromInlineChildren() override; |
| 512 | |
| 513 | void fitBorderToLinesIfNeeded(); // Shrink the box in which the border paints if border-fit is set. |
| 514 | void adjustForBorderFit(LayoutUnit x, LayoutUnit& left, LayoutUnit& right) const; |
| 515 | |
| 516 | void markLinesDirtyInBlockRange(LayoutUnit logicalTop, LayoutUnit logicalBottom, RootInlineBox* highest = 0); |
| 517 | |
| 518 | GapRects inlineSelectionGaps(RenderBlock& rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock, |
| 519 | LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const LogicalSelectionOffsetCaches&, const PaintInfo*) override; |
| 520 | |
| 521 | Position positionForBox(InlineBox*, bool start = true) const; |
| 522 | VisiblePosition positionForPointWithInlineChildren(const LayoutPoint& pointInLogicalContents, const RenderFragmentContainer*) override; |
| 523 | void addFocusRingRectsForInlineChildren(Vector<LayoutRect>& rects, const LayoutPoint& additionalOffset, const RenderLayerModelObject*) override; |
| 524 | |
| 525 | // FIXME-BLOCKFLOW: These methods have implementations in |
| 526 | // RenderBlockLineLayout. They should be moved to the proper header once the |
| 527 | // line layout code is separated from RenderBlock and RenderBlockFlow. |
| 528 | // START METHODS DEFINED IN RenderBlockLineLayout |
| 529 | public: |
| 530 | static void appendRunsForObject(BidiRunList<BidiRun>*, int start, int end, RenderObject&, InlineBidiResolver&); |
| 531 | RootInlineBox* createAndAppendRootInlineBox(); |
| 532 | |
| 533 | LayoutUnit startAlignedOffsetForLine(LayoutUnit position, IndentTextOrNot shouldIndentText); |
| 534 | virtual TextAlignMode textAlignmentForLine(bool endsWithSoftBreak) const; |
| 535 | virtual void adjustInlineDirectionLineBounds(int /* expansionOpportunityCount */, float& /* logicalLeft */, float& /* logicalWidth */) const { } |
| 536 | RootInlineBox* constructLine(BidiRunList<BidiRun>&, const LineInfo&); |
| 537 | |
| 538 | private: |
| 539 | void adjustIntrinsicLogicalWidthsForColumns(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const; |
| 540 | |
| 541 | void layoutLineBoxes(bool relayoutChildren, LayoutUnit& repaintLogicalTop, LayoutUnit& repaintLogicalBottom); |
| 542 | void layoutSimpleLines(bool relayoutChildren, LayoutUnit& repaintLogicalTop, LayoutUnit& repaintLogicalBottom); |
| 543 | |
| 544 | virtual std::unique_ptr<RootInlineBox> createRootInlineBox(); // Subclassed by RenderSVGText. |
| 545 | InlineFlowBox* createLineBoxes(RenderObject*, const LineInfo&, InlineBox* childBox); |
| 546 | void setMarginsForRubyRun(BidiRun*, RenderRubyRun&, RenderObject*, const LineInfo&); |
| 547 | void computeInlineDirectionPositionsForLine(RootInlineBox*, const LineInfo&, BidiRun* firstRun, BidiRun* trailingSpaceRun, bool reachedEnd, GlyphOverflowAndFallbackFontsMap&, VerticalPositionCache&, WordMeasurements&); |
| 548 | void updateRubyForJustifiedText(RenderRubyRun&, BidiRun&, const Vector<unsigned, 16>& expansionOpportunities, unsigned& expansionOpportunityCount, float& totalLogicalWidth, float availableLogicalWidth, size_t& expansionIndex); |
| 549 | void computeExpansionForJustifiedText(BidiRun* firstRun, BidiRun* trailingSpaceRun, const Vector<unsigned, 16>& expansionOpportunities, unsigned expansionOpportunityCount, float totalLogicalWidth, float availableLogicalWidth); |
| 550 | BidiRun* computeInlineDirectionPositionsForSegment(RootInlineBox*, const LineInfo&, TextAlignMode, float& logicalLeft, |
| 551 | float& availableLogicalWidth, BidiRun* firstRun, BidiRun* trailingSpaceRun, GlyphOverflowAndFallbackFontsMap& textBoxDataMap, VerticalPositionCache&, WordMeasurements&); |
| 552 | void computeBlockDirectionPositionsForLine(RootInlineBox*, BidiRun*, GlyphOverflowAndFallbackFontsMap&, VerticalPositionCache&); |
| 553 | BidiRun* handleTrailingSpaces(BidiRunList<BidiRun>&, BidiContext*); |
| 554 | void appendFloatingObjectToLastLine(FloatingObject&); |
| 555 | // Helper function for layoutInlineChildren() |
| 556 | RootInlineBox* createLineBoxesFromBidiRuns(unsigned bidiLevel, BidiRunList<BidiRun>&, const InlineIterator& end, LineInfo&, VerticalPositionCache&, BidiRun* trailingSpaceRun, WordMeasurements&); |
| 557 | void layoutRunsAndFloats(LineLayoutState&, bool hasInlineChild); |
| 558 | const InlineIterator& restartLayoutRunsAndFloatsInRange(LayoutUnit oldLogicalHeight, LayoutUnit newLogicalHeight, FloatingObject* lastFloatFromPreviousLine, InlineBidiResolver&, const InlineIterator&); |
| 559 | void layoutRunsAndFloatsInRange(LineLayoutState&, InlineBidiResolver&, const InlineIterator& cleanLineStart, const BidiStatus& cleanLineBidiStatus, unsigned consecutiveHyphenatedLines); |
| 560 | void reattachCleanLineFloats(RootInlineBox& cleanLine, LayoutUnit delta, bool isFirstCleanLine); |
| 561 | void linkToEndLineIfNeeded(LineLayoutState&); |
| 562 | void checkFloatInCleanLine(RootInlineBox& cleanLine, RenderBox& floatBoxOnCleanLine, FloatWithRect& matchingFloatWithRect, |
| 563 | bool& encounteredNewFloat, bool& dirtiedByFloat); |
| 564 | RootInlineBox* determineStartPosition(LineLayoutState&, InlineBidiResolver&); |
| 565 | void determineEndPosition(LineLayoutState&, RootInlineBox* startBox, InlineIterator& cleanLineStart, BidiStatus& cleanLineBidiStatus); |
| 566 | bool checkPaginationAndFloatsAtEndLine(LineLayoutState&); |
| 567 | bool matchedEndLine(LineLayoutState&, const InlineBidiResolver&, const InlineIterator& endLineStart, const BidiStatus& endLineStatus); |
| 568 | void deleteEllipsisLineBoxes(); |
| 569 | void checkLinesForTextOverflow(); |
| 570 | // Positions new floats and also adjust all floats encountered on the line if any of them |
| 571 | // have to move to the next page/column. |
| 572 | bool positionNewFloatOnLine(const FloatingObject& newFloat, FloatingObject* lastFloatFromPreviousLine, LineInfo&, LineWidth&); |
| 573 | // This function is called to test a line box that has moved in the block direction to see if it has ended up in a new |
| 574 | // page/column that has a different available line width than the old one. Used to know when you have to dirty a |
| 575 | // line, i.e., that it can't be re-used. |
| 576 | bool lineWidthForPaginatedLineChanged(RootInlineBox*, LayoutUnit lineDelta, RenderFragmentedFlow*) const; |
| 577 | void updateLogicalWidthForAlignment(const TextAlignMode&, const RootInlineBox*, BidiRun* trailingSpaceRun, float& logicalLeft, float& totalLogicalWidth, float& availableLogicalWidth, int expansionOpportunityCount); |
| 578 | // END METHODS DEFINED IN RenderBlockLineLayout |
| 579 | |
| 580 | void computeInlinePreferredLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const; |
| 581 | |
| 582 | void adjustInitialLetterPosition(RenderBox& childBox, LayoutUnit& logicalTopOffset, LayoutUnit& marginBeforeOffset); |
| 583 | |
| 584 | #if ENABLE(TEXT_AUTOSIZING) |
| 585 | int m_widthForTextAutosizing; |
| 586 | unsigned m_lineCountForTextAutosizing : 2; |
| 587 | #endif |
| 588 | void setSelectionState(SelectionState) final; |
| 589 | |
| 590 | void removeInlineBox(BidiRun&, const RootInlineBox&) const; |
| 591 | |
| 592 | public: |
| 593 | // FIXME-BLOCKFLOW: These can be made protected again once all callers have been moved here. |
| 594 | void (RootInlineBox*, LayoutUnit& deltaOffset, bool& overflowsFragment, RenderFragmentedFlow*); // Computes a deltaOffset value that put a line at the top of the next page if it doesn't fit on the current page. |
| 595 | void updateFragmentForLine(RootInlineBox*) const; |
| 596 | |
| 597 | // Pagination routines. |
| 598 | bool (); |
| 599 | |
| 600 | bool hasRareBlockFlowData() const { return m_rareBlockFlowData.get(); } |
| 601 | RenderBlockFlowRareData* rareBlockFlowData() const { ASSERT_WITH_SECURITY_IMPLICATION(hasRareBlockFlowData()); return m_rareBlockFlowData.get(); } |
| 602 | RenderBlockFlowRareData& ensureRareBlockFlowData(); |
| 603 | void materializeRareBlockFlowData(); |
| 604 | |
| 605 | #if ENABLE(TEXT_AUTOSIZING) |
| 606 | int lineCountForTextAutosizing(); |
| 607 | void adjustComputedFontSizes(float size, float visibleWidth, float pageScale, bool idempotentMode); |
| 608 | void resetComputedFontSize() |
| 609 | { |
| 610 | m_widthForTextAutosizing = -1; |
| 611 | m_lineCountForTextAutosizing = NOT_SET; |
| 612 | } |
| 613 | #endif |
| 614 | |
| 615 | protected: |
| 616 | std::unique_ptr<FloatingObjects> m_floatingObjects; |
| 617 | std::unique_ptr<RenderBlockFlowRareData> m_rareBlockFlowData; |
| 618 | RenderLineBoxList m_lineBoxes; |
| 619 | std::unique_ptr<SimpleLineLayout::Layout> m_simpleLineLayout; |
| 620 | |
| 621 | friend class LineBreaker; |
| 622 | friend class LineWidth; // Needs to know FloatingObject |
| 623 | }; |
| 624 | |
| 625 | inline const SimpleLineLayout::Layout* RenderBlockFlow::simpleLineLayout() const |
| 626 | { |
| 627 | ASSERT(lineLayoutPath() == SimpleLinesPath || !m_simpleLineLayout); |
| 628 | return m_simpleLineLayout.get(); |
| 629 | } |
| 630 | |
| 631 | } // namespace WebCore |
| 632 | |
| 633 | SPECIALIZE_TYPE_TRAITS_RENDER_OBJECT(RenderBlockFlow, isRenderBlockFlow()) |
| 634 | |