#include "wtf/MathExtras.h"
-namespace WebCore {
+namespace blink {
class MarginIntervalGenerator {
public:
return IntShapeInterval(m_x1 - dx, m_x2 + dx);
}
-void RasterShapeIntervals::appendInterval(int y, int x1, int x2)
-{
- ASSERT(x2 > x1 && (intervalsAt(y).isEmpty() || x1 > intervalsAt(y).last().x2()));
- m_bounds.unite(IntRect(x1, y, x2 - x1, 1));
- intervalsAt(y).append(IntShapeInterval(x1, x2));
-}
-
-void RasterShapeIntervals::uniteMarginInterval(int y, const IntShapeInterval& interval)
-{
- ASSERT(intervalsAt(y).size() <= 1); // Each m_intervalLists entry has 0 or one interval.
-
- if (intervalsAt(y).isEmpty()) {
- intervalsAt(y).append(interval);
- } else {
- IntShapeInterval& resultInterval = intervalsAt(y)[0];
- resultInterval.set(std::min(resultInterval.x1(), interval.x1()), std::max(resultInterval.x2(), interval.x2()));
- }
-
- m_bounds.unite(IntRect(interval.x1(), y, interval.width(), 1));
-}
-
-static inline bool shapeIntervalsContain(const IntShapeIntervals& intervals, const IntShapeInterval& interval)
-{
- for (unsigned i = 0; i < intervals.size(); i++) {
- if (intervals[i].x1() > interval.x2())
- return false;
- if (intervals[i].contains(interval))
- return true;
- }
-
- return false;
-}
-
-bool RasterShapeIntervals::contains(const IntRect& rect) const
-{
- if (!bounds().contains(rect))
- return false;
-
- const IntShapeInterval& rectInterval = IntShapeInterval(rect.x(), rect.maxX());
- for (int y = rect.y(); y < rect.maxY(); y++) {
- if (!shapeIntervalsContain(intervalsAt(y), rectInterval))
- return false;
- }
-
- return true;
-}
-
-static inline void appendX1Values(const IntShapeIntervals& intervals, int minIntervalWidth, Vector<int>& result)
-{
- for (unsigned i = 0; i < intervals.size(); i++) {
- if (intervals[i].width() >= minIntervalWidth)
- result.append(intervals[i].x1());
- }
-}
-
-bool RasterShapeIntervals::getIntervalX1Values(int y1, int y2, int minIntervalWidth, Vector<int>& result) const
-{
- ASSERT(y1 >= 0 && y2 > y1);
-
- for (int y = y1; y < y2; y++) {
- if (intervalsAt(y).isEmpty())
- return false;
- }
-
- appendX1Values(intervalsAt(y1), minIntervalWidth, result);
- for (int y = y1 + 1; y < y2; y++) {
- if (intervalsAt(y) != intervalsAt(y - 1))
- appendX1Values(intervalsAt(y), minIntervalWidth, result);
- }
-
- return true;
-}
-
-bool RasterShapeIntervals::firstIncludedIntervalY(int minY, const IntSize& minSize, LayoutUnit& result) const
-{
- minY = std::max<int>(bounds().y(), minY);
-
- ASSERT(minY >= 0 && minY < size());
-
- if (minSize.isEmpty() || minSize.width() > bounds().width())
- return false;
-
- for (int lineY = minY; lineY <= bounds().maxY() - minSize.height(); lineY++) {
- Vector<int> intervalX1Values;
- if (!getIntervalX1Values(lineY, lineY + minSize.height(), minSize.width(), intervalX1Values))
- continue;
-
- std::sort(intervalX1Values.begin(), intervalX1Values.end());
-
- IntRect firstFitRect(IntPoint(0, 0), minSize);
- for (unsigned i = 0; i < intervalX1Values.size(); i++) {
- int lineX = intervalX1Values[i];
- if (i > 0 && lineX == intervalX1Values[i - 1])
- continue;
- firstFitRect.setLocation(IntPoint(lineX, lineY));
- if (contains(firstFitRect)) {
- result = lineY;
- return true;
- }
- }
- }
-
- return false;
-}
-
-void RasterShapeIntervals::getIncludedIntervals(int y1, int y2, IntShapeIntervals& result) const
-{
- ASSERT(y2 >= y1);
-
- if (y1 < bounds().y() || y2 > bounds().maxY())
- return;
-
- for (int y = y1; y < y2; y++) {
- if (intervalsAt(y).isEmpty())
- return;
- }
-
- result = intervalsAt(y1);
- for (int y = y1 + 1; y < y2 && !result.isEmpty(); y++) {
- IntShapeIntervals intervals;
- IntShapeInterval::intersectShapeIntervals(result, intervalsAt(y), intervals);
- result.swap(intervals);
- }
-}
-
-void RasterShapeIntervals::getExcludedIntervals(int y1, int y2, IntShapeIntervals& result) const
-{
- ASSERT(y2 >= y1);
-
- if (y2 < bounds().y() || y1 >= bounds().maxY())
- return;
-
- y1 = std::max(y1, bounds().y());
- y2 = std::min(y2, bounds().maxY());
-
- result = intervalsAt(y1);
- for (int y = y1 + 1; y < y2; y++) {
- IntShapeIntervals intervals;
- IntShapeInterval::uniteShapeIntervals(result, intervalsAt(y), intervals);
- result.swap(intervals);
- }
-}
-
PassOwnPtr<RasterShapeIntervals> RasterShapeIntervals::computeShapeMarginIntervals(int shapeMargin) const
{
int marginIntervalsSize = (offset() > shapeMargin) ? size() : size() - offset() * 2 + shapeMargin * 2;
MarginIntervalGenerator marginIntervalGenerator(shapeMargin);
for (int y = bounds().y(); y < bounds().maxY(); ++y) {
- const IntShapeInterval& intervalAtY = limitIntervalAt(y);
+ const IntShapeInterval& intervalAtY = intervalAt(y);
if (intervalAtY.isEmpty())
continue;
marginIntervalGenerator.set(y, intervalAtY);
int marginY0 = std::max(minY(), y - shapeMargin);
- int marginY1 = std::min(maxY(), y + shapeMargin);
+ int marginY1 = std::min(maxY(), y + shapeMargin + 1);
for (int marginY = y - 1; marginY >= marginY0; --marginY) {
- if (marginY > bounds().y() && limitIntervalAt(marginY).contains(intervalAtY))
+ if (marginY > bounds().y() && intervalAt(marginY).contains(intervalAtY))
break;
- result->uniteMarginInterval(marginY, marginIntervalGenerator.intervalAt(marginY));
+ result->intervalAt(marginY).unite(marginIntervalGenerator.intervalAt(marginY));
}
- result->uniteMarginInterval(y, marginIntervalGenerator.intervalAt(y));
+ result->intervalAt(y).unite(marginIntervalGenerator.intervalAt(y));
- for (int marginY = y + 1; marginY <= marginY1; ++marginY) {
- if (marginY < bounds().maxY() && limitIntervalAt(marginY).contains(intervalAtY))
+ for (int marginY = y + 1; marginY < marginY1; ++marginY) {
+ if (marginY < bounds().maxY() && intervalAt(marginY).contains(intervalAtY))
break;
- result->uniteMarginInterval(marginY, marginIntervalGenerator.intervalAt(marginY));
+ result->intervalAt(marginY).unite(marginIntervalGenerator.intervalAt(marginY));
}
}
+ result->initializeBounds();
return result.release();
}
+void RasterShapeIntervals::initializeBounds()
+{
+ m_bounds = IntRect();
+ for (int y = minY(); y < maxY(); ++y) {
+ const IntShapeInterval& intervalAtY = intervalAt(y);
+ if (intervalAtY.isEmpty())
+ continue;
+ m_bounds.unite(IntRect(intervalAtY.x1(), y, intervalAtY.width(), 1));
+ }
+}
+
+void RasterShapeIntervals::buildBoundsPath(Path& path) const
+{
+ int maxY = bounds().maxY();
+ for (int y = bounds().y(); y < maxY; y++) {
+ if (intervalAt(y).isEmpty())
+ continue;
+
+ IntShapeInterval extent = intervalAt(y);
+ int endY = y + 1;
+ for (; endY < maxY; endY++) {
+ if (intervalAt(endY).isEmpty() || intervalAt(endY) != extent)
+ break;
+ }
+ path.addRect(FloatRect(extent.x1(), y, extent.width(), endY - y));
+ y = endY - 1;
+ }
+}
+
const RasterShapeIntervals& RasterShape::marginIntervals() const
{
ASSERT(shapeMargin() >= 0);
return *m_marginIntervals;
}
-const RasterShapeIntervals& RasterShape::paddingIntervals() const
-{
- ASSERT(shapePadding() >= 0);
- if (!shapePadding())
- return *m_intervals;
-
- // FIXME: Add support for non-zero padding, see https://bugs.webkit.org/show_bug.cgi?id=116348.
- return *m_intervals;
-}
-
-static inline void appendLineSegments(const IntShapeIntervals& intervals, SegmentList& result)
-{
- for (unsigned i = 0; i < intervals.size(); i++)
- result.append(LineSegment(intervals[i].x1(), intervals[i].x2() + 1));
-}
-
-void RasterShape::getExcludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList& result) const
+LineSegment RasterShape::getExcludedInterval(LayoutUnit logicalTop, LayoutUnit logicalHeight) const
{
const RasterShapeIntervals& intervals = marginIntervals();
if (intervals.isEmpty())
- return;
+ return LineSegment();
- IntShapeIntervals excludedIntervals;
- intervals.getExcludedIntervals(logicalTop, logicalTop + logicalHeight, excludedIntervals);
- appendLineSegments(excludedIntervals, result);
-}
+ int y1 = logicalTop;
+ int y2 = logicalTop + logicalHeight;
+ ASSERT(y2 >= y1);
+ if (y2 < intervals.bounds().y() || y1 >= intervals.bounds().maxY())
+ return LineSegment();
-void RasterShape::getIncludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList& result) const
-{
- const RasterShapeIntervals& intervals = paddingIntervals();
- if (intervals.isEmpty())
- return;
+ y1 = std::max(y1, intervals.bounds().y());
+ y2 = std::min(y2, intervals.bounds().maxY());
+ IntShapeInterval excludedInterval;
- IntShapeIntervals includedIntervals;
- intervals.getIncludedIntervals(logicalTop, logicalTop + logicalHeight, includedIntervals);
- appendLineSegments(includedIntervals, result);
-}
-
-bool RasterShape::firstIncludedIntervalLogicalTop(LayoutUnit minLogicalIntervalTop, const FloatSize& minLogicalIntervalSize, LayoutUnit& result) const
-{
- const RasterShapeIntervals& intervals = paddingIntervals();
- if (intervals.isEmpty())
- return false;
+ if (y1 == y2) {
+ excludedInterval = intervals.intervalAt(y1);
+ } else {
+ for (int y = y1; y < y2; y++)
+ excludedInterval.unite(intervals.intervalAt(y));
+ }
- return intervals.firstIncludedIntervalY(minLogicalIntervalTop.floor(), flooredIntSize(minLogicalIntervalSize), result);
+ // Note: |marginIntervals()| returns end-point exclusive
+ // intervals. |excludedInterval.x2()| contains the left-most pixel
+ // offset to the right of the calculated union.
+ return LineSegment(excludedInterval.x1(), excludedInterval.x2());
}
-} // namespace WebCore
+} // namespace blink