1/*
2 * Copyright (C) 2011 Adobe Systems Incorporated. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above
9 * copyright notice, this list of conditions and the following
10 * disclaimer.
11 * 2. Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following
13 * disclaimer in the documentation and/or other materials
14 * provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
21 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
25 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
26 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#include "config.h"
31#include "RenderFragmentContainer.h"
32
33#include "GraphicsContext.h"
34#include "HitTestResult.h"
35#include "IntRect.h"
36#include "LayoutRepainter.h"
37#include "Range.h"
38#include "RenderBoxFragmentInfo.h"
39#include "RenderFragmentedFlow.h"
40#include "RenderInline.h"
41#include "RenderIterator.h"
42#include "RenderLayer.h"
43#include "RenderView.h"
44#include "StyleResolver.h"
45#include <wtf/HexNumber.h>
46#include <wtf/IsoMallocInlines.h>
47
48namespace WebCore {
49
50WTF_MAKE_ISO_ALLOCATED_IMPL(RenderFragmentContainer);
51
52RenderFragmentContainer::RenderFragmentContainer(Element& element, RenderStyle&& style, RenderFragmentedFlow* fragmentedFlow)
53 : RenderBlockFlow(element, WTFMove(style))
54 , m_fragmentedFlow(fragmentedFlow)
55 , m_isValid(false)
56{
57}
58
59RenderFragmentContainer::RenderFragmentContainer(Document& document, RenderStyle&& style, RenderFragmentedFlow* fragmentedFlow)
60 : RenderBlockFlow(document, WTFMove(style))
61 , m_fragmentedFlow(fragmentedFlow)
62 , m_isValid(false)
63{
64}
65
66LayoutPoint RenderFragmentContainer::mapFragmentPointIntoFragmentedFlowCoordinates(const LayoutPoint& point)
67{
68 // Assuming the point is relative to the fragment block, 3 cases will be considered:
69 // a) top margin, padding or border.
70 // b) bottom margin, padding or border.
71 // c) non-content fragment area.
72
73 LayoutUnit pointLogicalTop(isHorizontalWritingMode() ? point.y() : point.x());
74 LayoutUnit pointLogicalLeft(isHorizontalWritingMode() ? point.x() : point.y());
75 LayoutUnit fragmentedFlowLogicalTop(isHorizontalWritingMode() ? m_fragmentedFlowPortionRect.y() : m_fragmentedFlowPortionRect.x());
76 LayoutUnit fragmentedFlowLogicalLeft(isHorizontalWritingMode() ? m_fragmentedFlowPortionRect.x() : m_fragmentedFlowPortionRect.y());
77 LayoutUnit fragmentedFlowPortionTopBound(isHorizontalWritingMode() ? m_fragmentedFlowPortionRect.height() : m_fragmentedFlowPortionRect.width());
78 LayoutUnit fragmentedFlowPortionLeftBound(isHorizontalWritingMode() ? m_fragmentedFlowPortionRect.width() : m_fragmentedFlowPortionRect.height());
79 LayoutUnit fragmentedFlowPortionTopMax(isHorizontalWritingMode() ? m_fragmentedFlowPortionRect.maxY() : m_fragmentedFlowPortionRect.maxX());
80 LayoutUnit fragmentedFlowPortionLeftMax(isHorizontalWritingMode() ? m_fragmentedFlowPortionRect.maxX() : m_fragmentedFlowPortionRect.maxY());
81 LayoutUnit effectiveFixedPointDenominator;
82 effectiveFixedPointDenominator.setRawValue(1);
83
84 if (pointLogicalTop < 0) {
85 LayoutPoint pointInThread(0_lu, fragmentedFlowLogicalTop);
86 return isHorizontalWritingMode() ? pointInThread : pointInThread.transposedPoint();
87 }
88
89 if (pointLogicalTop >= fragmentedFlowPortionTopBound) {
90 LayoutPoint pointInThread(fragmentedFlowPortionLeftBound, fragmentedFlowPortionTopMax - effectiveFixedPointDenominator);
91 return isHorizontalWritingMode() ? pointInThread : pointInThread.transposedPoint();
92 }
93
94 if (pointLogicalLeft < 0) {
95 LayoutPoint pointInThread(fragmentedFlowLogicalLeft, pointLogicalTop + fragmentedFlowLogicalTop);
96 return isHorizontalWritingMode() ? pointInThread : pointInThread.transposedPoint();
97 }
98 if (pointLogicalLeft >= fragmentedFlowPortionLeftBound) {
99 LayoutPoint pointInThread(fragmentedFlowPortionLeftMax - effectiveFixedPointDenominator, pointLogicalTop + fragmentedFlowLogicalTop);
100 return isHorizontalWritingMode() ? pointInThread : pointInThread.transposedPoint();
101 }
102 LayoutPoint pointInThread(pointLogicalLeft + fragmentedFlowLogicalLeft, pointLogicalTop + fragmentedFlowLogicalTop);
103 return isHorizontalWritingMode() ? pointInThread : pointInThread.transposedPoint();
104}
105
106VisiblePosition RenderFragmentContainer::positionForPoint(const LayoutPoint& point, const RenderFragmentContainer* fragment)
107{
108 if (!isValid() || !m_fragmentedFlow->firstChild()) // checking for empty fragment blocks.
109 return RenderBlock::positionForPoint(point, fragment);
110
111 return m_fragmentedFlow->positionForPoint(mapFragmentPointIntoFragmentedFlowCoordinates(point), this);
112}
113
114LayoutUnit RenderFragmentContainer::pageLogicalWidth() const
115{
116 ASSERT(isValid());
117 return m_fragmentedFlow->isHorizontalWritingMode() ? contentWidth() : contentHeight();
118}
119
120LayoutUnit RenderFragmentContainer::pageLogicalHeight() const
121{
122 ASSERT(isValid());
123 return m_fragmentedFlow->isHorizontalWritingMode() ? contentHeight() : contentWidth();
124}
125
126LayoutUnit RenderFragmentContainer::logicalHeightOfAllFragmentedFlowContent() const
127{
128 return pageLogicalHeight();
129}
130
131LayoutRect RenderFragmentContainer::fragmentedFlowPortionOverflowRect()
132{
133 return overflowRectForFragmentedFlowPortion(fragmentedFlowPortionRect(), isFirstFragment(), isLastFragment(), VisualOverflow);
134}
135
136LayoutPoint RenderFragmentContainer::fragmentedFlowPortionLocation() const
137{
138 LayoutPoint portionLocation;
139 LayoutRect portionRect = fragmentedFlowPortionRect();
140
141 if (fragmentedFlow()->style().isFlippedBlocksWritingMode()) {
142 LayoutRect flippedFragmentedFlowPortionRect(portionRect);
143 fragmentedFlow()->flipForWritingMode(flippedFragmentedFlowPortionRect);
144 portionLocation = flippedFragmentedFlowPortionRect.location();
145 } else
146 portionLocation = portionRect.location();
147
148 return portionLocation;
149}
150
151LayoutRect RenderFragmentContainer::overflowRectForFragmentedFlowPortion(const LayoutRect& fragmentedFlowPortionRect, bool isFirstPortion, bool isLastPortion, OverflowType overflowType)
152{
153 ASSERT(isValid());
154 if (shouldClipFragmentedFlowContent())
155 return fragmentedFlowPortionRect;
156
157 LayoutRect fragmentedFlowOverflow = overflowType == VisualOverflow ? visualOverflowRectForBox(*m_fragmentedFlow) : layoutOverflowRectForBox(m_fragmentedFlow);
158 LayoutRect clipRect;
159 if (m_fragmentedFlow->isHorizontalWritingMode()) {
160 LayoutUnit minY = isFirstPortion ? fragmentedFlowOverflow.y() : fragmentedFlowPortionRect.y();
161 LayoutUnit maxY = isLastPortion ? std::max(fragmentedFlowPortionRect.maxY(), fragmentedFlowOverflow.maxY()) : fragmentedFlowPortionRect.maxY();
162 bool clipX = style().overflowX() != Overflow::Visible;
163 LayoutUnit minX = clipX ? fragmentedFlowPortionRect.x() : std::min(fragmentedFlowPortionRect.x(), fragmentedFlowOverflow.x());
164 LayoutUnit maxX = clipX ? fragmentedFlowPortionRect.maxX() : std::max(fragmentedFlowPortionRect.maxX(), fragmentedFlowOverflow.maxX());
165 clipRect = LayoutRect(minX, minY, maxX - minX, maxY - minY);
166 } else {
167 LayoutUnit minX = isFirstPortion ? fragmentedFlowOverflow.x() : fragmentedFlowPortionRect.x();
168 LayoutUnit maxX = isLastPortion ? std::max(fragmentedFlowPortionRect.maxX(), fragmentedFlowOverflow.maxX()) : fragmentedFlowPortionRect.maxX();
169 bool clipY = style().overflowY() != Overflow::Visible;
170 LayoutUnit minY = clipY ? fragmentedFlowPortionRect.y() : std::min(fragmentedFlowPortionRect.y(), fragmentedFlowOverflow.y());
171 LayoutUnit maxY = clipY ? fragmentedFlowPortionRect.maxY() : std::max(fragmentedFlowPortionRect.y(), fragmentedFlowOverflow.maxY());
172 clipRect = LayoutRect(minX, minY, maxX - minX, maxY - minY);
173 }
174 return clipRect;
175}
176
177LayoutUnit RenderFragmentContainer::pageLogicalTopForOffset(LayoutUnit /* offset */) const
178{
179 return fragmentedFlow()->isHorizontalWritingMode() ? fragmentedFlowPortionRect().y() : fragmentedFlowPortionRect().x();
180}
181
182bool RenderFragmentContainer::isFirstFragment() const
183{
184 ASSERT(isValid());
185
186 return m_fragmentedFlow->firstFragment() == this;
187}
188
189bool RenderFragmentContainer::isLastFragment() const
190{
191 ASSERT(isValid());
192
193 return m_fragmentedFlow->lastFragment() == this;
194}
195
196bool RenderFragmentContainer::shouldClipFragmentedFlowContent() const
197{
198 return hasOverflowClip();
199}
200
201void RenderFragmentContainer::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
202{
203 RenderBlockFlow::styleDidChange(diff, oldStyle);
204
205 if (!isValid())
206 return;
207
208 if (oldStyle && oldStyle->writingMode() != style().writingMode())
209 m_fragmentedFlow->fragmentChangedWritingMode(this);
210}
211
212void RenderFragmentContainer::computeOverflowFromFragmentedFlow()
213{
214 ASSERT(isValid());
215
216 LayoutRect layoutRect = layoutOverflowRectForBox(m_fragmentedFlow);
217 layoutRect.setLocation(contentBoxRect().location() + (layoutRect.location() - m_fragmentedFlowPortionRect.location()));
218
219 // FIXME: Correctly adjust the layout overflow for writing modes.
220 addLayoutOverflow(layoutRect);
221 RenderFragmentedFlow* enclosingRenderFragmentedFlow = enclosingFragmentedFlow();
222 if (enclosingRenderFragmentedFlow)
223 enclosingRenderFragmentedFlow->addFragmentsLayoutOverflow(this, layoutRect);
224
225 updateLayerTransform();
226 updateScrollInfoAfterLayout();
227}
228
229void RenderFragmentContainer::repaintFragmentedFlowContent(const LayoutRect& repaintRect)
230{
231 repaintFragmentedFlowContentRectangle(repaintRect, fragmentedFlowPortionRect(), contentBoxRect().location());
232}
233
234void RenderFragmentContainer::repaintFragmentedFlowContentRectangle(const LayoutRect& repaintRect, const LayoutRect& fragmentedFlowPortionRect, const LayoutPoint& fragmentLocation, const LayoutRect* fragmentedFlowPortionClipRect)
235{
236 ASSERT(isValid());
237
238 // We only have to issue a repaint in this fragment if the fragment rect intersects the repaint rect.
239 LayoutRect clippedRect(repaintRect);
240
241 if (fragmentedFlowPortionClipRect) {
242 LayoutRect flippedFragmentedFlowPortionClipRect(*fragmentedFlowPortionClipRect);
243 fragmentedFlow()->flipForWritingMode(flippedFragmentedFlowPortionClipRect);
244 clippedRect.intersect(flippedFragmentedFlowPortionClipRect);
245 }
246
247 if (clippedRect.isEmpty())
248 return;
249
250 LayoutRect flippedFragmentedFlowPortionRect(fragmentedFlowPortionRect);
251 fragmentedFlow()->flipForWritingMode(flippedFragmentedFlowPortionRect); // Put the fragment rects into physical coordinates.
252
253 // Put the fragment rect into the fragment's physical coordinate space.
254 clippedRect.setLocation(fragmentLocation + (clippedRect.location() - flippedFragmentedFlowPortionRect.location()));
255
256 // Now switch to the fragment's writing mode coordinate space and let it repaint itself.
257 flipForWritingMode(clippedRect);
258
259 // Issue the repaint.
260 repaintRectangle(clippedRect);
261}
262
263void RenderFragmentContainer::installFragmentedFlow()
264{
265 ASSERT_NOT_REACHED();
266}
267
268void RenderFragmentContainer::attachFragment()
269{
270 if (renderTreeBeingDestroyed())
271 return;
272
273 // A fragment starts off invalid.
274 setIsValid(false);
275
276 // Initialize the flow thread reference and create the flow thread object if needed.
277 // The flow thread lifetime is influenced by the number of fragments attached to it,
278 // and we are attaching the fragment to the flow thread.
279 installFragmentedFlow();
280
281 if (!m_fragmentedFlow)
282 return;
283
284 // Only after adding the fragment to the thread, the fragment is marked to be valid.
285 m_fragmentedFlow->addFragmentToThread(this);
286}
287
288void RenderFragmentContainer::detachFragment()
289{
290 if (m_fragmentedFlow)
291 m_fragmentedFlow->removeFragmentFromThread(this);
292 m_fragmentedFlow = nullptr;
293}
294
295RenderBoxFragmentInfo* RenderFragmentContainer::renderBoxFragmentInfo(const RenderBox* box) const
296{
297 ASSERT(isValid());
298 return m_renderBoxFragmentInfo.get(box);
299}
300
301RenderBoxFragmentInfo* RenderFragmentContainer::setRenderBoxFragmentInfo(const RenderBox* box, LayoutUnit logicalLeftInset, LayoutUnit logicalRightInset,
302 bool containingBlockChainIsInset)
303{
304 ASSERT(isValid());
305
306 std::unique_ptr<RenderBoxFragmentInfo>& boxInfo = m_renderBoxFragmentInfo.add(box, std::make_unique<RenderBoxFragmentInfo>(logicalLeftInset, logicalRightInset, containingBlockChainIsInset)).iterator->value;
307 return boxInfo.get();
308}
309
310std::unique_ptr<RenderBoxFragmentInfo> RenderFragmentContainer::takeRenderBoxFragmentInfo(const RenderBox* box)
311{
312 return m_renderBoxFragmentInfo.take(box);
313}
314
315void RenderFragmentContainer::removeRenderBoxFragmentInfo(const RenderBox& box)
316{
317 m_renderBoxFragmentInfo.remove(&box);
318}
319
320void RenderFragmentContainer::deleteAllRenderBoxFragmentInfo()
321{
322 m_renderBoxFragmentInfo.clear();
323}
324
325LayoutUnit RenderFragmentContainer::logicalTopOfFragmentedFlowContentRect(const LayoutRect& rect) const
326{
327 ASSERT(isValid());
328 return fragmentedFlow()->isHorizontalWritingMode() ? rect.y() : rect.x();
329}
330
331LayoutUnit RenderFragmentContainer::logicalBottomOfFragmentedFlowContentRect(const LayoutRect& rect) const
332{
333 ASSERT(isValid());
334 return fragmentedFlow()->isHorizontalWritingMode() ? rect.maxY() : rect.maxX();
335}
336
337void RenderFragmentContainer::insertedIntoTree()
338{
339 attachFragment();
340 if (isValid())
341 RenderBlockFlow::insertedIntoTree();
342}
343
344void RenderFragmentContainer::willBeRemovedFromTree()
345{
346 RenderBlockFlow::willBeRemovedFromTree();
347
348 detachFragment();
349}
350
351void RenderFragmentContainer::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
352{
353 if (!isValid()) {
354 RenderBlockFlow::computeIntrinsicLogicalWidths(minLogicalWidth, maxLogicalWidth);
355 return;
356 }
357
358 minLogicalWidth = m_fragmentedFlow->minPreferredLogicalWidth();
359 maxLogicalWidth = m_fragmentedFlow->maxPreferredLogicalWidth();
360}
361
362void RenderFragmentContainer::computePreferredLogicalWidths()
363{
364 ASSERT(preferredLogicalWidthsDirty());
365
366 if (!isValid()) {
367 RenderBlockFlow::computePreferredLogicalWidths();
368 return;
369 }
370
371 // FIXME: Currently, the code handles only the <length> case for min-width/max-width.
372 // It should also support other values, like percentage, calc or viewport relative.
373 m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = 0;
374
375 const RenderStyle& styleToUse = style();
376 if (styleToUse.logicalWidth().isFixed() && styleToUse.logicalWidth().value() > 0)
377 m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = adjustContentBoxLogicalWidthForBoxSizing(styleToUse.logicalWidth().value());
378 else
379 computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
380
381 if (styleToUse.logicalMinWidth().isFixed() && styleToUse.logicalMinWidth().value() > 0) {
382 m_maxPreferredLogicalWidth = std::max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse.logicalMinWidth().value()));
383 m_minPreferredLogicalWidth = std::max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse.logicalMinWidth().value()));
384 }
385
386 if (styleToUse.logicalMaxWidth().isFixed()) {
387 m_maxPreferredLogicalWidth = std::min(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse.logicalMaxWidth().value()));
388 m_minPreferredLogicalWidth = std::min(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse.logicalMaxWidth().value()));
389 }
390
391 LayoutUnit borderAndPadding = borderAndPaddingLogicalWidth();
392 m_minPreferredLogicalWidth += borderAndPadding;
393 m_maxPreferredLogicalWidth += borderAndPadding;
394 setPreferredLogicalWidthsDirty(false);
395}
396
397void RenderFragmentContainer::adjustFragmentBoundsFromFragmentedFlowPortionRect(LayoutRect& fragmentBounds) const
398{
399 LayoutRect flippedFragmentedFlowPortionRect = fragmentedFlowPortionRect();
400 fragmentedFlow()->flipForWritingMode(flippedFragmentedFlowPortionRect);
401 fragmentBounds.moveBy(flippedFragmentedFlowPortionRect.location());
402}
403
404void RenderFragmentContainer::ensureOverflowForBox(const RenderBox* box, RefPtr<RenderOverflow>& overflow, bool forceCreation)
405{
406 ASSERT(m_fragmentedFlow->renderFragmentContainerList().contains(this));
407 ASSERT(isValid());
408
409 RenderBoxFragmentInfo* boxInfo = renderBoxFragmentInfo(box);
410 if (!boxInfo && !forceCreation)
411 return;
412
413 if (boxInfo && boxInfo->overflow()) {
414 overflow = boxInfo->overflow();
415 return;
416 }
417
418 LayoutRect borderBox = box->borderBoxRectInFragment(this);
419 LayoutRect clientBox;
420 ASSERT(m_fragmentedFlow->objectShouldFragmentInFlowFragment(box, this));
421
422 if (!borderBox.isEmpty()) {
423 borderBox = rectFlowPortionForBox(box, borderBox);
424
425 clientBox = box->clientBoxRectInFragment(this);
426 clientBox = rectFlowPortionForBox(box, clientBox);
427
428 m_fragmentedFlow->flipForWritingModeLocalCoordinates(borderBox);
429 m_fragmentedFlow->flipForWritingModeLocalCoordinates(clientBox);
430 }
431
432 if (boxInfo) {
433 boxInfo->createOverflow(clientBox, borderBox);
434 overflow = boxInfo->overflow();
435 } else
436 overflow = adoptRef(new RenderOverflow(clientBox, borderBox));
437}
438
439LayoutRect RenderFragmentContainer::rectFlowPortionForBox(const RenderBox* box, const LayoutRect& rect) const
440{
441 LayoutRect mappedRect = m_fragmentedFlow->mapFromLocalToFragmentedFlow(box, rect);
442
443 RenderFragmentContainer* startFragment = nullptr;
444 RenderFragmentContainer* endFragment = nullptr;
445 if (m_fragmentedFlow->getFragmentRangeForBox(box, startFragment, endFragment)) {
446 if (fragmentedFlow()->isHorizontalWritingMode()) {
447 if (this != startFragment)
448 mappedRect.shiftYEdgeTo(std::max<LayoutUnit>(logicalTopForFragmentedFlowContent(), mappedRect.y()));
449 if (this != endFragment)
450 mappedRect.setHeight(std::max<LayoutUnit>(0, std::min<LayoutUnit>(logicalBottomForFragmentedFlowContent() - mappedRect.y(), mappedRect.height())));
451 } else {
452 if (this != startFragment)
453 mappedRect.shiftXEdgeTo(std::max<LayoutUnit>(logicalTopForFragmentedFlowContent(), mappedRect.x()));
454 if (this != endFragment)
455 mappedRect.setWidth(std::max<LayoutUnit>(0, std::min<LayoutUnit>(logicalBottomForFragmentedFlowContent() - mappedRect.x(), mappedRect.width())));
456 }
457 }
458
459 return m_fragmentedFlow->mapFromFragmentedFlowToLocal(box, mappedRect);
460}
461
462void RenderFragmentContainer::addLayoutOverflowForBox(const RenderBox* box, const LayoutRect& rect)
463{
464 if (rect.isEmpty())
465 return;
466
467 RefPtr<RenderOverflow> fragmentOverflow;
468 ensureOverflowForBox(box, fragmentOverflow, false);
469
470 if (!fragmentOverflow)
471 return;
472
473 fragmentOverflow->addLayoutOverflow(rect);
474}
475
476void RenderFragmentContainer::addVisualOverflowForBox(const RenderBox* box, const LayoutRect& rect)
477{
478 if (rect.isEmpty())
479 return;
480
481 RefPtr<RenderOverflow> fragmentOverflow;
482 ensureOverflowForBox(box, fragmentOverflow, false);
483
484 if (!fragmentOverflow)
485 return;
486
487 LayoutRect flippedRect = rect;
488 fragmentedFlow()->flipForWritingModeLocalCoordinates(flippedRect);
489 fragmentOverflow->addVisualOverflow(flippedRect);
490}
491
492LayoutRect RenderFragmentContainer::layoutOverflowRectForBox(const RenderBox* box)
493{
494 RefPtr<RenderOverflow> overflow;
495 ensureOverflowForBox(box, overflow, true);
496
497 ASSERT(overflow);
498 return overflow->layoutOverflowRect();
499}
500
501LayoutRect RenderFragmentContainer::visualOverflowRectForBox(const RenderBoxModelObject& box)
502{
503 if (is<RenderInline>(box)) {
504 const RenderInline& inlineBox = downcast<RenderInline>(box);
505 return inlineBox.linesVisualOverflowBoundingBoxInFragment(this);
506 }
507
508 if (is<RenderBox>(box)) {
509 RefPtr<RenderOverflow> overflow;
510 ensureOverflowForBox(&downcast<RenderBox>(box), overflow, true);
511
512 ASSERT(overflow);
513 return overflow->visualOverflowRect();
514 }
515
516 ASSERT_NOT_REACHED();
517 return LayoutRect();
518}
519
520// FIXME: This doesn't work for writing modes.
521LayoutRect RenderFragmentContainer::layoutOverflowRectForBoxForPropagation(const RenderBox* box)
522{
523 // Only propagate interior layout overflow if we don't clip it.
524 LayoutRect rect = box->borderBoxRectInFragment(this);
525 rect = rectFlowPortionForBox(box, rect);
526 if (!box->hasOverflowClip())
527 rect.unite(layoutOverflowRectForBox(box));
528
529 bool hasTransform = box->hasTransform();
530 if (box->isInFlowPositioned() || hasTransform) {
531 if (hasTransform)
532 rect = box->layer()->currentTransform().mapRect(rect);
533
534 if (box->isInFlowPositioned())
535 rect.move(box->offsetForInFlowPosition());
536 }
537
538 return rect;
539}
540
541LayoutRect RenderFragmentContainer::visualOverflowRectForBoxForPropagation(const RenderBoxModelObject& box)
542{
543 LayoutRect rect = visualOverflowRectForBox(box);
544 fragmentedFlow()->flipForWritingModeLocalCoordinates(rect);
545
546 return rect;
547}
548
549CurrentRenderFragmentContainerMaintainer::CurrentRenderFragmentContainerMaintainer(RenderFragmentContainer& fragment)
550 : m_fragment(fragment)
551{
552 RenderFragmentedFlow* fragmentedFlow = fragment.fragmentedFlow();
553 // A flow thread can have only one current fragment.
554 ASSERT(!fragmentedFlow->currentFragment());
555 fragmentedFlow->setCurrentFragmentMaintainer(this);
556}
557
558CurrentRenderFragmentContainerMaintainer::~CurrentRenderFragmentContainerMaintainer()
559{
560 RenderFragmentedFlow* fragmentedFlow = m_fragment.fragmentedFlow();
561 fragmentedFlow->setCurrentFragmentMaintainer(nullptr);
562}
563
564#ifndef NDEBUG
565
566String RenderFragmentContainer::debugString() const
567{
568 return makeString("0x", hex(reinterpret_cast<uintptr_t>(this), Lowercase));
569}
570
571#endif
572
573} // namespace WebCore
574