// 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);
}
Example #5
0
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);
}
Example #6
0
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
}
Example #8
0
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();
}
Example #9
0
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();
}
Example #10
0
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);
}
Example #12
0
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());
}
Example #13
0
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();
}
Example #14
0
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;
}
Example #15
0
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;
}
Example #19
0
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;
}
Example #20
0
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);
}
Example #21
0
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();
}
Example #22
0
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);
}
Example #23
0
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);
}
Example #24
0
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);
}