LayoutUnit RenderFlowThread::regionLogicalHeightForLine(LayoutUnit position) const { RenderRegion* region = renderRegionForLine(position); if (!region) return 0; return isHorizontalWritingMode() ? region->regionRect().height() : region->regionRect().width(); }
LayoutUnit RenderFlowThread::contentLogicalLeftOfFirstRegion() const { if (!hasValidRegionInfo()) return 0; for (RenderRegionList::const_iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) { RenderRegion* region = *iter; if (!region->isValid()) continue; return isHorizontalWritingMode() ? region->regionRect().x() : region->regionRect().y(); } ASSERT_NOT_REACHED(); return 0; }
LayoutUnit RenderFlowThread::regionRemainingLogicalHeightForLine(LayoutUnit position, PageBoundaryRule pageBoundaryRule) const { RenderRegion* region = renderRegionForLine(position); if (!region) return 0; LayoutUnit regionLogicalBottom = isHorizontalWritingMode() ? region->regionRect().maxY() : region->regionRect().maxX(); LayoutUnit remainingHeight = regionLogicalBottom - position; if (pageBoundaryRule == IncludePageBoundary) { // If IncludePageBoundary is set, the line exactly on the top edge of a // region will act as being part of the previous region. LayoutUnit regionHeight = isHorizontalWritingMode() ? region->regionRect().height() : region->regionRect().width(); remainingHeight = layoutMod(remainingHeight, regionHeight); } return remainingHeight; }
RenderRegion* RenderFlowThread::renderRegionForLine(LayoutUnit position, bool extendLastRegion) const { ASSERT(!m_regionsInvalidated); // If no region matches the position and extendLastRegion is true, it will return // the last valid region. It is similar to auto extending the size of the last region. RenderRegion* lastValidRegion = 0; // FIXME: The regions are always in order, optimize this search. bool useHorizontalWritingMode = isHorizontalWritingMode(); for (RenderRegionList::const_iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) { RenderRegion* region = *iter; if (!region->isValid()) continue; if (position <= 0) return region; LayoutRect regionRect = region->regionRect(); if ((useHorizontalWritingMode && position < regionRect.maxY()) || (!useHorizontalWritingMode && position < regionRect.maxX())) return region; if (extendLastRegion) lastValidRegion = region; } return lastValidRegion; }
void RenderFlowThread::repaintRectangleInRegions(const LayoutRect& repaintRect, bool immediate) { if (!shouldRepaint(repaintRect) || !hasValidRegionInfo()) return; for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) { RenderRegion* region = *iter; if (!region->isValid()) continue; // We only have to issue a repaint in this region if the region rect intersects the repaint rect. LayoutRect flippedRegionRect(region->regionRect()); LayoutRect flippedRegionOverflowRect(region->regionOverflowRect()); flipForWritingMode(flippedRegionRect); // Put the region rects into physical coordinates. flipForWritingMode(flippedRegionOverflowRect); LayoutRect clippedRect(repaintRect); clippedRect.intersect(flippedRegionOverflowRect); if (clippedRect.isEmpty()) continue; // Put the region rect into the region's physical coordinate space. clippedRect.setLocation(region->contentBoxRect().location() + (clippedRect.location() - flippedRegionRect.location())); // Now switch to the region's writing mode coordinate space and let it repaint itself. region->flipForWritingMode(clippedRect); LayoutStateDisabler layoutStateDisabler(view()); // We can't use layout state to repaint, since the region is somewhere else. // Can't use currentFlowThread as it possible to have imbricated flow threads and the wrong one could be used, // so, we let each region figure out the proper enclosing flow thread CurrentRenderFlowThreadDisabler disabler(view()); region->repaintRectangle(clippedRect, immediate); } }
void RenderFlowThread::computeOverflowStateForRegions(LayoutUnit oldClientAfterEdge) { LayoutUnit height = oldClientAfterEdge; // FIXME: the visual overflow of middle region (if it is the last one to contain any content in a render flow thread) // might not be taken into account because the render flow thread height is greater that that regions height + its visual overflow // because of how computeLogicalHeight is implemented for RenderFlowThread (as a sum of all regions height). // This means that the middle region will be marked as fit (even if it has visual overflow flowing into the next region) if (hasRenderOverflow()) height = isHorizontalWritingMode() ? visualOverflowRect().maxY() : visualOverflowRect().maxX(); for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) { RenderRegion* region = *iter; if (!region->isValid()) { region->setRegionState(RenderRegion::RegionUndefined); continue; } LayoutUnit flowMin = height - (isHorizontalWritingMode() ? region->regionRect().y() : region->regionRect().x()); LayoutUnit flowMax = height - (isHorizontalWritingMode() ? region->regionRect().maxY() : region->regionRect().maxX()); RenderRegion::RegionState previousState = region->regionState(); RenderRegion::RegionState state = RenderRegion::RegionFit; if (flowMin <= 0) state = RenderRegion::RegionEmpty; if (flowMax > 0) state = RenderRegion::RegionOverflow; region->setRegionState(state); // determine whether this region should dispatch a regionLayoutUpdate event // FIXME: currently it cannot determine whether a region whose regionOverflow state remained either "fit" or "overflow" has actually // changed, so it just assumes that those region should dispatch the event if (previousState != state || state == RenderRegion::RegionFit || state == RenderRegion::RegionOverflow) region->setDispatchRegionLayoutUpdateEvent(true); } // With the regions overflow state computed we can also set the overflow for the named flow. RenderRegion* lastReg = lastRegion(); m_overflow = lastReg && (lastReg->regionState() == RenderRegion::RegionOverflow); }
RenderRegion* RenderFlowThread::mapFromFlowToRegion(TransformState& transformState) const { if (!hasValidRegionInfo()) return 0; LayoutRect boxRect = transformState.mappedQuad().enclosingBoundingBox(); flipForWritingMode(boxRect); // FIXME: We need to refactor RenderObject::absoluteQuads to be able to split the quads across regions, // for now we just take the center of the mapped enclosing box and map it to a region. // Note: Using the center in order to avoid rounding errors. LayoutPoint center = boxRect.center(); RenderRegion* renderRegion = renderRegionForLine(isHorizontalWritingMode() ? center.y() : center.x(), true); if (!renderRegion) return 0; LayoutRect flippedRegionRect(renderRegion->regionRect()); flipForWritingMode(flippedRegionRect); transformState.move(renderRegion->contentBoxRect().location() - flippedRegionRect.location()); return renderRegion; }