// FIXME: Why isn't this just another overload of drawImage? Why have a different name? void CanvasRenderingContext2D::drawImageFromRect(HTMLImageElement* image, float sx, float sy, float sw, float sh, float dx, float dy, float dw, float dh, const String& compositeOperation) { if (!image) return; CachedImage* cachedImage = image->cachedImage(); if (!cachedImage) return; GraphicsContext* c = drawingContext(); if (!c) return; CompositeOperator op; if (!parseCompositeOperator(compositeOperation, op)) op = CompositeSourceOver; FloatRect destRect = FloatRect(dx, dy, dw, dh); willDraw(destRect); #ifdef __OWB__ c->drawImage(cachedImage->image()->nativeImageForCurrentFrame(), destRect, FloatRect(sx, sy, sw, sh), op); cachedImage->image()->startAnimation(); #else c->drawImage(cachedImage->image(), destRect, FloatRect(sx, sy, sw, sh), op); #endif //__OWB__ }
void CanvasRenderingContext2D::drawImage(HTMLImageElement* image, const FloatRect& srcRect, const FloatRect& dstRect, ExceptionCode& ec) { ASSERT(image); ec = 0; FloatRect imageRect = FloatRect(FloatPoint(), size(image)); if (!(imageRect.contains(srcRect) && srcRect.width() >= 0 && srcRect.height() >= 0 && dstRect.width() >= 0 && dstRect.height() >= 0)) { ec = INDEX_SIZE_ERR; return; } if (srcRect.isEmpty() || dstRect.isEmpty()) return; GraphicsContext* c = drawingContext(); if (!c) return; CachedImage* cachedImage = image->cachedImage(); if (!cachedImage) return; FloatRect sourceRect = c->roundToDevicePixels(srcRect); FloatRect destRect = c->roundToDevicePixels(dstRect); willDraw(destRect); #ifdef __OWB__ c->drawImage(cachedImage->image()->nativeImageForCurrentFrame(), destRect, sourceRect, state().m_globalComposite); cachedImage->image()->startAnimation(); #else c->drawImage(cachedImage->image(), destRect, sourceRect, state().m_globalComposite); #endif //__OWB__ }
void CanvasRenderingContext2D::drawImage(HTMLImageElement* image, const FloatRect& srcRect, const FloatRect& dstRect, ExceptionCode& ec) { ASSERT(image); ec = 0; FloatRect imageRect = FloatRect(FloatPoint(), size(image)); if (!(imageRect.contains(srcRect) && srcRect.width() >= 0 && srcRect.height() >= 0 && dstRect.width() >= 0 && dstRect.height() >= 0)) { ec = INDEX_SIZE_ERR; return; } if (srcRect.isEmpty() || dstRect.isEmpty()) return; GraphicsContext* c = drawingContext(); if (!c) return; CachedImage* cachedImage = image->cachedImage(); if (!cachedImage) return; if (m_canvas->originClean()) checkOrigin(KURL(cachedImage->url())); FloatRect sourceRect = c->roundToDevicePixels(srcRect); FloatRect destRect = c->roundToDevicePixels(dstRect); willDraw(destRect); c->drawImage(cachedImage->image(), destRect, sourceRect, state().m_globalComposite); }
// FIXME: Why isn't this just another overload of drawImage? Why have a different name? void CanvasRenderingContext2D::drawImageFromRect(HTMLImageElement* image, float sx, float sy, float sw, float sh, float dx, float dy, float dw, float dh, const String& compositeOperation) { if (!image) return; CachedImage* cachedImage = image->cachedImage(); if (!cachedImage) return; if (m_canvas->originClean()) checkOrigin(KURL(cachedImage->url())); GraphicsContext* c = drawingContext(); if (!c) return; CompositeOperator op; if (!parseCompositeOperator(compositeOperation, op)) op = CompositeSourceOver; FloatRect destRect = FloatRect(dx, dy, dw, dh); willDraw(destRect); c->drawImage(cachedImage->image(), destRect, FloatRect(sx, sy, sw, sh), op); }
void RenderSnapshottedPlugIn::paintSnapshot(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { Image* image = m_snapshotResource->image().get(); if (!image || image->isNull()) return; LayoutUnit cWidth = contentWidth(); LayoutUnit cHeight = contentHeight(); if (!cWidth || !cHeight) return; GraphicsContext* context = paintInfo.context; #if PLATFORM(MAC) if (style()->highlight() != nullAtom && !context->paintingDisabled()) paintCustomHighlight(toPoint(paintOffset - location()), style()->highlight(), true); #endif LayoutSize contentSize(cWidth, cHeight); LayoutPoint contentLocation = location() + paintOffset; contentLocation.move(borderLeft() + paddingLeft(), borderTop() + paddingTop()); LayoutRect rect(contentLocation, contentSize); IntRect alignedRect = pixelSnappedIntRect(rect); if (alignedRect.width() <= 0 || alignedRect.height() <= 0) return; bool useLowQualityScaling = shouldPaintAtLowQuality(context, image, image, alignedRect.size()); ImageOrientationDescription orientationDescription; #if ENABLE(CSS_IMAGE_ORIENTATION) orientationDescription.setImageOrientationEnum(style()->imageOrientation()); #endif context->drawImage(image, style()->colorSpace(), alignedRect, CompositeSourceOver, orientationDescription, useLowQualityScaling); }
void FEGaussianBlur::applySoftware() { ImageBuffer* resultImage = createImageBufferResult(); if (!resultImage) return; FilterEffect* in = inputEffect(0); IntRect drawingRegion = drawingRegionOfInputImage(in->absolutePaintRect()); setIsAlphaImage(in->isAlphaImage()); float stdX = filter()->applyHorizontalScale(m_stdX); float stdY = filter()->applyVerticalScale(m_stdY); RefPtr<Image> image = in->asImageBuffer()->copyImage(DontCopyBackingStore); SkPaint paint; GraphicsContext* dstContext = resultImage->context(); paint.setImageFilter(SkBlurImageFilter::Create(stdX, stdY))->unref(); SkRect bounds = SkRect::MakeWH(absolutePaintRect().width(), absolutePaintRect().height()); dstContext->saveLayer(&bounds, &paint); paint.setColor(0xFFFFFFFF); dstContext->drawImage(image.get(), drawingRegion.location(), CompositeCopy); dstContext->restoreLayer(); }
void HTMLCanvasElement::paint(GraphicsContext& context, const LayoutRect& r, bool useLowQualityScale) { // Clear the dirty rect m_dirtyRect = FloatRect(); if (context.paintingDisabled()) return; if (m_context) { if (!paintsIntoCanvasBuffer() && !document().printing()) return; m_context->paintRenderingResultsToCanvas(); } if (hasCreatedImageBuffer()) { ImageBuffer* imageBuffer = buffer(); if (imageBuffer) { if (m_presentedImage) { ImageOrientationDescription orientationDescription; #if ENABLE(CSS_IMAGE_ORIENTATION) orientationDescription.setImageOrientationEnum(renderer()->style().imageOrientation()); #endif context.drawImage(*m_presentedImage, snappedIntRect(r), ImagePaintingOptions(orientationDescription, useLowQualityScale)); } else context.drawImageBuffer(*imageBuffer, snappedIntRect(r), useLowQualityScale); } } #if ENABLE(WEBGL) if (is3D()) static_cast<WebGLRenderingContextBase*>(m_context.get())->markLayerComposited(); #endif }
void Image::drawTiled(GraphicsContext& ctxt, const FloatRect& destRect, const FloatPoint& srcPoint, const FloatSize& scaledTileSize, SkBlendMode op, const FloatSize& repeatSpacing) { FloatSize intrinsicTileSize = FloatSize(size()); if (hasRelativeSize()) { intrinsicTileSize.setWidth(scaledTileSize.width()); intrinsicTileSize.setHeight(scaledTileSize.height()); } FloatSize scale(scaledTileSize.width() / intrinsicTileSize.width(), scaledTileSize.height() / intrinsicTileSize.height()); const FloatRect oneTileRect = computeTileContaining( destRect.location(), scaledTileSize, srcPoint, repeatSpacing); // Check and see if a single draw of the image can cover the entire area we // are supposed to tile. if (oneTileRect.contains(destRect)) { const FloatRect visibleSrcRect = computeSubsetForTile(oneTileRect, destRect, intrinsicTileSize); ctxt.drawImage(this, destRect, &visibleSrcRect, op, DoNotRespectImageOrientation); return; } FloatRect tileRect(FloatPoint(), intrinsicTileSize); drawPattern(ctxt, tileRect, scale, oneTileRect.location(), op, destRect, repeatSpacing); startAnimation(); }
void Image::drawTiled(GraphicsContext& ctxt, const FloatRect& destRect, const FloatPoint& srcPoint, const FloatSize& scaledTileSize, SkXfermode::Mode op, const FloatSize& repeatSpacing) { FloatSize intrinsicTileSize = FloatSize(size()); if (hasRelativeSize()) { intrinsicTileSize.setWidth(scaledTileSize.width()); intrinsicTileSize.setHeight(scaledTileSize.height()); } FloatSize scale(scaledTileSize.width() / intrinsicTileSize.width(), scaledTileSize.height() / intrinsicTileSize.height()); FloatSize actualTileSize(scaledTileSize.width() + repeatSpacing.width(), scaledTileSize.height() + repeatSpacing.height()); FloatRect oneTileRect; oneTileRect.setX(destRect.x() + fmodf(fmodf(-srcPoint.x(), actualTileSize.width()) - actualTileSize.width(), actualTileSize.width())); oneTileRect.setY(destRect.y() + fmodf(fmodf(-srcPoint.y(), actualTileSize.height()) - actualTileSize.height(), actualTileSize.height())); oneTileRect.setSize(scaledTileSize); // Check and see if a single draw of the image can cover the entire area we are supposed to tile. if (oneTileRect.contains(destRect)) { FloatRect visibleSrcRect; visibleSrcRect.setX((destRect.x() - oneTileRect.x()) / scale.width()); visibleSrcRect.setY((destRect.y() - oneTileRect.y()) / scale.height()); visibleSrcRect.setWidth(destRect.width() / scale.width()); visibleSrcRect.setHeight(destRect.height() / scale.height()); ctxt.drawImage(this, destRect, visibleSrcRect, op, DoNotRespectImageOrientation); return; } FloatRect tileRect(FloatPoint(), intrinsicTileSize); drawPattern(ctxt, tileRect, scale, oneTileRect.location(), op, destRect, repeatSpacing); startAnimation(); }
void ImageBuffer::draw(GraphicsContext& destinationContext, const FloatRect& destRect, const FloatRect& srcRect, CompositeOperator op, BlendMode blendMode) { BackingStoreCopy copyMode = &destinationContext == &context() ? CopyBackingStore : DontCopyBackingStore; RefPtr<Image> image = copyImage(copyMode); destinationContext.drawImage(*image, destRect, srcRect, ImagePaintingOptions(op, blendMode, ImageOrientationDescription())); }
// FIXME: Why isn't this just another overload of drawImage? Why have a different name? void CanvasRenderingContext2D::drawImageFromRect(HTMLImageElement* image, float sx, float sy, float sw, float sh, float dx, float dy, float dw, float dh, const String& compositeOperation) { if (!image) return; CachedImage* cachedImage = image->cachedImage(); if (!cachedImage) return; if (canvas()->originClean()) checkOrigin(cachedImage->response().url()); if (canvas()->originClean() && !cachedImage->image()->hasSingleSecurityOrigin()) canvas()->setOriginTainted(); GraphicsContext* c = drawingContext(); if (!c) return; if (!state().m_invertibleCTM) return; CompositeOperator op; if (!parseCompositeOperator(compositeOperation, op)) op = CompositeSourceOver; FloatRect destRect = FloatRect(dx, dy, dw, dh); willDraw(destRect); c->drawImage(cachedImage->image(), DeviceColorSpace, destRect, FloatRect(sx, sy, sw, sh), op); }
void FEColorMatrix::apply(Filter* filter) { m_in->apply(filter); if (!m_in->resultImage()) return; GraphicsContext* filterContext = getEffectContext(); if (!filterContext) return; filterContext->drawImage(m_in->resultImage()->image(), calculateDrawingRect(m_in->subRegion())); IntRect imageRect(IntPoint(), resultImage()->size()); PassRefPtr<ImageData> imageData(resultImage()->getUnmultipliedImageData(imageRect)); PassRefPtr<CanvasPixelArray> srcPixelArray(imageData->data()); switch (m_type) { case FECOLORMATRIX_TYPE_UNKNOWN: break; case FECOLORMATRIX_TYPE_MATRIX: effectType<FECOLORMATRIX_TYPE_MATRIX>(srcPixelArray, imageData, m_values); break; case FECOLORMATRIX_TYPE_SATURATE: effectType<FECOLORMATRIX_TYPE_SATURATE>(srcPixelArray, imageData, m_values); break; case FECOLORMATRIX_TYPE_HUEROTATE: effectType<FECOLORMATRIX_TYPE_HUEROTATE>(srcPixelArray, imageData, m_values); break; case FECOLORMATRIX_TYPE_LUMINANCETOALPHA: effectType<FECOLORMATRIX_TYPE_LUMINANCETOALPHA>(srcPixelArray, imageData, m_values); break; } resultImage()->putUnmultipliedImageData(imageData.get(), imageRect, IntPoint()); }
void FEMorphology::applySoftware() { ImageBuffer* resultImage = createImageBufferResult(); if (!resultImage) return; FilterEffect* in = inputEffect(0); IntRect drawingRegion = drawingRegionOfInputImage(in->absolutePaintRect()); setIsAlphaImage(in->isAlphaImage()); float radiusX = filter()->applyHorizontalScale(m_radiusX); float radiusY = filter()->applyVerticalScale(m_radiusY); RefPtr<Image> image = in->asImageBuffer()->copyImage(DontCopyBackingStore); SkPaint paint; GraphicsContext* dstContext = resultImage->context(); if (m_type == FEMORPHOLOGY_OPERATOR_DILATE) paint.setImageFilter(SkDilateImageFilter::Create(radiusX, radiusY))->unref(); else if (m_type == FEMORPHOLOGY_OPERATOR_ERODE) paint.setImageFilter(SkErodeImageFilter::Create(radiusX, radiusY))->unref(); SkRect bounds = SkRect::MakeWH(absolutePaintRect().width(), absolutePaintRect().height()); dstContext->saveLayer(&bounds, &paint); dstContext->drawImage(image.get(), drawingRegion.location(), CompositeCopy); dstContext->restoreLayer(); }
void FEGaussianBlur::platformApplySkia() { ImageBuffer* resultImage = createImageBufferResult(); if (!resultImage) return; FilterEffect* in = inputEffect(0); IntRect drawingRegion = drawingRegionOfInputImage(in->absolutePaintRect()); setIsAlphaImage(in->isAlphaImage()); float stdX = filter()->applyHorizontalScale(m_stdX); float stdY = filter()->applyVerticalScale(m_stdY); RefPtr<Image> image = in->asImageBuffer()->copyImage(DontCopyBackingStore); SkPaint paint; GraphicsContext* dstContext = resultImage->context(); SkCanvas* canvas = dstContext->platformContext()->canvas(); paint.setImageFilter(new SkBlurImageFilter(stdX, stdY))->unref(); canvas->saveLayer(0, &paint); paint.setColor(0xFFFFFFFF); dstContext->drawImage(image.get(), ColorSpaceDeviceRGB, drawingRegion.location(), CompositeCopy); canvas->restore(); return; }
void SourceGraphic::apply(Filter* filter) { GraphicsContext* filterContext = getEffectContext(); if (!filterContext) return; filterContext->drawImage(filter->sourceImage()->image(), IntPoint()); }
void ImageBufferSurface::draw(GraphicsContext& context, const FloatRect& destRect, const FloatRect& srcRect, SkXfermode::Mode op) { RefPtr<SkImage> snapshot = newImageSnapshot(PreferNoAcceleration, SnapshotReasonPaint); if (!snapshot) return; RefPtr<Image> image = StaticBitmapImage::create(snapshot.release()); context.drawImage(image.get(), destRect, &srcRect, op); }
bool RenderThemeGtk::paintSearchFieldResultsDecoration(RenderObject* o, const PaintInfo& i, const IntRect& rect) { GraphicsContext* context = i.context; static Image* searchImage = Image::loadPlatformThemeIcon(GTK_STOCK_FIND, rect.width()).releaseRef(); context->drawImage(searchImage, DeviceColorSpace, rect); return false; }
bool RenderThemeGtk::paintSearchFieldCancelButton(RenderObject* o, const PaintInfo& i, const IntRect& rect) { GraphicsContext* context = i.context; // TODO: Brightening up the image on hover is desirable here, I believe. static Image* cancelImage = Image::loadPlatformThemeIcon(GTK_STOCK_CLEAR, rect.width()).releaseRef(); context->drawImage(cancelImage, DeviceColorSpace, rect); return false; }
bool ImageBitmapRenderingContext::paint(GraphicsContext& gc, const IntRect& r) { if (!m_image) return true; // With impl-side painting, it is unsafe to use a gpu-backed SkImage ASSERT(!m_image->imageForCurrentFrame()->isTextureBacked()); gc.drawImage(m_image.get(), r, nullptr, m_hasAlpha ? SkXfermode::kSrcOver_Mode : SkXfermode::kSrc_Mode); return true; }
void ScrollableAreaPainter::drawPlatformResizerImage( GraphicsContext& context, IntRect resizerCornerRect) { float deviceScaleFactor = blink::deviceScaleFactor(getScrollableArea().box().frame()); RefPtr<Image> resizeCornerImage; IntSize cornerResizerSize; if (deviceScaleFactor >= 2) { DEFINE_STATIC_REF(Image, resizeCornerImageHiRes, (Image::loadPlatformResource("textAreaResizeCorner@2x"))); resizeCornerImage = resizeCornerImageHiRes; cornerResizerSize = resizeCornerImage->size(); cornerResizerSize.scale(0.5f); } else { DEFINE_STATIC_REF(Image, resizeCornerImageLoRes, (Image::loadPlatformResource("textAreaResizeCorner"))); resizeCornerImage = resizeCornerImageLoRes; cornerResizerSize = resizeCornerImage->size(); } if (getScrollableArea() .box() .shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) { context.save(); context.translate(resizerCornerRect.x() + cornerResizerSize.width(), resizerCornerRect.y() + resizerCornerRect.height() - cornerResizerSize.height()); context.scale(-1.0, 1.0); context.drawImage(resizeCornerImage.get(), IntRect(IntPoint(), cornerResizerSize)); context.restore(); return; } IntRect imageRect(resizerCornerRect.maxXMaxYCorner() - cornerResizerSize, cornerResizerSize); context.drawImage(resizeCornerImage.get(), imageRect); }
PassOwnPtr<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); OwnPtr<RasterShapeIntervals> intervals = adoptPtr(new RasterShapeIntervals(marginRect.height(), -marginRect.y())); OwnPtr<ImageBuffer> imageBuffer = ImageBuffer::create(imageRect.size()); if (image && imageBuffer) { GraphicsContext* graphicsContext = imageBuffer->context(); // FIXME: This is not totally correct but it is needed to prevent shapes // that loads SVG Images during paint invalidations to mark renderers for // layout, which is not allowed. See https://crbug.com/429346 ImageObserverDisabler disabler(image); graphicsContext->drawImage(image, IntRect(IntPoint(), imageRect.size())); WTF::ArrayBufferContents contents; imageBuffer->getImageData(Unmultiplied, IntRect(IntPoint(), imageRect.size()), contents); RefPtr<DOMArrayBuffer> arrayBuffer = DOMArrayBuffer::create(contents); RefPtr<DOMUint8ClampedArray> pixelArray = DOMUint8ClampedArray::create(arrayBuffer, 0, arrayBuffer->byteLength()); unsigned pixelArrayOffset = 3; // Each pixel is four bytes: RGBA. uint8_t alphaPixelThreshold = threshold * 255; ASSERT(static_cast<unsigned>(imageRect.width() * imageRect.height() * 4) == pixelArray->length()); int minBufferY = std::max(0, marginRect.y() - imageRect.y()); int maxBufferY = std::min(imageRect.height(), marginRect.maxY() - imageRect.y()); 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)) { int endX = alphaAboveThreshold ? x + 1 : x; intervals->intervalAt(y + imageRect.y()).unite(IntShapeInterval(startX + imageRect.x(), endX + imageRect.x())); startX = -1; } } } } OwnPtr<RasterShape> rasterShape = adoptPtr(new RasterShape(intervals.release(), marginRect.size())); rasterShape->m_writingMode = writingMode; rasterShape->m_margin = margin; return rasterShape.release(); }
void FEImage::apply(Filter*) { if (!m_image.get()) return; GraphicsContext* filterContext = getEffectContext(); if (!filterContext) return; FloatRect srcRect(FloatPoint(), m_image->size()); FloatRect destRect(FloatPoint(), subRegion().size()); m_preserveAspectRatio.transformRect(destRect, srcRect); filterContext->drawImage(m_image.get(), DeviceColorSpace, destRect, srcRect); }
void ImagePainter::paintIntoRect(GraphicsContext& context, const LayoutRect& destRect, const LayoutRect& contentRect) { if (!m_layoutImage.imageResource()->hasImage() || m_layoutImage.imageResource()->errorOccurred()) return; // FIXME: should we just ASSERT these conditions? (audit all // callers). IntRect pixelSnappedDestRect = pixelSnappedIntRect(destRect); if (pixelSnappedDestRect.isEmpty()) return; RefPtr<Image> image = m_layoutImage.imageResource()->image( pixelSnappedDestRect.size(), m_layoutImage.style()->effectiveZoom()); if (!image || image->isNull()) return; // FIXME: why is interpolation quality selection not included in the // Instrumentation reported cost of drawing an image? InterpolationQuality interpolationQuality = BoxPainter::chooseInterpolationQuality( m_layoutImage, image.get(), image.get(), LayoutSize(pixelSnappedDestRect.size())); FloatRect srcRect = image->rect(); // If the content rect requires clipping, adjust |srcRect| and // |pixelSnappedDestRect| over using a clip. if (!contentRect.contains(destRect)) { IntRect pixelSnappedContentRect = pixelSnappedIntRect(contentRect); pixelSnappedContentRect.intersect(pixelSnappedDestRect); if (pixelSnappedContentRect.isEmpty()) return; srcRect = mapRect(pixelSnappedContentRect, pixelSnappedDestRect, srcRect); pixelSnappedDestRect = pixelSnappedContentRect; } TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "PaintImage", "data", InspectorPaintImageEvent::data(m_layoutImage)); InterpolationQuality previousInterpolationQuality = context.imageInterpolationQuality(); context.setImageInterpolationQuality(interpolationQuality); context.drawImage( image.get(), pixelSnappedDestRect, &srcRect, SkXfermode::kSrcOver_Mode, LayoutObject::shouldRespectImageOrientation(&m_layoutImage)); context.setImageInterpolationQuality(previousInterpolationQuality); }
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); }