void RenderNamedFlowFragment::updateOversetState()
{
    ASSERT(isValid());

    RenderNamedFlowThread* flowThread = namedFlowThread();
    ASSERT(flowThread && (flowThread->inOverflowLayoutPhase() || flowThread->inFinalLayoutPhase()));

    LayoutUnit flowContentBottom = flowThread->flowContentBottom();
    bool isHorizontalWritingMode = flowThread->isHorizontalWritingMode();

    LayoutUnit flowMin = flowContentBottom - (isHorizontalWritingMode ? flowThreadPortionRect().y() : flowThreadPortionRect().x());
    LayoutUnit flowMax = flowContentBottom - (isHorizontalWritingMode ? flowThreadPortionRect().maxY() : flowThreadPortionRect().maxX());

    RegionOversetState previousState = regionOversetState();
    RegionOversetState state = RegionFit;
    if (flowMin <= 0)
        state = RegionEmpty;
    if (flowMax > 0 && isLastRegion())
        state = RegionOverset;
    
    setRegionOversetState(state);

    // Determine whether the NamedFlow object should dispatch a regionOversetChange event
    if (previousState != state)
        flowThread->setDispatchRegionOversetChangeEvent(true);
}
Ejemplo n.º 2
0
LayoutRect RenderRegion::rectFlowPortionForBox(const RenderBox* box, const LayoutRect& rect) const
{
    RenderRegion* startRegion = 0;
    RenderRegion* endRegion = 0;
    m_flowThread->getRegionRangeForBox(box, startRegion, endRegion);

    LayoutRect mappedRect = m_flowThread->mapFromLocalToFlowThread(box, rect);
    if (flowThread()->isHorizontalWritingMode()) {
        if (this != startRegion)
            mappedRect.shiftYEdgeTo(std::max<LayoutUnit>(logicalTopForFlowThreadContent(), mappedRect.y()));

        if (this != endRegion)
            mappedRect.setHeight(std::max<LayoutUnit>(0, std::min<LayoutUnit>(logicalBottomForFlowThreadContent() - mappedRect.y(), mappedRect.height())));
    } else {
        if (this != startRegion)
            mappedRect.shiftXEdgeTo(std::max<LayoutUnit>(logicalTopForFlowThreadContent(), mappedRect.x()));
            
        if (this != endRegion)
            mappedRect.setWidth(std::max<LayoutUnit>(0, std::min<LayoutUnit>(logicalBottomForFlowThreadContent() - mappedRect.x(), mappedRect.width())));
    }

    if (shouldClipFlowThreadContent()) {
        LayoutRect portionRect;
        if (isRenderNamedFlowFragment())
            portionRect = toRenderNamedFlowFragment(this)->flowThreadPortionRectForClipping(this == startRegion, this == endRegion);
        else
            portionRect = flowThreadPortionRect();
        
        mappedRect.intersect(portionRect);
    }

    return mappedRect.isEmpty() ? mappedRect : m_flowThread->mapFromFlowThreadToLocal(box, mappedRect);
}
Ejemplo n.º 3
0
void RenderNamedFlowFragment::layoutBlock(bool relayoutChildren, LayoutUnit)
{
    StackStats::LayoutCheckPoint layoutCheckPoint;
    RenderRegion::layoutBlock(relayoutChildren);

    if (isValid()) {
        LayoutRect oldRegionRect(flowThreadPortionRect());
        if (!isHorizontalWritingMode())
            oldRegionRect = oldRegionRect.transposedRect();

        if (m_flowThread->inOverflowLayoutPhase() || m_flowThread->inFinalLayoutPhase()) {
            computeOverflowFromFlowThread();
            updateOversetState();
        }

        if (hasAutoLogicalHeight() && m_flowThread->inMeasureContentLayoutPhase()) {
            m_flowThread->invalidateRegions();
            clearComputedAutoHeight();
            return;
        }

        if ((oldRegionRect.width() != pageLogicalWidth() || oldRegionRect.height() != pageLogicalHeight()) && !m_flowThread->inFinalLayoutPhase())
            // This can happen even if we are in the inConstrainedLayoutPhase and it will trigger a pathological layout of the flow thread.
            m_flowThread->invalidateRegions();
    }
}
Ejemplo n.º 4
0
void RenderRegion::layoutBlock(bool relayoutChildren, LayoutUnit)
{
    StackStats::LayoutCheckPoint layoutCheckPoint;
    RenderBlock::layoutBlock(relayoutChildren);

    if (isValid()) {
        LayoutRect oldRegionRect(flowThreadPortionRect());
        if (!isHorizontalWritingMode())
            oldRegionRect = oldRegionRect.transposedRect();

        if (hasAutoLogicalHeight() && !m_flowThread->inConstrainedLayoutPhase()) {
            m_flowThread->invalidateRegions();
            clearOverrideLogicalContentHeight();
            return;
        }

        if (!isRenderRegionSet() && (oldRegionRect.width() != pageLogicalWidth() || oldRegionRect.height() != pageLogicalHeight()))
            // This can happen even if we are in the inConstrainedLayoutPhase and it will trigger a pathological layout of the flow thread.
            m_flowThread->invalidateRegions();
    }

    // FIXME: We need to find a way to set up overflow properly. Our flow thread hasn't gotten a layout
    // yet, so we can't look to it for correct information. It's possible we could wait until after the RenderFlowThread
    // gets a layout, and then try to propagate overflow information back to the region, and then mark for a second layout.
    // That second layout would then be able to use the information from the RenderFlowThread to set up overflow.
    //
    // The big problem though is that overflow needs to be region-specific. We can't simply use the RenderFlowThread's global
    // overflow values, since then we'd always think any narrow region had huge overflow (all the way to the width of the
    // RenderFlowThread itself).
    //
    // We'll need to expand RenderBoxRegionInfo to also hold left and right overflow values.
}
Ejemplo n.º 5
0
LayoutRect RenderRegion::rectFlowPortionForBox(const RenderBox* box, const LayoutRect& rect) const
{
    RenderRegion* startRegion = 0;
    RenderRegion* endRegion = 0;
    m_flowThread->getRegionRangeForBox(box, startRegion, endRegion);

    LayoutRect mappedRect = m_flowThread->mapFromLocalToFlowThread(box, rect);
    if (flowThread()->isHorizontalWritingMode()) {
        if (this != startRegion)
            mappedRect.shiftYEdgeTo(std::max<LayoutUnit>(logicalTopForFlowThreadContent(), mappedRect.y()));

        if (this != endRegion)
            mappedRect.setHeight(std::max<LayoutUnit>(0, std::min<LayoutUnit>(logicalBottomForFlowThreadContent() - mappedRect.y(), mappedRect.height())));
    } else {
        if (this != startRegion)
            mappedRect.shiftXEdgeTo(std::max<LayoutUnit>(logicalTopForFlowThreadContent(), mappedRect.x()));
            
        if (this != endRegion)
            mappedRect.setWidth(std::max<LayoutUnit>(0, std::min<LayoutUnit>(logicalBottomForFlowThreadContent() - mappedRect.x(), mappedRect.width())));
    }

    bool isLastRegionWithRegionFragmentBreak = (isLastRegion() && (style().regionFragment() == BreakRegionFragment));
    if (hasOverflowClip() || isLastRegionWithRegionFragmentBreak)
        mappedRect.intersect(flowThreadPortionRect());

    return mappedRect.isEmpty() ? mappedRect : m_flowThread->mapFromFlowThreadToLocal(box, mappedRect);
}
Ejemplo n.º 6
0
void RenderRegion::adjustRegionBoundsFromFlowThreadPortionRect(const LayoutPoint& layerOffset, LayoutRect& regionBounds)
{
    LayoutRect flippedFlowThreadPortionRect = flowThreadPortionRect();
    flowThread()->flipForWritingMode(flippedFlowThreadPortionRect);
    regionBounds.moveBy(flippedFlowThreadPortionRect.location());

    UNUSED_PARAM(layerOffset);
}
LayoutRect RenderMultiColumnSet::flowThreadPortionRectAt(unsigned index) const
{
    LayoutRect portionRect = flowThreadPortionRect();
    if (isHorizontalWritingMode())
        portionRect = LayoutRect(portionRect.x(), portionRect.y() + index * computedColumnHeight(), portionRect.width(), computedColumnHeight());
    else
        portionRect = LayoutRect(portionRect.x() + index * computedColumnHeight(), portionRect.y(), computedColumnHeight(), portionRect.height());
    return portionRect;
}
unsigned RenderMultiColumnSet::columnCount() const
{
    if (!computedColumnHeight())
        return 0;
    
    // Our region rect determines our column count. We have as many columns as needed to fit all the content.
    LayoutUnit logicalHeightInColumns = flowThread()->isHorizontalWritingMode() ? flowThreadPortionRect().height() : flowThreadPortionRect().width();
    return ceil(static_cast<float>(logicalHeightInColumns) / computedColumnHeight());
}
unsigned RenderMultiColumnSet::columnCount() const
{
    // We must always return a value of 1 or greater. Column count = 0 is a meaningless situation,
    // and will confuse and cause problems in other parts of the code.
    if (!computedColumnHeight())
        return 1;

    // Our portion rect determines our column count. We have as many columns as needed to fit all the content.
    LayoutUnit logicalHeightInColumns = flowThread()->isHorizontalWritingMode() ? flowThreadPortionRect().height() : flowThreadPortionRect().width();
    unsigned count = ceil(static_cast<float>(logicalHeightInColumns) / computedColumnHeight());
    ASSERT(count >= 1);
    return count;
}
void RenderNamedFlowFragment::invalidateRegionIfNeeded()
{
    if (!isValid())
        return;

    LayoutRect oldRegionRect(flowThreadPortionRect());
    if (!isHorizontalWritingMode())
        oldRegionRect = oldRegionRect.transposedRect();

    if ((oldRegionRect.width() != pageLogicalWidth() || oldRegionRect.height() != pageLogicalHeight()) && !m_flowThread->inFinalLayoutPhase()) {
        // This can happen even if we are in the inConstrainedLayoutPhase and it will trigger a pathological layout of the flow thread.
        m_flowThread->invalidateRegions();
    }
}
Ejemplo n.º 11
0
LayoutPoint RenderRegion::flowThreadPortionLocation() const
{
    LayoutPoint portionLocation;
    LayoutRect portionRect = flowThreadPortionRect();

    if (flowThread()->style().isFlippedBlocksWritingMode()) {
        LayoutRect flippedFlowThreadPortionRect(portionRect);
        flowThread()->flipForWritingMode(flippedFlowThreadPortionRect);
        portionLocation = flippedFlowThreadPortionRect.location();
    } else
        portionLocation = portionRect.location();

    return portionLocation;
}
Ejemplo n.º 12
0
void RenderRegion::computeOverflowFromFlowThread()
{
    ASSERT(isValid());

    LayoutRect layoutRect = overflowRectForFlowThreadPortion(flowThreadPortionRect(), isFirstRegion(), isLastRegion(), LayoutOverflow);

    layoutRect.setLocation(contentBoxRect().location() + (layoutRect.location() - m_flowThreadPortionRect.location()));

    // FIXME: Correctly adjust the layout overflow for writing modes.
    addLayoutOverflow(layoutRect);

    updateLayerTransform();
    updateScrollInfoAfterLayout();
}
Ejemplo n.º 13
0
unsigned RenderMultiColumnSet::columnIndexAtOffset(LayoutUnit offset) const
{
    LayoutRect portionRect(flowThreadPortionRect());
    LayoutUnit flowThreadLogicalTop = isHorizontalWritingMode() ? portionRect.y() : portionRect.x();
    LayoutUnit flowThreadLogicalBottom = isHorizontalWritingMode() ? portionRect.maxY() : portionRect.maxX();
    
    // Handle the offset being out of range.
    if (offset < flowThreadLogicalTop)
        return 0;
    if (offset >= flowThreadLogicalBottom)
        return columnCount() - 1;
    
    // Just divide by the column height to determine the correct column.
    return static_cast<float>(offset - flowThreadLogicalTop) / computedColumnHeight();
}
// Hit Testing
bool RenderRegion::hitTestFlowThreadContents(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action)
{
    if (!isValid() || action != HitTestForeground)
        return false;

    LayoutRect boundsRect = borderBoxRectInRegion(locationInContainer.region());
    boundsRect.moveBy(accumulatedOffset);
    if (visibleToHitTesting() && locationInContainer.intersects(boundsRect)) {
        if (m_flowThread->hitTestFlowThreadPortionInRegion(this, flowThreadPortionRect(), flowThreadPortionOverflowRect(), request, result,
            locationInContainer, LayoutPoint(accumulatedOffset.x() + borderLeft() + paddingLeft(), accumulatedOffset.y() + borderTop() + paddingTop())))
            return true;
    }

    return false;
}
Ejemplo n.º 15
0
void RenderMultiColumnSet::expandToEncompassFlowThreadContentsIfNeeded()
{
    ASSERT(multiColumnFlowThread()->lastMultiColumnSet() == this);
    LayoutRect rect(flowThreadPortionRect());

    // Get the offset within the flow thread in its block progression direction. Then get the
    // flow thread's remaining logical height including its overflow and expand our rect
    // to encompass that remaining height and overflow. The idea is that we will generate
    // additional columns and pages to hold that overflow, since people do write bad
    // content like <body style="height:0px"> in multi-column layouts.
    bool isHorizontal = flowThread()->isHorizontalWritingMode();
    LayoutUnit logicalTopOffset = isHorizontal ? rect.y() : rect.x();
    LayoutRect layoutRect = flowThread()->layoutOverflowRect();
    LayoutUnit logicalHeightWithOverflow = (isHorizontal ? layoutRect.maxY() : layoutRect.maxX()) - logicalTopOffset;
    setFlowThreadPortionRect(LayoutRect(rect.x(), rect.y(), isHorizontal ? rect.width() : logicalHeightWithOverflow, isHorizontal ? logicalHeightWithOverflow : rect.height()));
}
Ejemplo n.º 16
0
void RenderRegionSet::expandToEncompassFlowThreadContentsIfNeeded()
{
    // Whenever the last region is a set, it always expands its region rect to consume all
    // of the flow thread content. This is because it is always capable of generating an
    // infinite number of boxes in order to hold all of the remaining content.
    LayoutRect rect(flowThreadPortionRect());
    
    // Get the offset within the flow thread in its block progression direction. Then get the
    // flow thread's remaining logical height including its overflow and expand our rect
    // to encompass that remaining height and overflow. The idea is that we will generate
    // additional columns and pages to hold that overflow, since people do write bad
    // content like <body style="height:0px"> in multi-column layouts.
    bool isHorizontal = flowThread()->isHorizontalWritingMode();
    LayoutUnit logicalTopOffset = isHorizontal ? rect.y() : rect.x();
    LayoutRect layoutRect = flowThread()->layoutOverflowRect();
    LayoutUnit logicalHeightWithOverflow = (isHorizontal ? layoutRect.maxY() : layoutRect.maxX()) - logicalTopOffset;
    setFlowThreadPortionRect(LayoutRect(rect.x(), rect.y(), isHorizontal ? rect.width() : logicalHeightWithOverflow, isHorizontal ? logicalHeightWithOverflow : rect.height()));
}
Ejemplo n.º 17
0
void RenderRegion::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
{
    if (style()->visibility() != VISIBLE)
        return;

    RenderBlock::paintObject(paintInfo, paintOffset);

    // Delegate painting of content in region to RenderFlowThread.
    // RenderFlowThread is a self painting layer (being a positioned object) who is painting its children, the collected objects.
    // Since we do not want to paint the flow thread content multiple times (for each painting phase of the region object),
    // we allow the flow thread painting only for the selection and the foreground phase.
    if (!isValid() || (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection))
        return;

    setRegionObjectsRegionStyle();
    m_flowThread->paintFlowThreadPortionInRegion(paintInfo, this, flowThreadPortionRect(), flowThreadPortionOverflowRect(), LayoutPoint(paintOffset.x() + borderLeft() + paddingLeft(), paintOffset.y() + borderTop() + paddingTop()));
    restoreRegionObjectsOriginalStyle();
}
Ejemplo n.º 18
0
unsigned RenderMultiColumnSet::columnIndexAtOffset(LayoutUnit offset, ColumnIndexCalculationMode mode) const
{
    LayoutRect portionRect(flowThreadPortionRect());

    // Handle the offset being out of range.
    LayoutUnit flowThreadLogicalTop = isHorizontalWritingMode() ? portionRect.y() : portionRect.x();
    if (offset < flowThreadLogicalTop)
        return 0;
    // If we're laying out right now, we cannot constrain against some logical bottom, since it
    // isn't known yet. Otherwise, just return the last column if we're past the logical bottom.
    if (mode == ClampToExistingColumns) {
        LayoutUnit flowThreadLogicalBottom = isHorizontalWritingMode() ? portionRect.maxY() : portionRect.maxX();
        if (offset >= flowThreadLogicalBottom)
            return columnCount() - 1;
    }

    // Just divide by the column height to determine the correct column.
    return (offset - flowThreadLogicalTop).toFloat() / computedColumnHeight().toFloat();
}
LayoutRect RenderNamedFlowFragment::flowThreadPortionRectForClipping(bool isFirstRegionInRange, bool isLastRegionInRange) const
{
    // Elements flowed into a region should not be painted past the region's content box
    // if they continue to flow into another region in that direction.
    // If they do not continue into another region in that direction, they should be
    // painted all the way to the region's border box.
    // Regions with overflow:hidden will apply clip at the border box, not the content box.
    
    LayoutRect clippingRect = flowThreadPortionRect();
    RenderBlockFlow& container = fragmentContainer();
    if (container.style().hasPadding()) {
        if (isFirstRegionInRange) {
            if (flowThread()->isHorizontalWritingMode()) {
                clippingRect.move(0, -container.paddingBefore());
                clippingRect.expand(0, container.paddingBefore());
            } else {
                clippingRect.move(-container.paddingBefore(), 0);
                clippingRect.expand(container.paddingBefore(), 0);
            }
        }
        
        if (isLastRegionInRange) {
            if (flowThread()->isHorizontalWritingMode())
                clippingRect.expand(0, container.paddingAfter());
            else
                clippingRect.expand(container.paddingAfter(), 0);
        }
        
        if (flowThread()->isHorizontalWritingMode()) {
            clippingRect.move(-container.paddingStart(), 0);
            clippingRect.expand(container.paddingStart() + container.paddingEnd(), 0);
        } else {
            clippingRect.move(0, -container.paddingStart());
            clippingRect.expand(0, container.paddingStart() + container.paddingEnd());
        }
    }
    
    return clippingRect;
}
Ejemplo n.º 20
0
void RenderRegion::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
{
    if (style()->visibility() != VISIBLE)
        return;

    RenderBlock::paintObject(paintInfo, paintOffset);

    if (!isValid())
        return;

    // We do not want to paint a region's contents multiple times (for each paint phase of the region object).
    // Thus, we only paint the region's contents in certain phases.
    if (!shouldPaintRegionContentsInPhase(paintInfo.phase))
        return;

    // Delegate the painting of a region's contents to RenderFlowThread.
    // RenderFlowThread is a self painting layer because it's a positioned object.
    // RenderFlowThread paints its children, the collected objects.
    setRegionObjectsRegionStyle();
    m_flowThread->paintFlowThreadPortionInRegion(paintInfo, this, flowThreadPortionRect(), flowThreadPortionOverflowRect(), LayoutPoint(paintOffset.x() + borderLeft() + paddingLeft(), paintOffset.y() + borderTop() + paddingTop()));
    restoreRegionObjectsOriginalStyle();
}
Ejemplo n.º 21
0
// Hit Testing
bool RenderRegion::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action)
{
    if (!isValid())
        return false;

    LayoutPoint adjustedLocation = accumulatedOffset + location();

    // Check our bounds next. For this purpose always assume that we can only be hit in the
    // foreground phase (which is true for replaced elements like images).
    // FIXME: Once we support overflow, we need to intersect with that and not with the bounds rect.
    LayoutRect boundsRect = borderBoxRectInRegion(locationInContainer.region());
    boundsRect.moveBy(adjustedLocation);
    if (visibleToHitTestRequest(request) && action == HitTestForeground && locationInContainer.intersects(boundsRect)) {
        // Check the contents of the RenderFlowThread.
        if (m_flowThread->hitTestFlowThreadPortionInRegion(this, flowThreadPortionRect(), flowThreadPortionOverflowRect(), request, result, locationInContainer, LayoutPoint(adjustedLocation.x() + borderLeft() + paddingLeft(), adjustedLocation.y() + borderTop() + paddingTop())))
            return true;
        updateHitTestResult(result, locationInContainer.point() - toLayoutSize(adjustedLocation));
        if (!result.addNodeToRectBasedTestResult(generatingNode(), request, locationInContainer, boundsRect))
            return true;
    }

    return false;
}
Ejemplo n.º 22
0
LayoutUnit RenderMultiColumnSet::pageLogicalTopForOffset(LayoutUnit offset) const
{
    LayoutUnit portionLogicalTop = (isHorizontalWritingMode() ? flowThreadPortionRect().y() : flowThreadPortionRect().x());
    unsigned columnIndex = (offset - portionLogicalTop) / computedColumnHeight();
    return portionLogicalTop + columnIndex * computedColumnHeight();
}
Ejemplo n.º 23
0
LayoutRect RenderRegion::flowThreadPortionOverflowRect()
{
    return overflowRectForFlowThreadPortion(flowThreadPortionRect(), isFirstRegion(), isLastRegion(), VisualOverflow);
}
LayoutRect LayoutMultiColumnSet::flowThreadPortionOverflowRect() const
{
    return overflowRectForFlowThreadPortion(flowThreadPortionRect(), !previousSiblingMultiColumnSet(), !nextSiblingMultiColumnSet());
}
Ejemplo n.º 25
0
LayoutRect RenderRegion::flowThreadPortionOverflowRect() const
{
    return overflowRectForFlowThreadPortion(flowThreadPortionRect(), isFirstRegion(), isLastRegion());
}
Ejemplo n.º 26
0
void RenderRegion::repaintFlowThreadContent(const LayoutRect& repaintRect) const
{
    repaintFlowThreadContentRectangle(repaintRect, flowThreadPortionRect(), flowThreadPortionOverflowRect(), contentBoxRect().location());
}
Ejemplo n.º 27
0
LayoutUnit RenderRegion::pageLogicalTopForOffset(LayoutUnit /* offset */) const
{
    return flowThread()->isHorizontalWritingMode() ? flowThreadPortionRect().y() : flowThreadPortionRect().x();
}
Ejemplo n.º 28
0
void RenderRegion::repaintFlowThreadContent(const LayoutRect& repaintRect, bool immediate)
{
    repaintFlowThreadContentRectangle(repaintRect, immediate, flowThreadPortionRect(), contentBoxRect().location());
}