void ExclusionPolygon::getIncludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList& result) const { const FloatPolygon& polygon = shapePaddingBounds(); if (polygon.isEmpty()) return; float y1 = logicalTop; float y2 = logicalTop + logicalHeight; Vector<ExclusionInterval> y1XIntervals, y2XIntervals; computeXIntersections(polygon, y1, true, y1XIntervals); computeXIntersections(polygon, y2, false, y2XIntervals); Vector<ExclusionInterval> commonIntervals; intersectExclusionIntervals(y1XIntervals, y2XIntervals, commonIntervals); Vector<ExclusionInterval> edgeIntervals; computeOverlappingEdgeXProjections(polygon, y1, y2, edgeIntervals); Vector<ExclusionInterval> includedIntervals; subtractExclusionIntervals(commonIntervals, edgeIntervals, includedIntervals); for (unsigned i = 0; i < includedIntervals.size(); ++i) { ExclusionInterval interval = includedIntervals[i]; result.append(LineSegment(interval.x1, interval.x2)); } }
void PolygonShape::getIncludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList& result) const { const FloatPolygon& polygon = shapePaddingBounds(); if (polygon.isEmpty()) return; float y1 = logicalTop; float y2 = logicalTop + logicalHeight; FloatShapeIntervals y1XIntervals, y2XIntervals; computeXIntersections(polygon, y1, true, y1XIntervals); computeXIntersections(polygon, y2, false, y2XIntervals); FloatShapeIntervals commonIntervals; FloatShapeInterval::intersectShapeIntervals(y1XIntervals, y2XIntervals, commonIntervals); FloatShapeIntervals edgeIntervals; computeOverlappingEdgeXProjections(polygon, y1, y2, edgeIntervals); FloatShapeIntervals includedIntervals; FloatShapeInterval::subtractShapeIntervals(commonIntervals, edgeIntervals, includedIntervals); for (unsigned i = 0; i < includedIntervals.size(); ++i) { const FloatShapeInterval& interval = includedIntervals[i]; result.append(LineSegment(interval.x1(), interval.x2())); } }
void BoxShape::getIncludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList& result) const { const FloatRoundedRect& paddingBounds = shapePaddingBounds(); if (paddingBounds.isEmpty()) return; const FloatRect& rect = paddingBounds.rect(); float y1 = logicalTop; float y2 = logicalTop + logicalHeight; if (y1 < rect.y() || y2 > rect.maxY()) return; if (!paddingBounds.isRounded()) { result.append(LineSegment(rect.x(), rect.maxX())); return; } float x1 = rect.x(); float x2 = rect.maxX(); float minXIntercept; float maxXIntercept; if (paddingBounds.xInterceptsAtY(y1, minXIntercept, maxXIntercept)) { x1 = std::max<float>(x1, minXIntercept); x2 = std::min<float>(x2, maxXIntercept); } if (paddingBounds.xInterceptsAtY(y2, minXIntercept, maxXIntercept)) { x1 = std::max<float>(x1, minXIntercept); x2 = std::min<float>(x2, maxXIntercept); } result.append(LineSegment(x1, x2)); }
bool RectangleShape::firstIncludedIntervalLogicalTop(LayoutUnit minLogicalIntervalTop, const LayoutSize& minLogicalIntervalSize, LayoutUnit& result) const { float minIntervalTop = minLogicalIntervalTop; float minIntervalHeight = minLogicalIntervalSize.height(); float minIntervalWidth = minLogicalIntervalSize.width(); const FloatRoundedRect& bounds = shapePaddingBounds(); if (bounds.isEmpty() || minIntervalWidth > bounds.width()) return false; float minY = std::max(bounds.y(), minIntervalTop); float maxY = minY + minIntervalHeight; if (maxY > bounds.maxY()) return false; bool intervalOverlapsMinCorner = minY < bounds.y() + bounds.ry(); bool intervalOverlapsMaxCorner = maxY > bounds.maxY() - bounds.ry(); if (!intervalOverlapsMinCorner && !intervalOverlapsMaxCorner) { result = minY; return true; } float centerY = bounds.y() + bounds.height() / 2; bool minCornerDefinesX = fabs(centerY - minY) > fabs(centerY - maxY); bool intervalFitsWithinCorners = minIntervalWidth + 2 * bounds.rx() <= bounds.width(); FloatPoint cornerIntercept = bounds.cornerInterceptForWidth(minIntervalWidth); if (intervalOverlapsMinCorner && (!intervalOverlapsMaxCorner || minCornerDefinesX)) { if (intervalFitsWithinCorners || bounds.y() + cornerIntercept.y() < minY) { result = minY; return true; } if (minIntervalHeight < bounds.height() - (2 * cornerIntercept.y())) { result = ceiledLayoutUnit(bounds.y() + cornerIntercept.y()); return true; } } if (intervalOverlapsMaxCorner && (!intervalOverlapsMinCorner || !minCornerDefinesX)) { if (intervalFitsWithinCorners || minY <= bounds.maxY() - cornerIntercept.y() - minIntervalHeight) { result = minY; return true; } } return false; }
void RectangleShape::getIncludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList& result) const { const FloatRoundedRect& bounds = shapePaddingBounds(); if (bounds.isEmpty()) return; float y1 = logicalTop; float y2 = logicalTop + logicalHeight; if (y1 < bounds.y() || y2 > bounds.maxY()) return; float x1 = bounds.x(); float x2 = bounds.maxX(); if (bounds.ry() > 0) { bool y1InterceptsCorner = y1 < bounds.y() + bounds.ry(); bool y2InterceptsCorner = y2 > bounds.maxY() - bounds.ry(); float xi = 0; if (y1InterceptsCorner && y2InterceptsCorner) { if (y1 < bounds.height() + 2 * bounds.y() - y2) { float yi = y1 - bounds.y() - bounds.ry(); xi = ellipseXIntercept(yi, bounds.rx(), bounds.ry()); } else { float yi = y2 - (bounds.maxY() - bounds.ry()); xi = ellipseXIntercept(yi, bounds.rx(), bounds.ry()); } } else if (y1InterceptsCorner) { float yi = y1 - bounds.y() - bounds.ry(); xi = ellipseXIntercept(yi, bounds.rx(), bounds.ry()); } else if (y2InterceptsCorner) { float yi = y2 - (bounds.maxY() - bounds.ry()); xi = ellipseXIntercept(yi, bounds.rx(), bounds.ry()); } if (y1InterceptsCorner || y2InterceptsCorner) { x1 = bounds.x() + bounds.rx() - xi; x2 = bounds.maxX() - bounds.rx() + xi; } } result.append(LineSegment(x1, x2)); }
bool ExclusionPolygon::firstIncludedIntervalLogicalTop(LayoutUnit minLogicalIntervalTop, const LayoutSize& minLogicalIntervalSize, LayoutUnit& result) const { float minIntervalTop = minLogicalIntervalTop; float minIntervalHeight = minLogicalIntervalSize.height(); float minIntervalWidth = minLogicalIntervalSize.width(); const FloatPolygon& polygon = shapePaddingBounds(); const FloatRect boundingBox = polygon.boundingBox(); if (minIntervalWidth > boundingBox.width()) return false; float minY = std::max(boundingBox.y(), minIntervalTop); float maxY = minY + minIntervalHeight; if (maxY > boundingBox.maxY()) return false; Vector<const FloatPolygonEdge*> edges; polygon.overlappingEdges(minIntervalTop, boundingBox.maxY(), edges); float dx = minIntervalWidth / 2; float dy = minIntervalHeight / 2; Vector<OffsetPolygonEdge> offsetEdges; for (unsigned i = 0; i < edges.size(); ++i) { const FloatPolygonEdge& edge = *(edges[i]); const FloatPoint& vertex0 = edge.previousEdge().vertex1(); const FloatPoint& vertex1 = edge.vertex1(); const FloatPoint& vertex2 = edge.vertex2(); Vector<OffsetPolygonEdge> offsetEdgeBuffer; if (vertex2.y() > vertex1.y() ? vertex2.x() >= vertex1.x() : vertex1.x() >= vertex2.x()) { offsetEdgeBuffer.append(OffsetPolygonEdge(edge, FloatSize(dx, -dy))); offsetEdgeBuffer.append(OffsetPolygonEdge(edge, FloatSize(-dx, dy))); } else { offsetEdgeBuffer.append(OffsetPolygonEdge(edge, FloatSize(dx, dy))); offsetEdgeBuffer.append(OffsetPolygonEdge(edge, FloatSize(-dx, -dy))); } if (isReflexVertex(vertex0, vertex1, vertex2)) { if (vertex2.x() <= vertex1.x() && vertex0.x() <= vertex1.x()) offsetEdgeBuffer.append(OffsetPolygonEdge(vertex1, FloatSize(dx, -dy), FloatSize(dx, dy))); else if (vertex2.x() >= vertex1.x() && vertex0.x() >= vertex1.x()) offsetEdgeBuffer.append(OffsetPolygonEdge(vertex1, FloatSize(-dx, -dy), FloatSize(-dx, dy))); if (vertex2.y() <= vertex1.y() && vertex0.y() <= vertex1.y()) offsetEdgeBuffer.append(OffsetPolygonEdge(vertex1, FloatSize(-dx, dy), FloatSize(dx, dy))); else if (vertex2.y() >= vertex1.y() && vertex0.y() >= vertex1.y()) offsetEdgeBuffer.append(OffsetPolygonEdge(vertex1, FloatSize(-dx, -dy), FloatSize(dx, -dy))); } for (unsigned j = 0; j < offsetEdgeBuffer.size(); ++j) if (offsetEdgeBuffer[j].maxY() >= minY) offsetEdges.append(offsetEdgeBuffer[j]); } offsetEdges.append(OffsetPolygonEdge(polygon, minIntervalTop, FloatSize(0, dy))); FloatPoint offsetEdgesIntersection; FloatRect firstFitRect; bool firstFitFound = false; for (unsigned i = 0; i < offsetEdges.size() - 1; ++i) { for (unsigned j = i + 1; j < offsetEdges.size(); ++j) { if (offsetEdges[i].intersection(offsetEdges[j], offsetEdgesIntersection)) { FloatPoint potentialFirstFitLocation(offsetEdgesIntersection.x() - dx, offsetEdgesIntersection.y() - dy); FloatRect potentialFirstFitRect(potentialFirstFitLocation, minLogicalIntervalSize); if ((offsetEdges[i].basis() == OffsetPolygonEdge::LineTop || offsetEdges[j].basis() == OffsetPolygonEdge::LineTop || potentialFirstFitLocation.y() >= minIntervalTop) && (!firstFitFound || aboveOrToTheLeft(potentialFirstFitRect, firstFitRect)) && polygon.contains(offsetEdgesIntersection) && firstFitRectInPolygon(polygon, potentialFirstFitRect, offsetEdges[i].edgeIndex(), offsetEdges[j].edgeIndex())) { firstFitFound = true; firstFitRect = potentialFirstFitRect; } } } } if (firstFitFound) result = LayoutUnit::fromFloatCeil(firstFitRect.y()); return firstFitFound; }