PassOwnPtr<RasterShapeIntervals> RasterShapeIntervals::computeShapeMarginIntervals(int shapeMargin) const { int marginIntervalsSize = (offset() > shapeMargin) ? size() : size() - offset() * 2 + shapeMargin * 2; OwnPtr<RasterShapeIntervals> result = adoptPtr(new 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.release(); }
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; } }
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)); } }
std::unique_ptr<Shape> Shape::createRasterShape(Image* image, float threshold, const LayoutRect& imageR, const LayoutRect& marginR, WritingMode writingMode, float margin) { IntRect imageRect = pixelSnappedIntRect(imageR); IntRect marginRect = pixelSnappedIntRect(marginR); auto intervals = std::make_unique<RasterShapeIntervals>(marginRect.height(), -marginRect.y()); std::unique_ptr<ImageBuffer> imageBuffer = ImageBuffer::create(imageRect.size()); if (imageBuffer) { GraphicsContext* graphicsContext = imageBuffer->context(); graphicsContext->drawImage(image, ColorSpaceDeviceRGB, IntRect(IntPoint(), imageRect.size())); RefPtr<Uint8ClampedArray> pixelArray = imageBuffer->getUnmultipliedImageData(IntRect(IntPoint(), imageRect.size())); unsigned pixelArrayLength = pixelArray->length(); unsigned pixelArrayOffset = 3; // Each pixel is four bytes: RGBA. uint8_t alphaPixelThreshold = threshold * 255; int minBufferY = std::max(0, marginRect.y() - imageRect.y()); int maxBufferY = std::min(imageRect.height(), marginRect.maxY() - imageRect.y()); if (static_cast<unsigned>(imageRect.width() * imageRect.height() * 4) == pixelArrayLength) { for (int y = minBufferY; y < maxBufferY; ++y) { int startX = -1; for (int x = 0; x < imageRect.width(); ++x, pixelArrayOffset += 4) { uint8_t alpha = pixelArray->item(pixelArrayOffset); bool alphaAboveThreshold = alpha > alphaPixelThreshold; if (startX == -1 && alphaAboveThreshold) { startX = x; } else if (startX != -1 && (!alphaAboveThreshold || x == imageRect.width() - 1)) { // We're creating "end-point exclusive" intervals here. The value of an interval's x1 is // the first index of an above-threshold pixel for y, and the value of x2 is 1+ the index // of the last above-threshold pixel. int endX = alphaAboveThreshold ? x + 1 : x; intervals->intervalAt(y + imageRect.y()).unite(IntShapeInterval(startX + imageRect.x(), endX + imageRect.x())); startX = -1; } } } } } auto rasterShape = std::make_unique<RasterShape>(WTF::move(intervals), marginRect.size()); rasterShape->m_writingMode = writingMode; rasterShape->m_margin = margin; return WTF::move(rasterShape); }