600 lines
23 KiB
C++
600 lines
23 KiB
C++
/*
|
|
* Copyright (C) 2011 Adobe Systems Incorporated. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above
|
|
* copyright notice, this list of conditions and the following
|
|
* disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above
|
|
* copyright notice, this list of conditions and the following
|
|
* disclaimer in the documentation and/or other materials
|
|
* provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY
|
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
|
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
|
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
|
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include "RenderFragmentContainer.h"
|
|
|
|
#include "GraphicsContext.h"
|
|
#include "HitTestResult.h"
|
|
#include "IntRect.h"
|
|
#include "LayoutRepainter.h"
|
|
#include "Range.h"
|
|
#include "RenderBoxFragmentInfo.h"
|
|
#include "RenderFragmentedFlow.h"
|
|
#include "RenderInline.h"
|
|
#include "RenderIterator.h"
|
|
#include "RenderLayer.h"
|
|
#include "RenderView.h"
|
|
#include "StyleResolver.h"
|
|
#include <wtf/HexNumber.h>
|
|
#include <wtf/IsoMallocInlines.h>
|
|
|
|
namespace WebCore {
|
|
|
|
WTF_MAKE_ISO_ALLOCATED_IMPL(RenderFragmentContainer);
|
|
|
|
RenderFragmentContainer::RenderFragmentContainer(Element& element, RenderStyle&& style, RenderFragmentedFlow* fragmentedFlow)
|
|
: RenderBlockFlow(element, WTFMove(style))
|
|
, m_fragmentedFlow(fragmentedFlow)
|
|
{
|
|
}
|
|
|
|
RenderFragmentContainer::RenderFragmentContainer(Document& document, RenderStyle&& style, RenderFragmentedFlow* fragmentedFlow)
|
|
: RenderBlockFlow(document, WTFMove(style))
|
|
, m_fragmentedFlow(fragmentedFlow)
|
|
{
|
|
}
|
|
|
|
LayoutPoint RenderFragmentContainer::mapFragmentPointIntoFragmentedFlowCoordinates(const LayoutPoint& point)
|
|
{
|
|
// Assuming the point is relative to the fragment block, 3 cases will be considered:
|
|
// a) top margin, padding or border.
|
|
// b) bottom margin, padding or border.
|
|
// c) non-content fragment area.
|
|
|
|
LayoutUnit pointLogicalTop(isHorizontalWritingMode() ? point.y() : point.x());
|
|
LayoutUnit pointLogicalLeft(isHorizontalWritingMode() ? point.x() : point.y());
|
|
LayoutUnit fragmentedFlowLogicalTop(isHorizontalWritingMode() ? m_fragmentedFlowPortionRect.y() : m_fragmentedFlowPortionRect.x());
|
|
LayoutUnit fragmentedFlowLogicalLeft(isHorizontalWritingMode() ? m_fragmentedFlowPortionRect.x() : m_fragmentedFlowPortionRect.y());
|
|
LayoutUnit fragmentedFlowPortionTopBound(isHorizontalWritingMode() ? m_fragmentedFlowPortionRect.height() : m_fragmentedFlowPortionRect.width());
|
|
LayoutUnit fragmentedFlowPortionLeftBound(isHorizontalWritingMode() ? m_fragmentedFlowPortionRect.width() : m_fragmentedFlowPortionRect.height());
|
|
LayoutUnit fragmentedFlowPortionTopMax(isHorizontalWritingMode() ? m_fragmentedFlowPortionRect.maxY() : m_fragmentedFlowPortionRect.maxX());
|
|
LayoutUnit fragmentedFlowPortionLeftMax(isHorizontalWritingMode() ? m_fragmentedFlowPortionRect.maxX() : m_fragmentedFlowPortionRect.maxY());
|
|
LayoutUnit effectiveFixedPointDenominator;
|
|
effectiveFixedPointDenominator.setRawValue(1);
|
|
|
|
if (pointLogicalTop < 0) {
|
|
LayoutPoint pointInThread(0_lu, fragmentedFlowLogicalTop);
|
|
return isHorizontalWritingMode() ? pointInThread : pointInThread.transposedPoint();
|
|
}
|
|
|
|
if (pointLogicalTop >= fragmentedFlowPortionTopBound) {
|
|
LayoutPoint pointInThread(fragmentedFlowPortionLeftBound, fragmentedFlowPortionTopMax - effectiveFixedPointDenominator);
|
|
return isHorizontalWritingMode() ? pointInThread : pointInThread.transposedPoint();
|
|
}
|
|
|
|
if (pointLogicalLeft < 0) {
|
|
LayoutPoint pointInThread(fragmentedFlowLogicalLeft, pointLogicalTop + fragmentedFlowLogicalTop);
|
|
return isHorizontalWritingMode() ? pointInThread : pointInThread.transposedPoint();
|
|
}
|
|
if (pointLogicalLeft >= fragmentedFlowPortionLeftBound) {
|
|
LayoutPoint pointInThread(fragmentedFlowPortionLeftMax - effectiveFixedPointDenominator, pointLogicalTop + fragmentedFlowLogicalTop);
|
|
return isHorizontalWritingMode() ? pointInThread : pointInThread.transposedPoint();
|
|
}
|
|
LayoutPoint pointInThread(pointLogicalLeft + fragmentedFlowLogicalLeft, pointLogicalTop + fragmentedFlowLogicalTop);
|
|
return isHorizontalWritingMode() ? pointInThread : pointInThread.transposedPoint();
|
|
}
|
|
|
|
VisiblePosition RenderFragmentContainer::positionForPoint(const LayoutPoint& point, const RenderFragmentContainer* fragment)
|
|
{
|
|
if (!isValid() || !m_fragmentedFlow->firstChild()) // checking for empty fragment blocks.
|
|
return RenderBlock::positionForPoint(point, fragment);
|
|
|
|
return m_fragmentedFlow->positionForPoint(mapFragmentPointIntoFragmentedFlowCoordinates(point), this);
|
|
}
|
|
|
|
LayoutUnit RenderFragmentContainer::pageLogicalWidth() const
|
|
{
|
|
ASSERT(isValid());
|
|
return m_fragmentedFlow->isHorizontalWritingMode() ? contentWidth() : contentHeight();
|
|
}
|
|
|
|
LayoutUnit RenderFragmentContainer::pageLogicalHeight() const
|
|
{
|
|
ASSERT(isValid());
|
|
return m_fragmentedFlow->isHorizontalWritingMode() ? contentHeight() : contentWidth();
|
|
}
|
|
|
|
LayoutUnit RenderFragmentContainer::logicalHeightOfAllFragmentedFlowContent() const
|
|
{
|
|
return pageLogicalHeight();
|
|
}
|
|
|
|
LayoutRect RenderFragmentContainer::fragmentedFlowPortionOverflowRect()
|
|
{
|
|
return overflowRectForFragmentedFlowPortion(fragmentedFlowPortionRect(), isFirstFragment(), isLastFragment(), VisualOverflow);
|
|
}
|
|
|
|
LayoutPoint RenderFragmentContainer::fragmentedFlowPortionLocation() const
|
|
{
|
|
LayoutPoint portionLocation;
|
|
LayoutRect portionRect = fragmentedFlowPortionRect();
|
|
|
|
if (fragmentedFlow()->style().isFlippedBlocksWritingMode()) {
|
|
LayoutRect flippedFragmentedFlowPortionRect(portionRect);
|
|
fragmentedFlow()->flipForWritingMode(flippedFragmentedFlowPortionRect);
|
|
portionLocation = flippedFragmentedFlowPortionRect.location();
|
|
} else
|
|
portionLocation = portionRect.location();
|
|
|
|
return portionLocation;
|
|
}
|
|
|
|
LayoutRect RenderFragmentContainer::overflowRectForFragmentedFlowPortion(const LayoutRect& fragmentedFlowPortionRect, bool isFirstPortion, bool isLastPortion, OverflowType overflowType)
|
|
{
|
|
ASSERT(isValid());
|
|
if (shouldClipFragmentedFlowContent())
|
|
return fragmentedFlowPortionRect;
|
|
|
|
LayoutRect fragmentedFlowOverflow = overflowType == VisualOverflow ? visualOverflowRectForBox(*m_fragmentedFlow) : layoutOverflowRectForBox(m_fragmentedFlow);
|
|
LayoutRect clipRect;
|
|
if (m_fragmentedFlow->isHorizontalWritingMode()) {
|
|
LayoutUnit minY = isFirstPortion ? fragmentedFlowOverflow.y() : fragmentedFlowPortionRect.y();
|
|
LayoutUnit maxY = isLastPortion ? std::max(fragmentedFlowPortionRect.maxY(), fragmentedFlowOverflow.maxY()) : fragmentedFlowPortionRect.maxY();
|
|
bool clipX = style().overflowX() != Overflow::Visible;
|
|
LayoutUnit minX = clipX ? fragmentedFlowPortionRect.x() : std::min(fragmentedFlowPortionRect.x(), fragmentedFlowOverflow.x());
|
|
LayoutUnit maxX = clipX ? fragmentedFlowPortionRect.maxX() : std::max(fragmentedFlowPortionRect.maxX(), fragmentedFlowOverflow.maxX());
|
|
clipRect = LayoutRect(minX, minY, maxX - minX, maxY - minY);
|
|
} else {
|
|
LayoutUnit minX = isFirstPortion ? fragmentedFlowOverflow.x() : fragmentedFlowPortionRect.x();
|
|
LayoutUnit maxX = isLastPortion ? std::max(fragmentedFlowPortionRect.maxX(), fragmentedFlowOverflow.maxX()) : fragmentedFlowPortionRect.maxX();
|
|
bool clipY = style().overflowY() != Overflow::Visible;
|
|
LayoutUnit minY = clipY ? fragmentedFlowPortionRect.y() : std::min(fragmentedFlowPortionRect.y(), fragmentedFlowOverflow.y());
|
|
LayoutUnit maxY = clipY ? fragmentedFlowPortionRect.maxY() : std::max(fragmentedFlowPortionRect.y(), fragmentedFlowOverflow.maxY());
|
|
clipRect = LayoutRect(minX, minY, maxX - minX, maxY - minY);
|
|
}
|
|
return clipRect;
|
|
}
|
|
|
|
LayoutUnit RenderFragmentContainer::pageLogicalTopForOffset(LayoutUnit /* offset */) const
|
|
{
|
|
return fragmentedFlow()->isHorizontalWritingMode() ? fragmentedFlowPortionRect().y() : fragmentedFlowPortionRect().x();
|
|
}
|
|
|
|
bool RenderFragmentContainer::isFirstFragment() const
|
|
{
|
|
ASSERT(isValid());
|
|
|
|
return m_fragmentedFlow->firstFragment() == this;
|
|
}
|
|
|
|
bool RenderFragmentContainer::isLastFragment() const
|
|
{
|
|
ASSERT(isValid());
|
|
|
|
return m_fragmentedFlow->lastFragment() == this;
|
|
}
|
|
|
|
bool RenderFragmentContainer::shouldClipFragmentedFlowContent() const
|
|
{
|
|
return hasNonVisibleOverflow();
|
|
}
|
|
|
|
void RenderFragmentContainer::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
|
|
{
|
|
RenderBlockFlow::styleDidChange(diff, oldStyle);
|
|
|
|
if (!isValid())
|
|
return;
|
|
|
|
if (oldStyle && oldStyle->writingMode() != style().writingMode())
|
|
m_fragmentedFlow->fragmentChangedWritingMode(this);
|
|
}
|
|
|
|
void RenderFragmentContainer::computeOverflowFromFragmentedFlow()
|
|
{
|
|
ASSERT(isValid());
|
|
|
|
LayoutRect layoutRect = layoutOverflowRectForBox(m_fragmentedFlow);
|
|
layoutRect.setLocation(contentBoxRect().location() + (layoutRect.location() - m_fragmentedFlowPortionRect.location()));
|
|
|
|
// FIXME: Correctly adjust the layout overflow for writing modes.
|
|
addLayoutOverflow(layoutRect);
|
|
RenderFragmentedFlow* enclosingRenderFragmentedFlow = enclosingFragmentedFlow();
|
|
if (enclosingRenderFragmentedFlow)
|
|
enclosingRenderFragmentedFlow->addFragmentsLayoutOverflow(this, layoutRect);
|
|
|
|
updateLayerTransform();
|
|
updateScrollInfoAfterLayout();
|
|
}
|
|
|
|
void RenderFragmentContainer::repaintFragmentedFlowContent(const LayoutRect& repaintRect)
|
|
{
|
|
repaintFragmentedFlowContentRectangle(repaintRect, fragmentedFlowPortionRect(), contentBoxRect().location());
|
|
}
|
|
|
|
void RenderFragmentContainer::repaintFragmentedFlowContentRectangle(const LayoutRect& repaintRect, const LayoutRect& fragmentedFlowPortionRect, const LayoutPoint& fragmentLocation, const LayoutRect* fragmentedFlowPortionClipRect)
|
|
{
|
|
ASSERT(isValid());
|
|
|
|
// We only have to issue a repaint in this fragment if the fragment rect intersects the repaint rect.
|
|
LayoutRect clippedRect(repaintRect);
|
|
|
|
if (fragmentedFlowPortionClipRect) {
|
|
LayoutRect flippedFragmentedFlowPortionClipRect(*fragmentedFlowPortionClipRect);
|
|
fragmentedFlow()->flipForWritingMode(flippedFragmentedFlowPortionClipRect);
|
|
clippedRect.intersect(flippedFragmentedFlowPortionClipRect);
|
|
}
|
|
|
|
if (clippedRect.isEmpty())
|
|
return;
|
|
|
|
LayoutRect flippedFragmentedFlowPortionRect(fragmentedFlowPortionRect);
|
|
fragmentedFlow()->flipForWritingMode(flippedFragmentedFlowPortionRect); // Put the fragment rects into physical coordinates.
|
|
|
|
// Put the fragment rect into the fragment's physical coordinate space.
|
|
clippedRect.setLocation(fragmentLocation + (clippedRect.location() - flippedFragmentedFlowPortionRect.location()));
|
|
|
|
// Now switch to the fragment's writing mode coordinate space and let it repaint itself.
|
|
flipForWritingMode(clippedRect);
|
|
|
|
// Issue the repaint.
|
|
repaintRectangle(clippedRect);
|
|
}
|
|
|
|
LayoutRect RenderFragmentContainer::fragmentedFlowContentRectangle(const LayoutRect& rect, const LayoutRect& fragmentedFlowPortionRect, const LayoutPoint& fragmentLocation, const LayoutRect* fragmentedFlowPortionClipRect)
|
|
{
|
|
auto clippedRect = rect;
|
|
|
|
if (fragmentedFlowPortionClipRect) {
|
|
LayoutRect flippedFragmentedFlowPortionClipRect(*fragmentedFlowPortionClipRect);
|
|
fragmentedFlow()->flipForWritingMode(flippedFragmentedFlowPortionClipRect);
|
|
clippedRect.edgeInclusiveIntersect(flippedFragmentedFlowPortionClipRect); // edgeInclusiveIntersect to avoid rects with zero height or width becoming zero-sized.
|
|
}
|
|
|
|
LayoutRect flippedFragmentedFlowPortionRect(fragmentedFlowPortionRect);
|
|
fragmentedFlow()->flipForWritingMode(flippedFragmentedFlowPortionRect);
|
|
|
|
// Put the fragment rect into the fragment's physical coordinate space.
|
|
clippedRect.setLocation(fragmentLocation + (clippedRect.location() - flippedFragmentedFlowPortionRect.location()));
|
|
|
|
// Now switch to the fragment's writing mode coordinate space and let it repaint itself.
|
|
flipForWritingMode(clippedRect);
|
|
|
|
return clippedRect;
|
|
}
|
|
|
|
Vector<LayoutRect> RenderFragmentContainer::fragmentRectsForFlowContentRect(const LayoutRect& contentRect)
|
|
{
|
|
auto portionRect = fragmentedFlowPortionRect();
|
|
auto fragmentLocation = contentBoxRect().location();
|
|
|
|
auto fragmentRect = contentRect;
|
|
|
|
auto flippedFragmentedFlowPortionRect = portionRect;
|
|
fragmentedFlow()->flipForWritingMode(flippedFragmentedFlowPortionRect);
|
|
fragmentRect.setLocation(fragmentLocation + (fragmentRect.location() - flippedFragmentedFlowPortionRect.location()));
|
|
|
|
flipForWritingMode(fragmentRect);
|
|
|
|
return { fragmentRect };
|
|
}
|
|
|
|
void RenderFragmentContainer::installFragmentedFlow()
|
|
{
|
|
ASSERT_NOT_REACHED();
|
|
}
|
|
|
|
void RenderFragmentContainer::attachFragment()
|
|
{
|
|
if (renderTreeBeingDestroyed())
|
|
return;
|
|
|
|
// A fragment starts off invalid.
|
|
setIsValid(false);
|
|
|
|
// Initialize the flow thread reference and create the flow thread object if needed.
|
|
// The flow thread lifetime is influenced by the number of fragments attached to it,
|
|
// and we are attaching the fragment to the flow thread.
|
|
installFragmentedFlow();
|
|
|
|
if (!m_fragmentedFlow)
|
|
return;
|
|
|
|
// Only after adding the fragment to the thread, the fragment is marked to be valid.
|
|
m_fragmentedFlow->addFragmentToThread(this);
|
|
}
|
|
|
|
void RenderFragmentContainer::detachFragment()
|
|
{
|
|
if (m_fragmentedFlow)
|
|
m_fragmentedFlow->removeFragmentFromThread(this);
|
|
m_fragmentedFlow = nullptr;
|
|
}
|
|
|
|
RenderBoxFragmentInfo* RenderFragmentContainer::renderBoxFragmentInfo(const RenderBox* box) const
|
|
{
|
|
ASSERT(isValid());
|
|
return m_renderBoxFragmentInfo.get(box);
|
|
}
|
|
|
|
RenderBoxFragmentInfo* RenderFragmentContainer::setRenderBoxFragmentInfo(const RenderBox* box, LayoutUnit logicalLeftInset, LayoutUnit logicalRightInset,
|
|
bool containingBlockChainIsInset)
|
|
{
|
|
ASSERT(isValid());
|
|
|
|
std::unique_ptr<RenderBoxFragmentInfo>& boxInfo = m_renderBoxFragmentInfo.add(box, makeUnique<RenderBoxFragmentInfo>(logicalLeftInset, logicalRightInset, containingBlockChainIsInset)).iterator->value;
|
|
return boxInfo.get();
|
|
}
|
|
|
|
std::unique_ptr<RenderBoxFragmentInfo> RenderFragmentContainer::takeRenderBoxFragmentInfo(const RenderBox* box)
|
|
{
|
|
return m_renderBoxFragmentInfo.take(box);
|
|
}
|
|
|
|
void RenderFragmentContainer::removeRenderBoxFragmentInfo(const RenderBox& box)
|
|
{
|
|
m_renderBoxFragmentInfo.remove(&box);
|
|
}
|
|
|
|
void RenderFragmentContainer::deleteAllRenderBoxFragmentInfo()
|
|
{
|
|
m_renderBoxFragmentInfo.clear();
|
|
}
|
|
|
|
LayoutUnit RenderFragmentContainer::logicalTopOfFragmentedFlowContentRect(const LayoutRect& rect) const
|
|
{
|
|
ASSERT(isValid());
|
|
return fragmentedFlow()->isHorizontalWritingMode() ? rect.y() : rect.x();
|
|
}
|
|
|
|
LayoutUnit RenderFragmentContainer::logicalBottomOfFragmentedFlowContentRect(const LayoutRect& rect) const
|
|
{
|
|
ASSERT(isValid());
|
|
return fragmentedFlow()->isHorizontalWritingMode() ? rect.maxY() : rect.maxX();
|
|
}
|
|
|
|
void RenderFragmentContainer::insertedIntoTree(IsInternalMove isInternalMove)
|
|
{
|
|
attachFragment();
|
|
if (isValid())
|
|
RenderBlockFlow::insertedIntoTree(isInternalMove);
|
|
}
|
|
|
|
void RenderFragmentContainer::willBeRemovedFromTree(IsInternalMove isInternalMove)
|
|
{
|
|
RenderBlockFlow::willBeRemovedFromTree(isInternalMove);
|
|
|
|
detachFragment();
|
|
}
|
|
|
|
void RenderFragmentContainer::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
|
|
{
|
|
if (!isValid()) {
|
|
RenderBlockFlow::computeIntrinsicLogicalWidths(minLogicalWidth, maxLogicalWidth);
|
|
return;
|
|
}
|
|
|
|
minLogicalWidth = m_fragmentedFlow->minPreferredLogicalWidth();
|
|
maxLogicalWidth = m_fragmentedFlow->maxPreferredLogicalWidth();
|
|
}
|
|
|
|
void RenderFragmentContainer::computePreferredLogicalWidths()
|
|
{
|
|
ASSERT(preferredLogicalWidthsDirty());
|
|
|
|
if (!isValid()) {
|
|
RenderBlockFlow::computePreferredLogicalWidths();
|
|
return;
|
|
}
|
|
|
|
// FIXME: Currently, the code handles only the <length> case for min-width/max-width.
|
|
// It should also support other values, like percentage, calc or viewport relative.
|
|
m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = 0;
|
|
|
|
const RenderStyle& styleToUse = style();
|
|
if (styleToUse.logicalWidth().isFixed() && styleToUse.logicalWidth().value() > 0)
|
|
m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = adjustContentBoxLogicalWidthForBoxSizing(styleToUse.logicalWidth());
|
|
else
|
|
computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
|
|
|
|
RenderBox::computePreferredLogicalWidths(style().logicalMinWidth(), style().logicalMaxWidth(), borderAndPaddingLogicalWidth());
|
|
|
|
setPreferredLogicalWidthsDirty(false);
|
|
}
|
|
|
|
// FIXME: Unused.
|
|
void RenderFragmentContainer::adjustFragmentBoundsFromFragmentedFlowPortionRect(LayoutRect& fragmentBounds) const
|
|
{
|
|
LayoutRect flippedFragmentedFlowPortionRect = fragmentedFlowPortionRect();
|
|
fragmentedFlow()->flipForWritingMode(flippedFragmentedFlowPortionRect);
|
|
fragmentBounds.moveBy(flippedFragmentedFlowPortionRect.location());
|
|
}
|
|
|
|
void RenderFragmentContainer::ensureOverflowForBox(const RenderBox* box, RefPtr<RenderOverflow>& overflow, bool forceCreation)
|
|
{
|
|
ASSERT(m_fragmentedFlow->renderFragmentContainerList().contains(this));
|
|
ASSERT(isValid());
|
|
|
|
RenderBoxFragmentInfo* boxInfo = renderBoxFragmentInfo(box);
|
|
if (!boxInfo && !forceCreation)
|
|
return;
|
|
|
|
if (boxInfo && boxInfo->overflow()) {
|
|
overflow = boxInfo->overflow();
|
|
return;
|
|
}
|
|
|
|
LayoutRect borderBox = box->borderBoxRectInFragment(this);
|
|
LayoutRect clientBox;
|
|
ASSERT(m_fragmentedFlow->objectShouldFragmentInFlowFragment(box, this));
|
|
|
|
if (!borderBox.isEmpty()) {
|
|
borderBox = rectFlowPortionForBox(box, borderBox);
|
|
|
|
clientBox = box->clientBoxRectInFragment(this);
|
|
clientBox = rectFlowPortionForBox(box, clientBox);
|
|
|
|
m_fragmentedFlow->flipForWritingModeLocalCoordinates(borderBox);
|
|
m_fragmentedFlow->flipForWritingModeLocalCoordinates(clientBox);
|
|
}
|
|
|
|
if (boxInfo) {
|
|
boxInfo->createOverflow(clientBox, borderBox);
|
|
overflow = boxInfo->overflow();
|
|
} else
|
|
overflow = adoptRef(new RenderOverflow(clientBox, borderBox));
|
|
}
|
|
|
|
LayoutRect RenderFragmentContainer::rectFlowPortionForBox(const RenderBox* box, const LayoutRect& rect) const
|
|
{
|
|
LayoutRect mappedRect = m_fragmentedFlow->mapFromLocalToFragmentedFlow(box, rect);
|
|
|
|
RenderFragmentContainer* startFragment = nullptr;
|
|
RenderFragmentContainer* endFragment = nullptr;
|
|
if (m_fragmentedFlow->getFragmentRangeForBox(box, startFragment, endFragment)) {
|
|
if (fragmentedFlow()->isHorizontalWritingMode()) {
|
|
if (this != startFragment)
|
|
mappedRect.shiftYEdgeTo(std::max<LayoutUnit>(logicalTopForFragmentedFlowContent(), mappedRect.y()));
|
|
if (this != endFragment)
|
|
mappedRect.setHeight(std::max<LayoutUnit>(0, std::min<LayoutUnit>(logicalBottomForFragmentedFlowContent() - mappedRect.y(), mappedRect.height())));
|
|
} else {
|
|
if (this != startFragment)
|
|
mappedRect.shiftXEdgeTo(std::max<LayoutUnit>(logicalTopForFragmentedFlowContent(), mappedRect.x()));
|
|
if (this != endFragment)
|
|
mappedRect.setWidth(std::max<LayoutUnit>(0, std::min<LayoutUnit>(logicalBottomForFragmentedFlowContent() - mappedRect.x(), mappedRect.width())));
|
|
}
|
|
}
|
|
|
|
return m_fragmentedFlow->mapFromFragmentedFlowToLocal(box, mappedRect);
|
|
}
|
|
|
|
void RenderFragmentContainer::addLayoutOverflowForBox(const RenderBox* box, const LayoutRect& rect)
|
|
{
|
|
if (rect.isEmpty())
|
|
return;
|
|
|
|
RefPtr<RenderOverflow> fragmentOverflow;
|
|
ensureOverflowForBox(box, fragmentOverflow, false);
|
|
|
|
if (!fragmentOverflow)
|
|
return;
|
|
|
|
fragmentOverflow->addLayoutOverflow(rect);
|
|
}
|
|
|
|
void RenderFragmentContainer::addVisualOverflowForBox(const RenderBox* box, const LayoutRect& rect)
|
|
{
|
|
if (rect.isEmpty())
|
|
return;
|
|
|
|
RefPtr<RenderOverflow> fragmentOverflow;
|
|
ensureOverflowForBox(box, fragmentOverflow, false);
|
|
|
|
if (!fragmentOverflow)
|
|
return;
|
|
|
|
LayoutRect flippedRect = rect;
|
|
fragmentedFlow()->flipForWritingModeLocalCoordinates(flippedRect);
|
|
fragmentOverflow->addVisualOverflow(flippedRect);
|
|
}
|
|
|
|
LayoutRect RenderFragmentContainer::layoutOverflowRectForBox(const RenderBox* box)
|
|
{
|
|
RefPtr<RenderOverflow> overflow;
|
|
ensureOverflowForBox(box, overflow, true);
|
|
|
|
ASSERT(overflow);
|
|
return overflow->layoutOverflowRect();
|
|
}
|
|
|
|
LayoutRect RenderFragmentContainer::visualOverflowRectForBox(const RenderBoxModelObject& box)
|
|
{
|
|
if (is<RenderInline>(box)) {
|
|
const RenderInline& inlineBox = downcast<RenderInline>(box);
|
|
return inlineBox.linesVisualOverflowBoundingBoxInFragment(this);
|
|
}
|
|
|
|
if (is<RenderBox>(box)) {
|
|
RefPtr<RenderOverflow> overflow;
|
|
ensureOverflowForBox(&downcast<RenderBox>(box), overflow, true);
|
|
|
|
ASSERT(overflow);
|
|
return overflow->visualOverflowRect();
|
|
}
|
|
|
|
ASSERT_NOT_REACHED();
|
|
return LayoutRect();
|
|
}
|
|
|
|
// FIXME: This doesn't work for writing modes.
|
|
LayoutRect RenderFragmentContainer::layoutOverflowRectForBoxForPropagation(const RenderBox* box)
|
|
{
|
|
// Only propagate interior layout overflow if we don't clip it.
|
|
LayoutRect rect = box->borderBoxRectInFragment(this);
|
|
rect = rectFlowPortionForBox(box, rect);
|
|
if (!box->hasNonVisibleOverflow())
|
|
rect.unite(layoutOverflowRectForBox(box));
|
|
|
|
bool hasTransform = box->hasTransform();
|
|
if (box->isInFlowPositioned() || hasTransform) {
|
|
if (hasTransform)
|
|
rect = box->layer()->currentTransform().mapRect(rect);
|
|
|
|
if (box->isInFlowPositioned())
|
|
rect.move(box->offsetForInFlowPosition());
|
|
}
|
|
|
|
return rect;
|
|
}
|
|
|
|
LayoutRect RenderFragmentContainer::visualOverflowRectForBoxForPropagation(const RenderBoxModelObject& box)
|
|
{
|
|
LayoutRect rect = visualOverflowRectForBox(box);
|
|
fragmentedFlow()->flipForWritingModeLocalCoordinates(rect);
|
|
|
|
return rect;
|
|
}
|
|
|
|
CurrentRenderFragmentContainerMaintainer::CurrentRenderFragmentContainerMaintainer(RenderFragmentContainer& fragment)
|
|
: m_fragment(fragment)
|
|
{
|
|
RenderFragmentedFlow* fragmentedFlow = fragment.fragmentedFlow();
|
|
// A flow thread can have only one current fragment.
|
|
ASSERT(!fragmentedFlow->currentFragment());
|
|
fragmentedFlow->setCurrentFragmentMaintainer(this);
|
|
}
|
|
|
|
CurrentRenderFragmentContainerMaintainer::~CurrentRenderFragmentContainerMaintainer()
|
|
{
|
|
RenderFragmentedFlow* fragmentedFlow = m_fragment.fragmentedFlow();
|
|
fragmentedFlow->setCurrentFragmentMaintainer(nullptr);
|
|
}
|
|
|
|
#ifndef NDEBUG
|
|
|
|
TextStream& operator<<(TextStream& stream, const RenderFragmentContainer& container)
|
|
{
|
|
return stream << &container;
|
|
}
|
|
|
|
#endif
|
|
|
|
} // namespace WebCore
|