| /* |
| * Copyright (C) 2013 Adobe Systems Incorporated. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * 1. Redistributions of source code must retain the above |
| * copyright notice, this list of conditions and the following |
| * disclaimer. |
| * 2. Redistributions in binary form must reproduce the above |
| * copyright notice, this list of conditions and the following |
| * disclaimer in the documentation and/or other materials |
| * provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
| * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
| * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, |
| * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
| * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
| * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED |
| * OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "config.h" |
| #include "RasterShape.h" |
| |
| #include <wtf/MathExtras.h> |
| |
| namespace WebCore { |
| |
| class MarginIntervalGenerator { |
| public: |
| explicit MarginIntervalGenerator(unsigned radius); |
| void set(int y, const IntShapeInterval&); |
| IntShapeInterval intervalAt(int y) const; |
| |
| private: |
| Vector<int> m_xIntercepts; |
| int m_y; |
| int m_x1; |
| int m_x2; |
| }; |
| |
| MarginIntervalGenerator::MarginIntervalGenerator(unsigned radius) |
| : m_y(0) |
| , m_x1(0) |
| , m_x2(0) |
| { |
| m_xIntercepts.resize(radius + 1); |
| unsigned radiusSquared = radius * radius; |
| for (unsigned y = 0; y <= radius; y++) |
| m_xIntercepts[y] = sqrt(static_cast<double>(radiusSquared - y * y)); |
| } |
| |
| void MarginIntervalGenerator::set(int y, const IntShapeInterval& interval) |
| { |
| ASSERT(y >= 0 && interval.x1() >= 0); |
| m_y = y; |
| m_x1 = interval.x1(); |
| m_x2 = interval.x2(); |
| } |
| |
| IntShapeInterval MarginIntervalGenerator::intervalAt(int y) const |
| { |
| unsigned xInterceptsIndex = abs(y - m_y); |
| int dx = (xInterceptsIndex >= m_xIntercepts.size()) ? 0 : m_xIntercepts[xInterceptsIndex]; |
| return IntShapeInterval(m_x1 - dx, m_x2 + dx); |
| } |
| |
| std::unique_ptr<RasterShapeIntervals> RasterShapeIntervals::computeShapeMarginIntervals(int shapeMargin) const |
| { |
| int marginIntervalsSize = (offset() > shapeMargin) ? size() : size() - offset() * 2 + shapeMargin * 2; |
| auto result = makeUnique<RasterShapeIntervals>(marginIntervalsSize, std::max(shapeMargin, offset())); |
| MarginIntervalGenerator marginIntervalGenerator(shapeMargin); |
| |
| for (int y = bounds().y(); y < bounds().maxY(); ++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 + 1); |
| |
| for (int marginY = y - 1; marginY >= marginY0; --marginY) { |
| if (marginY > bounds().y() && intervalAt(marginY).contains(intervalAtY)) |
| break; |
| result->intervalAt(marginY).unite(marginIntervalGenerator.intervalAt(marginY)); |
| } |
| |
| result->intervalAt(y).unite(marginIntervalGenerator.intervalAt(y)); |
| |
| for (int marginY = y + 1; marginY < marginY1; ++marginY) { |
| if (marginY < bounds().maxY() && intervalAt(marginY).contains(intervalAtY)) |
| break; |
| result->intervalAt(marginY).unite(marginIntervalGenerator.intervalAt(marginY)); |
| } |
| } |
| |
| result->initializeBounds(); |
| return result; |
| } |
| |
| 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 |
| { |
| for (int y = bounds().y(); y < bounds().maxY(); y++) { |
| if (intervalAt(y).isEmpty()) |
| continue; |
| |
| IntShapeInterval extent = intervalAt(y); |
| int endY = y + 1; |
| for (; endY < bounds().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); |
| if (!shapeMargin()) |
| return *m_intervals; |
| |
| int shapeMarginInt = clampToPositiveInteger(ceil(shapeMargin())); |
| int maxShapeMarginInt = std::max(m_marginRectSize.width(), m_marginRectSize.height()) * sqrt(2); |
| if (!m_marginIntervals) |
| m_marginIntervals = m_intervals->computeShapeMarginIntervals(std::min(shapeMarginInt, maxShapeMarginInt)); |
| |
| return *m_marginIntervals; |
| } |
| |
| LineSegment RasterShape::getExcludedInterval(LayoutUnit logicalTop, LayoutUnit logicalHeight) const |
| { |
| const RasterShapeIntervals& intervals = marginIntervals(); |
| if (intervals.isEmpty()) |
| return LineSegment(); |
| |
| int y1 = logicalTop; |
| int y2 = logicalTop + logicalHeight; |
| ASSERT(y2 >= y1); |
| if (y2 < intervals.bounds().y() || y1 >= intervals.bounds().maxY()) |
| return LineSegment(); |
| |
| y1 = std::max(y1, intervals.bounds().y()); |
| y2 = std::min(y2, intervals.bounds().maxY()); |
| IntShapeInterval excludedInterval; |
| |
| if (y1 == y2) |
| excludedInterval = intervals.intervalAt(y1); |
| else { |
| for (int y = y1; y < y2; y++) |
| excludedInterval.unite(intervals.intervalAt(y)); |
| } |
| |
| return LineSegment(excludedInterval.x1(), excludedInterval.x2()); |
| } |
| |
| } // namespace WebCore |