Commit 0300c329 authored by rob.buis@samsung.com's avatar rob.buis@samsung.com

[CSS Shapes] Simplify RasterShape implementation

Since only floats can specify shape-outside, the RasterShapeIntervals
class only needs to track the first and last above threshold pixel column
(x1 and x2 in the implementation) for each row. Removed code for dealing with
multiple "runs" per row as well as shape-inside internals.

This is a merge of http://trac.webkit.org/changeset/166522 by Hans Muller <hmuller@adobe.com>.

BUG=359098

Review URL: https://codereview.chromium.org/212223006

git-svn-id: svn://svn.chromium.org/blink/trunk@170716 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 3b62b1cf
...@@ -73,97 +73,6 @@ IntShapeInterval MarginIntervalGenerator::intervalAt(int y) const ...@@ -73,97 +73,6 @@ IntShapeInterval MarginIntervalGenerator::intervalAt(int y) const
return IntShapeInterval(m_x1 - dx, m_x2 + dx); 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;
}
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 PassOwnPtr<RasterShapeIntervals> RasterShapeIntervals::computeShapeMarginIntervals(int shapeMargin) const
{ {
int marginIntervalsSize = (offset() > shapeMargin) ? size() : size() - offset() * 2 + shapeMargin * 2; int marginIntervalsSize = (offset() > shapeMargin) ? size() : size() - offset() * 2 + shapeMargin * 2;
...@@ -171,7 +80,7 @@ PassOwnPtr<RasterShapeIntervals> RasterShapeIntervals::computeShapeMarginInterva ...@@ -171,7 +80,7 @@ PassOwnPtr<RasterShapeIntervals> RasterShapeIntervals::computeShapeMarginInterva
MarginIntervalGenerator marginIntervalGenerator(shapeMargin); MarginIntervalGenerator marginIntervalGenerator(shapeMargin);
for (int y = bounds().y(); y < bounds().maxY(); ++y) { for (int y = bounds().y(); y < bounds().maxY(); ++y) {
const IntShapeInterval& intervalAtY = limitIntervalAt(y); const IntShapeInterval& intervalAtY = intervalAt(y);
if (intervalAtY.isEmpty()) if (intervalAtY.isEmpty())
continue; continue;
...@@ -180,23 +89,35 @@ PassOwnPtr<RasterShapeIntervals> RasterShapeIntervals::computeShapeMarginInterva ...@@ -180,23 +89,35 @@ PassOwnPtr<RasterShapeIntervals> RasterShapeIntervals::computeShapeMarginInterva
int marginY1 = std::min(maxY(), y + shapeMargin); int marginY1 = std::min(maxY(), y + shapeMargin);
for (int marginY = y - 1; marginY >= marginY0; --marginY) { 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; 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) { for (int marginY = y + 1; marginY <= marginY1; ++marginY) {
if (marginY < bounds().maxY() && limitIntervalAt(marginY).contains(intervalAtY)) if (marginY < bounds().maxY() && intervalAt(marginY).contains(intervalAtY))
break; break;
result->uniteMarginInterval(marginY, marginIntervalGenerator.intervalAt(marginY)); result->intervalAt(marginY).unite(marginIntervalGenerator.intervalAt(marginY));
} }
} }
result->initializeBounds();
return result.release(); 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));
}
}
const RasterShapeIntervals& RasterShape::marginIntervals() const const RasterShapeIntervals& RasterShape::marginIntervals() const
{ {
ASSERT(shapeMargin() >= 0); ASSERT(shapeMargin() >= 0);
...@@ -211,21 +132,26 @@ const RasterShapeIntervals& RasterShape::marginIntervals() const ...@@ -211,21 +132,26 @@ const RasterShapeIntervals& RasterShape::marginIntervals() const
return *m_marginIntervals; return *m_marginIntervals;
} }
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 void RasterShape::getExcludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList& result) const
{ {
const RasterShapeIntervals& intervals = marginIntervals(); const RasterShapeIntervals& intervals = marginIntervals();
if (intervals.isEmpty()) if (intervals.isEmpty())
return; return;
IntShapeIntervals excludedIntervals; int y1 = logicalTop;
intervals.getExcludedIntervals(logicalTop, logicalTop + logicalHeight, excludedIntervals); int y2 = logicalTop + logicalHeight;
appendLineSegments(excludedIntervals, result); ASSERT(y2 >= y1);
if (y2 < intervals.bounds().y() || y1 >= intervals.bounds().maxY())
return;
y1 = std::max(y1, intervals.bounds().y());
y2 = std::min(y2, intervals.bounds().maxY());
IntShapeInterval excludedInterval;
for (int y = y1; y < y2; y++)
excludedInterval.unite(intervals.intervalAt(y));
result.append(LineSegment(excludedInterval.x1(), excludedInterval.x2() + 1));
} }
} // namespace WebCore } // namespace WebCore
...@@ -43,48 +43,37 @@ public: ...@@ -43,48 +43,37 @@ public:
RasterShapeIntervals(unsigned size, int offset = 0) RasterShapeIntervals(unsigned size, int offset = 0)
: m_offset(offset) : m_offset(offset)
{ {
m_intervalLists.resize(size); m_intervals.resize(size);
} }
void initializeBounds();
const IntRect& bounds() const { return m_bounds; } const IntRect& bounds() const { return m_bounds; }
bool isEmpty() const { return m_bounds.isEmpty(); } bool isEmpty() const { return m_bounds.isEmpty(); }
void appendInterval(int y, int x1, int x2);
void getExcludedIntervals(int y1, int y2, IntShapeIntervals& result) const; IntShapeInterval& intervalAt(int y)
{
ASSERT(y + m_offset >= 0 && static_cast<unsigned>(y + m_offset) < m_intervals.size());
return m_intervals[y + m_offset];
}
const IntShapeInterval& intervalAt(int y) const
{
ASSERT(y + m_offset >= 0 && static_cast<unsigned>(y + m_offset) < m_intervals.size());
return m_intervals[y + m_offset];
}
PassOwnPtr<RasterShapeIntervals> computeShapeMarginIntervals(int shapeMargin) const; PassOwnPtr<RasterShapeIntervals> computeShapeMarginIntervals(int shapeMargin) const;
void buildBoundsPath(Path&) const; void buildBoundsPath(Path&) const;
private: private:
int size() const { return m_intervalLists.size(); } int size() const { return m_intervals.size(); }
int offset() const { return m_offset; } int offset() const { return m_offset; }
int minY() const { return -m_offset; } int minY() const { return -m_offset; }
int maxY() const { return -m_offset + m_intervalLists.size(); } int maxY() const { return -m_offset + m_intervals.size(); }
IntShapeIntervals& intervalsAt(int y)
{
ASSERT(y + m_offset >= 0 && static_cast<unsigned>(y + m_offset) < m_intervalLists.size());
return m_intervalLists[y + m_offset];
}
const IntShapeIntervals& intervalsAt(int y) const
{
ASSERT(y + m_offset >= 0 && static_cast<unsigned>(y + m_offset) < m_intervalLists.size());
return m_intervalLists[y + m_offset];
}
IntShapeInterval limitIntervalAt(int y) const
{
const IntShapeIntervals& intervals = intervalsAt(y);
return intervals.size() ? IntShapeInterval(intervals[0].x1(), intervals.last().x2()) : IntShapeInterval();
}
bool contains(const IntRect&) const;
bool getIntervalX1Values(int minY, int maxY, int minIntervalWidth, Vector<int>& result) const;
void uniteMarginInterval(int y, const IntShapeInterval&);
IntRect m_bounds; IntRect m_bounds;
Vector<IntShapeIntervals> m_intervalLists; Vector<IntShapeInterval> m_intervals;
int m_offset; int m_offset;
}; };
...@@ -95,6 +84,7 @@ public: ...@@ -95,6 +84,7 @@ public:
: m_intervals(intervals) : m_intervals(intervals)
, m_marginRectSize(marginRectSize) , m_marginRectSize(marginRectSize)
{ {
m_intervals->initializeBounds();
} }
virtual LayoutRect shapeMarginLogicalBoundingBox() const OVERRIDE { return static_cast<LayoutRect>(marginIntervals().bounds()); } virtual LayoutRect shapeMarginLogicalBoundingBox() const OVERRIDE { return static_cast<LayoutRect>(marginIntervals().bounds()); }
......
...@@ -202,7 +202,7 @@ PassOwnPtr<Shape> Shape::createRasterShape(Image* image, float threshold, const ...@@ -202,7 +202,7 @@ PassOwnPtr<Shape> Shape::createRasterShape(Image* image, float threshold, const
if (startX == -1 && alphaAboveThreshold) { if (startX == -1 && alphaAboveThreshold) {
startX = x; startX = x;
} else if (startX != -1 && (!alphaAboveThreshold || x == imageRect.width() - 1)) { } else if (startX != -1 && (!alphaAboveThreshold || x == imageRect.width() - 1)) {
intervals->appendInterval(y + imageRect.y(), startX + imageRect.x(), x + imageRect.x()); intervals->intervalAt(y + imageRect.y()).unite(IntShapeInterval(startX + imageRect.x(), x + imageRect.x()));
startX = -1; startX = -1;
} }
} }
......
...@@ -207,6 +207,16 @@ public: ...@@ -207,6 +207,16 @@ public:
bool operator==(const ShapeInterval<T>& other) const { return x1() == other.x1() && x2() == other.x2(); } bool operator==(const ShapeInterval<T>& other) const { return x1() == other.x1() && x2() == other.x2(); }
bool operator!=(const ShapeInterval<T>& other) const { return !operator==(other); } bool operator!=(const ShapeInterval<T>& other) const { return !operator==(other); }
void unite(const ShapeInterval<T>& interval)
{
if (interval.isEmpty())
return;
if (isEmpty())
set(interval.x1(), interval.x2());
else
set(std::min<T>(x1(), interval.x1()), std::max<T>(x2(), interval.x2()));
}
private: private:
T m_x1; T m_x1;
T m_x2; T m_x2;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment