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);
}
Пример #3
0
void BitmapImageSingleFrameSkia::draw(GraphicsContext* ctxt,
                                      const FloatRect& dstRect,
                                      const FloatRect& srcRect,
                                      ColorSpace styleColorSpace,
                                      CompositeOperator compositeOp)
{
    FloatRect normDstRect = normalizeRect(dstRect);
    FloatRect normSrcRect = normalizeRect(srcRect);

    if (normSrcRect.isEmpty() || normDstRect.isEmpty())
        return;  // Nothing to draw.

    if (ctxt->platformContext()->useGPU() && ctxt->platformContext()->canAccelerate()) {
        drawBitmapGLES2(ctxt, &m_nativeImage, srcRect, dstRect, styleColorSpace, compositeOp);
        return;
    }

    ctxt->platformContext()->prepareForSoftwareDraw();

    paintSkBitmap(ctxt->platformContext(),
                  m_nativeImage,
                  enclosingIntRect(normSrcRect),
                  normDstRect,
                  WebCoreCompositeToSkiaComposite(compositeOp));
}
Пример #4
0
void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect,
                       const FloatRect& srcRect, ColorSpace colorSpace, CompositeOperator compositeOp)
{
    if (!m_source.initialized())
        return;

    // Spin the animation to the correct frame before we try to draw it, so we
    // don't draw an old frame and then immediately need to draw a newer one,
    // causing flicker and wasting CPU.
    startAnimation();

    NativeImageSkia* bm = nativeImageForCurrentFrame();
    if (!bm)
        return;  // It's too early and we don't have an image yet.

    FloatRect normDstRect = normalizeRect(dstRect);
    FloatRect normSrcRect = normalizeRect(srcRect);

    if (normSrcRect.isEmpty() || normDstRect.isEmpty())
        return;  // Nothing to draw.

    paintSkBitmap(ctxt->platformContext(),
                  *bm,
                  enclosingIntRect(normSrcRect),
                  normDstRect,
                  WebCoreCompositeToSkiaComposite(compositeOp));

    if (ImageObserver* observer = imageObserver())
        observer->didDraw(this);
}
Пример #5
0
FloatRect RenderSVGImage::repaintRectInLocalCoordinates() const
{
    // If we already have a cached repaint rect, return that
    if (!m_cachedLocalRepaintRect.isEmpty())
        return m_cachedLocalRepaintRect;

    m_cachedLocalRepaintRect = m_localBounds;

    // FIXME: We need to be careful here. We assume that there is no filter,
    // clipper or masker if the rects are empty.
    FloatRect rect = filterBoundingBoxForRenderer(this);
    if (!rect.isEmpty())
        m_cachedLocalRepaintRect = rect;

    rect = clipperBoundingBoxForRenderer(this);
    if (!rect.isEmpty())
        m_cachedLocalRepaintRect.intersect(rect);

    rect = maskerBoundingBoxForRenderer(this);
    if (!rect.isEmpty())
        m_cachedLocalRepaintRect.intersect(rect);

    style()->svgStyle()->inflateForShadow(m_cachedLocalRepaintRect);

    return m_cachedLocalRepaintRect;
}
Пример #6
0
FloatRect RenderPath::repaintRectInLocalCoordinates() const
{
    if (m_path.isEmpty())
        return FloatRect();

    // If we already have a cached repaint rect, return that
    if (!m_cachedLocalRepaintRect.isEmpty())
        return m_cachedLocalRepaintRect;

    // FIXME: We need to be careful here. We assume that there is no filter,
    // clipper, marker or masker if the rects are empty.
    FloatRect rect = filterBoundingBoxForRenderer(this);
    if (!rect.isEmpty())
        m_cachedLocalRepaintRect = rect;
    else {
        m_cachedLocalRepaintRect = strokeBoundingBox();
        m_cachedLocalRepaintRect.unite(markerBoundingBox());
    }

    rect = clipperBoundingBoxForRenderer(this);
    if (!rect.isEmpty())
        m_cachedLocalRepaintRect.intersect(rect);

    rect = maskerBoundingBoxForRenderer(this);
    if (!rect.isEmpty())
        m_cachedLocalRepaintRect.intersect(rect);

    style()->svgStyle()->inflateForShadow(m_cachedLocalRepaintRect);

    return m_cachedLocalRepaintRect;
}
Пример #7
0
void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect,
                       const FloatRect& srcRect, ColorSpace colorSpace, CompositeOperator compositeOp)
{
    if (!m_source.initialized())
        return;

    // Spin the animation to the correct frame before we try to draw it, so we
    // don't draw an old frame and then immediately need to draw a newer one,
    // causing flicker and wasting CPU.
    startAnimation();

    NativeImageSkia* bm = nativeImageForCurrentFrame();
    if (!bm)
        return;  // It's too early and we don't have an image yet.

    FloatRect normDstRect = normalizeRect(dstRect);
    FloatRect normSrcRect = normalizeRect(srcRect);

    if (normSrcRect.isEmpty() || normDstRect.isEmpty())
        return;  // Nothing to draw.

#if ENABLE(ACCELERATED_2D_CANVAS)
    if (ctxt->platformContext()->useGPU() && ctxt->platformContext()->canAccelerate()) {
        drawBitmapGLES2(ctxt, bm, normSrcRect, normDstRect, colorSpace, compositeOp);
        return;
    }
#endif
    ctxt->platformContext()->prepareForSoftwareDraw();

    paintSkBitmap(ctxt->platformContext(),
                  *bm,
                  enclosingIntRect(normSrcRect),
                  normDstRect,
                  WebCoreCompositeToSkiaComposite(compositeOp));
}
Пример #8
0
SVGPaintServer LayoutSVGResourceGradient::preparePaintServer(
    const LayoutObject& object) {
  clearInvalidationMask();

  // Be sure to synchronize all SVG properties on the gradientElement _before_
  // processing any further. Otherwhise the call to collectGradientAttributes()
  // in createTileImage(), may cause the SVG DOM property synchronization to
  // kick in, which causes removeAllClientsFromCache() to be called, which in
  // turn deletes our GradientData object! Leaving out the line below will cause
  // svg/dynamic-updates/SVG*GradientElement-svgdom* to crash.
  SVGGradientElement* gradientElement = toSVGGradientElement(element());
  if (!gradientElement)
    return SVGPaintServer::invalid();

  if (m_shouldCollectGradientAttributes) {
    gradientElement->synchronizeAnimatedSVGAttribute(anyQName());
    if (!collectGradientAttributes(gradientElement))
      return SVGPaintServer::invalid();

    m_shouldCollectGradientAttributes = false;
  }

  // Spec: When the geometry of the applicable element has no width or height
  // and objectBoundingBox is specified, then the given effect (e.g. a gradient
  // or a filter) will be ignored.
  FloatRect objectBoundingBox = object.objectBoundingBox();
  if (gradientUnits() == SVGUnitTypes::kSvgUnitTypeObjectboundingbox &&
      objectBoundingBox.isEmpty())
    return SVGPaintServer::invalid();

  std::unique_ptr<GradientData>& gradientData =
      m_gradientMap.add(&object, nullptr).storedValue->value;
  if (!gradientData)
    gradientData = WTF::wrapUnique(new GradientData);

  // Create gradient object
  if (!gradientData->gradient) {
    gradientData->gradient = buildGradient();

    // We want the text bounding box applied to the gradient space transform
    // now, so the gradient shader can use it.
    if (gradientUnits() == SVGUnitTypes::kSvgUnitTypeObjectboundingbox &&
        !objectBoundingBox.isEmpty()) {
      gradientData->userspaceTransform.translate(objectBoundingBox.x(),
                                                 objectBoundingBox.y());
      gradientData->userspaceTransform.scaleNonUniform(
          objectBoundingBox.width(), objectBoundingBox.height());
    }

    AffineTransform gradientTransform = calculateGradientTransform();
    gradientData->userspaceTransform *= gradientTransform;
  }

  if (!gradientData->gradient)
    return SVGPaintServer::invalid();

  return SVGPaintServer(gradientData->gradient,
                        gradientData->userspaceTransform);
}
Пример #9
0
void Image::drawPattern(GraphicsContext* context, const FloatRect& floatSrcRect, const FloatSize& scale,
    const FloatPoint& phase, SkXfermode::Mode compositeOp, const FloatRect& destRect, const IntSize& repeatSpacing)
{
    TRACE_EVENT0("skia", "Image::drawPattern");
    SkBitmap bitmap;
    if (!bitmapForCurrentFrame(&bitmap))
        return;

    FloatRect normSrcRect = floatSrcRect;

    normSrcRect.intersect(FloatRect(0, 0, bitmap.width(), bitmap.height()));
    if (destRect.isEmpty() || normSrcRect.isEmpty())
        return; // nothing to draw

    SkMatrix localMatrix;
    // We also need to translate it such that the origin of the pattern is the
    // origin of the destination rect, which is what WebKit expects. Skia uses
    // the coordinate system origin as the base for the pattern. If WebKit wants
    // a shifted image, it will shift it from there using the localMatrix.
    const float adjustedX = phase.x() + normSrcRect.x() * scale.width();
    const float adjustedY = phase.y() + normSrcRect.y() * scale.height();
    localMatrix.setTranslate(SkFloatToScalar(adjustedX), SkFloatToScalar(adjustedY));

    // Because no resizing occurred, the shader transform should be
    // set to the pattern's transform, which just includes scale.
    localMatrix.preScale(scale.width(), scale.height());

    SkBitmap bitmapToPaint;
    bitmap.extractSubset(&bitmapToPaint, enclosingIntRect(normSrcRect));
    if (!repeatSpacing.isZero()) {
        SkScalar ctmScaleX = 1.0;
        SkScalar ctmScaleY = 1.0;

        if (!RuntimeEnabledFeatures::slimmingPaintEnabled()) {
            AffineTransform ctm = context->getCTM();
            ctmScaleX = ctm.xScale();
            ctmScaleY = ctm.yScale();
        }

        bitmapToPaint = createBitmapWithSpace(
            bitmapToPaint,
            repeatSpacing.width() * ctmScaleX / scale.width(),
            repeatSpacing.height() * ctmScaleY / scale.height());
    }
    RefPtr<SkShader> shader = adoptRef(SkShader::CreateBitmapShader(bitmapToPaint, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, &localMatrix));

    bool isLazyDecoded = DeferredImageDecoder::isLazyDecoded(bitmap);
    {
        SkPaint paint;
        int initialSaveCount = context->preparePaintForDrawRectToRect(&paint, floatSrcRect,
            destRect, compositeOp, !bitmap.isOpaque(), isLazyDecoded, bitmap.isImmutable());
        paint.setShader(shader.get());
        context->drawRect(destRect, paint);
        context->canvas()->restoreToCount(initialSaveCount);
    }

    if (isLazyDecoded)
        PlatformInstrumentation::didDrawLazyPixelRef(bitmap.getGenerationID());
}
Пример #10
0
void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect, const FloatRect& srcRect, SkXfermode::Mode compositeOp, RespectImageOrientationEnum shouldRespectImageOrientation)
{
    TRACE_EVENT0("skia", "BitmapImage::draw");
    SkBitmap bitmap;
    if (!bitmapForCurrentFrame(&bitmap))
        return; // It's too early and we don't have an image yet.

    FloatRect normDstRect = adjustForNegativeSize(dstRect);
    FloatRect normSrcRect = adjustForNegativeSize(srcRect);
    normSrcRect.intersect(FloatRect(0, 0, bitmap.width(), bitmap.height()));

    if (normSrcRect.isEmpty() || normDstRect.isEmpty())
        return; // Nothing to draw.

    ImageOrientation orientation = DefaultImageOrientation;
    if (shouldRespectImageOrientation == RespectImageOrientation)
        orientation = frameOrientationAtIndex(m_currentFrame);

    GraphicsContextStateSaver saveContext(*ctxt, false);
    if (orientation != DefaultImageOrientation) {
        saveContext.save();

        // ImageOrientation expects the origin to be at (0, 0)
        ctxt->translate(normDstRect.x(), normDstRect.y());
        normDstRect.setLocation(FloatPoint());

        ctxt->concatCTM(orientation.transformFromDefault(normDstRect.size()));

        if (orientation.usesWidthAsHeight()) {
            // The destination rect will have it's width and height already reversed for the orientation of
            // the image, as it was needed for page layout, so we need to reverse it back here.
            normDstRect = FloatRect(normDstRect.x(), normDstRect.y(), normDstRect.height(), normDstRect.width());
        }
    }

    bool isLazyDecoded = DeferredImageDecoder::isLazyDecoded(bitmap);
    bool isOpaque = bitmap.isOpaque();

    {
        SkPaint paint;
        SkRect skSrcRect = normSrcRect;
        int initialSaveCount = ctxt->preparePaintForDrawRectToRect(&paint, skSrcRect, normDstRect, compositeOp, !isOpaque, isLazyDecoded, bitmap.isImmutable());
        // We want to filter it if we decided to do interpolation above, or if
        // there is something interesting going on with the matrix (like a rotation).
        // Note: for serialization, we will want to subset the bitmap first so we
        // don't send extra pixels.
        ctxt->drawBitmapRect(bitmap, &skSrcRect, normDstRect, &paint);
        ctxt->canvas()->restoreToCount(initialSaveCount);
    }

    if (isLazyDecoded)
        PlatformInstrumentation::didDrawLazyPixelRef(bitmap.getGenerationID());

    if (ImageObserver* observer = imageObserver())
        observer->didDraw(this);

    startAnimation();
}
Пример #11
0
void Image::drawPattern(GraphicsContext& context,
                        const FloatRect& floatSrcRect,
                        const FloatSize& scale,
                        const FloatPoint& phase,
                        SkBlendMode compositeOp,
                        const FloatRect& destRect,
                        const FloatSize& repeatSpacing) {
  TRACE_EVENT0("skia", "Image::drawPattern");

  sk_sp<SkImage> image = imageForCurrentFrame();
  if (!image)
    return;

  FloatRect normSrcRect = floatSrcRect;

  normSrcRect.intersect(FloatRect(0, 0, image->width(), image->height()));
  if (destRect.isEmpty() || normSrcRect.isEmpty())
    return;  // nothing to draw

  SkMatrix localMatrix;
  // We also need to translate it such that the origin of the pattern is the
  // origin of the destination rect, which is what WebKit expects. Skia uses
  // the coordinate system origin as the base for the pattern. If WebKit wants
  // a shifted image, it will shift it from there using the localMatrix.
  const float adjustedX = phase.x() + normSrcRect.x() * scale.width();
  const float adjustedY = phase.y() + normSrcRect.y() * scale.height();
  localMatrix.setTranslate(SkFloatToScalar(adjustedX),
                           SkFloatToScalar(adjustedY));

  // Because no resizing occurred, the shader transform should be
  // set to the pattern's transform, which just includes scale.
  localMatrix.preScale(scale.width(), scale.height());

  // Fetch this now as subsetting may swap the image.
  auto imageID = image->uniqueID();

  image = image->makeSubset(enclosingIntRect(normSrcRect));
  if (!image)
    return;

  {
    SkPaint paint = context.fillPaint();
    paint.setColor(SK_ColorBLACK);
    paint.setBlendMode(static_cast<SkBlendMode>(compositeOp));
    paint.setFilterQuality(
        context.computeFilterQuality(this, destRect, normSrcRect));
    paint.setAntiAlias(context.shouldAntialias());
    paint.setShader(createPatternShader(
        image.get(), localMatrix, paint,
        FloatSize(repeatSpacing.width() / scale.width(),
                  repeatSpacing.height() / scale.height())));
    context.drawRect(destRect, paint);
  }

  if (currentFrameIsLazyDecoded())
    PlatformInstrumentation::didDrawLazyPixelRef(imageID);
}
Пример #12
0
void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect, const FloatRect& srcRect, ColorSpace colorSpace, CompositeOperator compositeOp, RespectImageOrientationEnum shouldRespectImageOrientation)
{
    if (!m_source.initialized())
        return;

    // Spin the animation to the correct frame before we try to draw it, so we
    // don't draw an old frame and then immediately need to draw a newer one,
    // causing flicker and wasting CPU.
    startAnimation();

    NativeImageSkia* bm = nativeImageForCurrentFrame();
    if (!bm)
        return; // It's too early and we don't have an image yet.

    FloatRect normDstRect = normalizeRect(dstRect);
    FloatRect normSrcRect = normalizeRect(srcRect);
    normSrcRect.intersect(FloatRect(0, 0, bm->bitmap().width(), bm->bitmap().height()));

    if (normSrcRect.isEmpty() || normDstRect.isEmpty())
        return; // Nothing to draw.

    ImageOrientation orientation = DefaultImageOrientation;
    if (shouldRespectImageOrientation == RespectImageOrientation)
        orientation = frameOrientationAtIndex(m_currentFrame);

    GraphicsContextStateSaver saveContext(*ctxt, false);
    if (orientation != DefaultImageOrientation) {
        saveContext.save();

        // ImageOrientation expects the origin to be at (0, 0)
        ctxt->translate(normDstRect.x(), normDstRect.y());
        normDstRect.setLocation(FloatPoint());

        ctxt->concatCTM(orientation.transformFromDefault(normDstRect.size()));

        if (orientation.usesWidthAsHeight()) {
            // The destination rect will have it's width and height already reversed for the orientation of
            // the image, as it was needed for page layout, so we need to reverse it back here.
            normDstRect = FloatRect(normDstRect.x(), normDstRect.y(), normDstRect.height(), normDstRect.width());
        }
    }

    paintSkBitmap(ctxt->platformContext(),
        *bm,
        normSrcRect,
        normDstRect,
        WebCoreCompositeToSkiaComposite(compositeOp));

    if (ImageObserver* observer = imageObserver())
        observer->didDraw(this);
}
Пример #13
0
void BitmapImage::draw(SkCanvas* canvas, const SkPaint& paint, const FloatRect& dstRect, const FloatRect& srcRect, RespectImageOrientationEnum shouldRespectImageOrientation, ImageClampingMode clampMode)
{
    TRACE_EVENT0("skia", "BitmapImage::draw");

    RefPtr<SkImage> image = imageForCurrentFrame();
    if (!image)
        return; // It's too early and we don't have an image yet.

    FloatRect adjustedSrcRect = srcRect;
    adjustedSrcRect.intersect(FloatRect(0, 0, image->width(), image->height()));

    if (adjustedSrcRect.isEmpty() || dstRect.isEmpty())
        return; // Nothing to draw.

    ImageOrientation orientation = DefaultImageOrientation;
    if (shouldRespectImageOrientation == RespectImageOrientation)
        orientation = frameOrientationAtIndex(m_currentFrame);

    int initialSaveCount = canvas->getSaveCount();
    FloatRect adjustedDstRect = dstRect;
    if (orientation != DefaultImageOrientation) {
        canvas->save();

        // ImageOrientation expects the origin to be at (0, 0)
        canvas->translate(adjustedDstRect.x(), adjustedDstRect.y());
        adjustedDstRect.setLocation(FloatPoint());

        canvas->concat(affineTransformToSkMatrix(orientation.transformFromDefault(adjustedDstRect.size())));

        if (orientation.usesWidthAsHeight()) {
            // The destination rect will have it's width and height already reversed for the orientation of
            // the image, as it was needed for page layout, so we need to reverse it back here.
            adjustedDstRect = FloatRect(adjustedDstRect.x(), adjustedDstRect.y(), adjustedDstRect.height(), adjustedDstRect.width());
        }
    }

    SkRect skSrcRect = adjustedSrcRect;
    canvas->drawImageRect(image.get(), skSrcRect, adjustedDstRect, &paint,
        WebCoreClampingModeToSkiaRectConstraint(clampMode));
    canvas->restoreToCount(initialSaveCount);

    if (currentFrameIsLazyDecoded())
        PlatformInstrumentation::didDrawLazyPixelRef(image->uniqueID());

    if (ImageObserver* observer = imageObserver())
        observer->didDraw(this);

    startAnimation();
}
bool FloatRect::intersects(const FloatRect& other) const
{
    // Checking emptiness handles negative widths as well as zero.
    return !isEmpty() && !other.isEmpty()
        && x() < other.maxX() && other.x() < maxX()
        && y() < other.maxY() && other.y() < maxY();
}
Пример #15
0
void KdPath::addRoundedRect(const FloatRect& rect, const FloatSize& topLeftRadius, const FloatSize& topRightRadius, const FloatSize& bottomLeftRadius, const FloatSize& bottomRightRadius)
{
    if (rect.isEmpty())
        return;

    if (rect.width() < topLeftRadius.width() + topRightRadius.width()
            || rect.width() < bottomLeftRadius.width() + bottomRightRadius.width()
            || rect.height() < topLeftRadius.height() + bottomLeftRadius.height()
            || rect.height() < topRightRadius.height() + bottomRightRadius.height()) {
        // If all the radii cannot be accommodated, return a rect.
        addRect(rect);
        return;
    }

    moveTo(FloatPoint(rect.x() + topLeftRadius.width(), rect.y()));

    addLineTo(FloatPoint(rect.x() + rect.width() - topRightRadius.width(), rect.y()));
    addBezierCurveTo(FloatPoint(rect.x() + rect.width() - topRightRadius.width() * gCircleControlPoint, rect.y()),
                     FloatPoint(rect.x() + rect.width(), rect.y() + topRightRadius.height() * gCircleControlPoint),
                     FloatPoint(rect.x() + rect.width(), rect.y() + topRightRadius.height()));
    addLineTo(FloatPoint(rect.x() + rect.width(), rect.y() + rect.height() - bottomRightRadius.height()));
    addBezierCurveTo(FloatPoint(rect.x() + rect.width(), rect.y() + rect.height() - bottomRightRadius.height() * gCircleControlPoint),
                     FloatPoint(rect.x() + rect.width() - bottomRightRadius.width() * gCircleControlPoint, rect.y() + rect.height()),
                     FloatPoint(rect.x() + rect.width() - bottomRightRadius.width(), rect.y() + rect.height()));
    addLineTo(FloatPoint(rect.x() + bottomLeftRadius.width(), rect.y() + rect.height()));
    addBezierCurveTo(FloatPoint(rect.x() + bottomLeftRadius.width() * gCircleControlPoint, rect.y() + rect.height()),
                     FloatPoint(rect.x(), rect.y() + rect.height() - bottomLeftRadius.height() * gCircleControlPoint),
                     FloatPoint(rect.x(), rect.y() + rect.height() - bottomLeftRadius.height()));
    addLineTo(FloatPoint(rect.x(), rect.y() + topLeftRadius.height()));
    addBezierCurveTo(FloatPoint(rect.x(), rect.y() + topLeftRadius.height() * gCircleControlPoint),
                     FloatPoint(rect.x() + topLeftRadius.width() * gCircleControlPoint, rect.y()),
                     FloatPoint(rect.x() + topLeftRadius.width(), rect.y()));

    closeSubpath();
}
Пример #16
0
void BitmapImage::drawPattern(GraphicsContext& ctxt, const FloatRect& tileRect, const AffineTransform& transform,
    const FloatPoint& phase, const FloatSize& spacing, CompositeOperator op, const FloatRect& destRect, BlendMode blendMode)
{
    if (tileRect.isEmpty())
        return;

    if (!ctxt.drawLuminanceMask()) {
        Image::drawPattern(ctxt, tileRect, transform, phase, spacing, op, destRect, blendMode);
        return;
    }
    if (!m_cachedImage) {
        auto buffer = ImageBuffer::createCompatibleBuffer(expandedIntSize(tileRect.size()), ctxt);
        if (!buffer)
            return;

        ImageObserver* observer = imageObserver();
        ASSERT(observer);

        // Temporarily reset image observer, we don't want to receive any changeInRect() calls due to this relayout.
        setImageObserver(nullptr);

        draw(buffer->context(), tileRect, tileRect, op, blendMode, ImageOrientationDescription());

        setImageObserver(observer);
        buffer->convertToLuminanceMask();

        m_cachedImage = buffer->copyImage(DontCopyBackingStore, Unscaled);
        if (!m_cachedImage)
            return;
    }

    ctxt.setDrawLuminanceMask(false);
    m_cachedImage->drawPattern(ctxt, tileRect, transform, phase, spacing, op, destRect, blendMode);
}
Пример #17
0
FloatRect findInPageRectFromAbsoluteRect(const FloatRect& inputRect, const LayoutObject* baseLayoutObject)
{
    if (!baseLayoutObject || inputRect.isEmpty())
        return FloatRect();

    // Normalize the input rect to its container block.
    const LayoutBlock* baseContainer = enclosingScrollableAncestor(baseLayoutObject);
    FloatRect normalizedRect = toNormalizedRect(inputRect, baseLayoutObject, baseContainer);

    // Go up across frames.
    for (const LayoutBox* layoutObject = baseContainer; layoutObject; ) {

        // Go up the layout tree until we reach the root of the current frame (the LayoutView).
        while (!layoutObject->isLayoutView()) {
            const LayoutBlock* container = enclosingScrollableAncestor(layoutObject);

            // Compose the normalized rects.
            FloatRect normalizedBoxRect = toNormalizedRect(layoutObject->absoluteBoundingBoxRect(), layoutObject, container);
            normalizedRect.scale(normalizedBoxRect.width(), normalizedBoxRect.height());
            normalizedRect.moveBy(normalizedBoxRect.location());

            layoutObject = container;
        }

        ASSERT(layoutObject->isLayoutView());

        // Jump to the layoutObject owning the frame, if any.
        layoutObject = layoutObject->frame() ? layoutObject->frame()->ownerLayoutObject() : 0;
    }

    return normalizedRect;
}
Пример #18
0
static FloatRect toNormalizedRect(const FloatRect& absoluteRect, const LayoutObject* layoutObject, const LayoutBlock* container)
{
    ASSERT(layoutObject);

    ASSERT(container || layoutObject->isLayoutView());
    if (!container)
        return FloatRect();

    // We want to normalize by the max layout overflow size instead of only the visible bounding box.
    // Quads and their enclosing bounding boxes need to be used in order to keep results transform-friendly.
    FloatPoint scrolledOrigin;

    // For overflow:scroll we need to get where the actual origin is independently of the scroll.
    if (container->hasOverflowClip())
        scrolledOrigin = -IntPoint(container->scrolledContentOffset());

    FloatRect overflowRect(scrolledOrigin, FloatSize(container->maxLayoutOverflow()));
    FloatRect containerRect = container->localToAbsoluteQuad(FloatQuad(overflowRect)).enclosingBoundingBox();

    if (containerRect.isEmpty())
        return FloatRect();

    // Make the coordinates relative to the container enclosing bounding box.
    // Since we work with rects enclosing quad unions this is still transform-friendly.
    FloatRect normalizedRect = absoluteRect;
    normalizedRect.moveBy(-containerRect.location());

    // Fixed positions do not make sense in this coordinate system, but need to leave consistent tickmarks.
    // So, use their position when the view is not scrolled, like an absolute position.
    if (layoutObject->style()->position() == FixedPosition && container->isLayoutView())
        normalizedRect.moveBy(-toLayoutView(container)->frameView()->scrollPosition());

    normalizedRect.scale(1 / containerRect.width(), 1 / containerRect.height());
    return normalizedRect;
}
FloatRect RenderSVGResourceClipper::resourceBoundingBox(const FloatRect& objectBoundingBox) const
{
    FloatRect clipRect;
    for (Node* childNode = node()->firstChild(); childNode; childNode = childNode->nextSibling()) {
        if (!childNode->isSVGElement() || !static_cast<SVGElement*>(childNode)->isStyledTransformable())
            continue;
        SVGStyledTransformableElement* styled = static_cast<SVGStyledTransformableElement*>(childNode);
        RenderStyle* style = styled->renderer() ? styled->renderer()->style() : 0;
        if (!style || style->display() == NONE)
            continue;
        clipRect.unite(styled->renderer()->objectBoundingBox());
    }

    if (clipRect.isEmpty())
        return FloatRect();

    if (static_cast<SVGClipPathElement*>(node())->clipPathUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
        AffineTransform obbTransform;
        obbTransform.translate(objectBoundingBox.x(), objectBoundingBox.y());
        obbTransform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height());
        return obbTransform.mapRect(clipRect);
    }

    return clipRect;
}
void CCDirectRenderer::drawRenderPass(DrawingFrame& frame, const CCRenderPass* renderPass)
{
    if (!useRenderPass(frame, renderPass))
        return;

    frame.scissorRectInRenderPassSpace = frame.currentRenderPass->outputRect();
    if (frame.rootDamageRect != frame.rootRenderPass->outputRect()) {
        WebTransformationMatrix inverseTransformToRoot = frame.currentRenderPass->transformToRootTarget().inverse();
        frame.scissorRectInRenderPassSpace.intersect(CCMathUtil::projectClippedRect(inverseTransformToRoot, frame.rootDamageRect));
    }

    enableScissorTestRect(moveScissorToWindowSpace(frame, frame.scissorRectInRenderPassSpace));
    clearFramebuffer(frame);

    const CCQuadList& quadList = renderPass->quadList();
    for (CCQuadList::constBackToFrontIterator it = quadList.backToFrontBegin(); it != quadList.backToFrontEnd(); ++it) {
        FloatRect quadScissorRect = frame.scissorRectInRenderPassSpace;
        quadScissorRect.intersect(it->get()->clippedRectInTarget());
        if (!quadScissorRect.isEmpty()) {
            enableScissorTestRect(moveScissorToWindowSpace(frame, quadScissorRect));
            drawQuad(frame, it->get());
        }
    }

    CachedTexture* texture = m_renderPassTextures.get(renderPass->id());
    if (texture)
        texture->setIsComplete(!renderPass->hasOcclusionFromOutsideTargetSurface());
}
Пример #21
0
void Path::addRoundedRect(const FloatRect& rect,
                          const FloatSize& roundingRadii) {
  if (rect.isEmpty())
    return;

  FloatSize radius(roundingRadii);
  FloatSize halfSize(rect.width() / 2, rect.height() / 2);

  // Apply the SVG corner radius constraints, per the rect section of the SVG
  // shapes spec: if one of rx,ry is negative, then the other corner radius
  // value is used. If both values are negative then rx = ry = 0. If rx is
  // greater than half of the width of the rectangle then set rx to half of the
  // width; ry is handled similarly.

  if (radius.width() < 0)
    radius.setWidth((radius.height() < 0) ? 0 : radius.height());

  if (radius.height() < 0)
    radius.setHeight(radius.width());

  if (radius.width() > halfSize.width())
    radius.setWidth(halfSize.width());

  if (radius.height() > halfSize.height())
    radius.setHeight(halfSize.height());

  addPathForRoundedRect(rect, radius, radius, radius, radius);
}
Пример #22
0
void BitmapImage::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const AffineTransform& transform,
    const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& destRect, BlendMode blendMode)
{
    if (tileRect.isEmpty())
        return;

    if (!ctxt->drawLuminanceMask()) {
        Image::drawPattern(ctxt, tileRect, transform, phase, styleColorSpace, op, destRect, blendMode);
        return;
    }
    if (!m_cachedImage) {
        OwnPtr<ImageBuffer> buffer = ImageBuffer::create(expandedIntSize(tileRect.size()));
        ASSERT(buffer.get());

        ImageObserver* observer = imageObserver();
        ASSERT(observer);

        // Temporarily reset image observer, we don't want to receive any changeInRect() calls due to this relayout.
        setImageObserver(0);

        draw(buffer->context(), tileRect, tileRect, styleColorSpace, op, blendMode);

        setImageObserver(observer);
        buffer->convertToLuminanceMask();

        m_cachedImage = buffer->copyImage(DontCopyBackingStore, Unscaled);
        m_cachedImage->setSpaceSize(spaceSize());

        setImageObserver(observer);
    }

    ctxt->setDrawLuminanceMask(false);
    m_cachedImage->drawPattern(ctxt, tileRect, transform, phase, styleColorSpace, op, destRect, blendMode);
}
Пример #23
0
FloatRect findInPageRectFromAbsoluteRect(const FloatRect& inputRect, const RenderObject* baseRenderer)
{
    if (!baseRenderer || inputRect.isEmpty())
        return FloatRect();

    // Normalize the input rect to its container block.
    const RenderBlock* baseContainer = enclosingScrollableAncestor(baseRenderer);
    FloatRect normalizedRect = toNormalizedRect(inputRect, baseRenderer, baseContainer);

    // Go up across frames.
    for (const RenderBox* renderer = baseContainer; renderer; ) {

        // Go up the render tree until we reach the root of the current frame (the RenderView).
        while (!renderer->isRenderView()) {
            const RenderBlock* container = enclosingScrollableAncestor(renderer);

            // Compose the normalized rects.
            FloatRect normalizedBoxRect = toNormalizedRect(renderer->absoluteBoundingBoxRect(), renderer, container);
            normalizedRect.scale(normalizedBoxRect.width(), normalizedBoxRect.height());
            normalizedRect.moveBy(normalizedBoxRect.location());

            renderer = container;
        }

        ASSERT(renderer->isRenderView());

        // Jump to the renderer owning the frame, if any.
        renderer = renderer->frame() ? renderer->frame()->ownerRenderer() : 0;
    }

    return normalizedRect;
}
Пример #24
0
FloatRect SVGSVGElement::currentViewBoxRect() const
{
    if (useCurrentView()) {
        if (SVGViewSpec* view = currentView()) // what if we should use it but it is not set?
            return view->viewBox();
        return FloatRect();
    }

    FloatRect useViewBox = viewBox();
    if (!useViewBox.isEmpty())
        return useViewBox;
    if (!renderer() || !renderer()->isSVGRoot())
        return FloatRect();
    if (!toRenderSVGRoot(renderer())->isEmbeddedThroughSVGImage())
        return FloatRect();

    Length intrinsicWidth = this->intrinsicWidth();
    Length intrinsicHeight = this->intrinsicHeight();
    if (!intrinsicWidth.isFixed() || !intrinsicHeight.isFixed())
        return FloatRect();

    // If no viewBox is specified but non-relative width/height values, then we
    // should always synthesize a viewBox if we're embedded through a SVGImage.    
    return FloatRect(FloatPoint(), FloatSize(intrinsicWidth.calcFloatValue(0), intrinsicHeight.calcFloatValue(0)));
}
Пример #25
0
void RenderSVGPath::updateCachedBoundaries()
{
    if (m_path.isEmpty()) {
        m_fillBoundingBox = FloatRect();
        m_strokeAndMarkerBoundingBox = FloatRect();
        m_repaintBoundingBox = FloatRect();
        return;
    }

    // Cache _unclipped_ fill bounding box, used for calculations in resources
    m_fillBoundingBox = m_path.boundingRect();

    // Cache _unclipped_ stroke bounding box, used for calculations in resources (includes marker boundaries)
    m_strokeAndMarkerBoundingBox = m_fillBoundingBox;

    const SVGRenderStyle* svgStyle = style()->svgStyle();
    if (svgStyle->hasStroke()) {
        BoundingRectStrokeStyleApplier strokeStyle(this, style());
        m_strokeAndMarkerBoundingBox.unite(m_path.strokeBoundingRect(&strokeStyle));
    }

    if (svgStyle->hasMarkers()) {
        FloatRect markerBounds = calculateMarkerBoundsIfNeeded();
        if (!markerBounds.isEmpty())
            m_strokeAndMarkerBoundingBox.unite(markerBounds);
    }

    // Cache smallest possible repaint rectangle
    m_repaintBoundingBox = m_strokeAndMarkerBoundingBox;
    SVGRenderSupport::intersectRepaintRectWithResources(this, m_repaintBoundingBox);
}
static inline bool createMaskAndSwapContextForTextGradient(GraphicsContext*& context,
                                                           GraphicsContext*& savedContext,
                                                           OwnPtr<ImageBuffer>& imageBuffer,
                                                           RenderObject* object)
{
    RenderObject* textRootBlock = RenderSVGText::locateRenderSVGTextAncestor(object);
    ASSERT(textRootBlock);

    AffineTransform absoluteTransform;
    SVGImageBufferTools::calculateTransformationToOutermostSVGCoordinateSystem(textRootBlock, absoluteTransform);

    FloatRect absoluteTargetRect = absoluteTransform.mapRect(textRootBlock->repaintRectInLocalCoordinates());
    FloatRect clampedAbsoluteTargetRect = SVGImageBufferTools::clampedAbsoluteTargetRectForRenderer(textRootBlock, absoluteTargetRect);
    if (clampedAbsoluteTargetRect.isEmpty())
        return false;

    OwnPtr<ImageBuffer> maskImage;
    if (!SVGImageBufferTools::createImageBuffer(absoluteTargetRect, clampedAbsoluteTargetRect, maskImage, ColorSpaceDeviceRGB))
        return false;

    GraphicsContext* maskImageContext = maskImage->context();
    ASSERT(maskImageContext);

    maskImageContext->translate(-clampedAbsoluteTargetRect.x(), -clampedAbsoluteTargetRect.y());
    maskImageContext->concatCTM(absoluteTransform);

    ASSERT(maskImage);
    savedContext = context;
    context = maskImageContext;
    imageBuffer = maskImage.release();
    return true;
}
FloatRect RenderSVGResourcePattern::calculatePatternBoundariesIncludingOverflow(PatternAttributes& attributes,
                                                                                const FloatRect& objectBoundingBox,
                                                                                const AffineTransform& viewBoxCTM,
                                                                                const FloatRect& patternBoundaries) const
{
    // Eventually calculate the pattern content boundaries (only needed with overflow="visible").
    FloatRect patternContentBoundaries;

    const RenderStyle* style = this->style();
    if (style->overflowX() == OVISIBLE && style->overflowY() == OVISIBLE) {
        for (Node* node = attributes.patternContentElement()->firstChild(); node; node = node->nextSibling()) {
            if (!node->isSVGElement() || !static_cast<SVGElement*>(node)->isStyledTransformable() || !node->renderer())
                continue;
            patternContentBoundaries.unite(node->renderer()->repaintRectInLocalCoordinates());
        }
    }

    if (patternContentBoundaries.isEmpty())
        return patternBoundaries;

    FloatRect patternBoundariesIncludingOverflow = patternBoundaries;

    // Respect objectBoundingBoxMode for patternContentUnits, if viewBox is not set.
    if (!viewBoxCTM.isIdentity())
        patternContentBoundaries = viewBoxCTM.mapRect(patternContentBoundaries);
    else if (attributes.boundingBoxModeContent())
        patternContentBoundaries = FloatRect(patternContentBoundaries.x() * objectBoundingBox.width(),
                                             patternContentBoundaries.y() * objectBoundingBox.height(),
                                             patternContentBoundaries.width() * objectBoundingBox.width(),
                                             patternContentBoundaries.height() * objectBoundingBox.height());

    patternBoundariesIncludingOverflow.unite(patternContentBoundaries);
    return patternBoundariesIncludingOverflow;
}
Пример #28
0
void TilingData::intersectDrawQuad(const FloatRect& srcRect, const FloatRect& dstRect, int tile,
                                   FloatRect* newSrc, FloatRect* newDst) const
{
    // Intersect with tile
    FloatRect tileBounds = this->tileBounds(tile);
    FloatRect srcRectIntersected = srcRect;
    srcRectIntersected.intersect(tileBounds);

    if (srcRectIntersected.isEmpty()) {
        *newSrc = *newDst = FloatRect(0, 0, 0, 0);
        return;
    }

    float srcRectIntersectedNormX = (srcRectIntersected.x() - srcRect.x()) / srcRect.width();
    float srcRectIntersectedNormY = (srcRectIntersected.y() - srcRect.y()) / srcRect.height();
    float srcRectIntersectedNormW = srcRectIntersected.width() / srcRect.width();
    float srcRectIntersectedNormH = srcRectIntersected.height() / srcRect.height();

    *newSrc = srcRectIntersected;
    newSrc->move(
        -tileBounds.x() + ((tileXIndex(tile) > 0) ? m_borderTexels : 0),
        -tileBounds.y() + ((tileYIndex(tile) > 0) ? m_borderTexels : 0));

    *newDst = FloatRect(
        srcRectIntersectedNormX * dstRect.width() + dstRect.x(),
        srcRectIntersectedNormY * dstRect.height() + dstRect.y(),
        srcRectIntersectedNormW * dstRect.width(),
        srcRectIntersectedNormH * dstRect.height());
}
Пример #29
0
void Path::addRoundedRect(const FloatRect& rect,
                          const FloatSize& topLeftRadius,
                          const FloatSize& topRightRadius,
                          const FloatSize& bottomLeftRadius,
                          const FloatSize& bottomRightRadius) {
  if (rect.isEmpty())
    return;

  if (rect.width() < topLeftRadius.width() + topRightRadius.width() ||
      rect.width() < bottomLeftRadius.width() + bottomRightRadius.width() ||
      rect.height() < topLeftRadius.height() + bottomLeftRadius.height() ||
      rect.height() < topRightRadius.height() + bottomRightRadius.height()) {
    // If all the radii cannot be accommodated, return a rect.
    // FIXME: Is this an error scenario, given that it appears the code in
    // FloatRoundedRect::constrainRadii() should be always called first? Should
    // we assert that this code is not reached? This fallback is very bad, since
    // it means that radii that are just barely too big due to rounding or
    // snapping will get completely ignored.
    addRect(rect);
    return;
  }

  addPathForRoundedRect(rect, topLeftRadius, topRightRadius, bottomLeftRadius,
                        bottomRightRadius);
}
Пример #30
0
bool RenderSVGResourceMasker::applyResource(RenderElement& renderer, const RenderStyle&, GraphicsContext*& context, unsigned short resourceMode)
{
    ASSERT(context);
    ASSERT_UNUSED(resourceMode, resourceMode == ApplyToDefaultMode);

    bool missingMaskerData = !m_masker.contains(&renderer);
    if (missingMaskerData)
        m_masker.set(&renderer, std::make_unique<MaskerData>());

    MaskerData* maskerData = m_masker.get(&renderer);
    AffineTransform absoluteTransform = SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(renderer);
    FloatRect repaintRect = renderer.repaintRectInLocalCoordinates();

    if (!maskerData->maskImage && !repaintRect.isEmpty()) {
        const SVGRenderStyle& svgStyle = style().svgStyle();
        ColorSpace colorSpace = svgStyle.colorInterpolation() == CI_LINEARRGB ? ColorSpaceLinearRGB : ColorSpaceDeviceRGB;
        maskerData->maskImage = SVGRenderingContext::createImageBuffer(repaintRect, absoluteTransform, colorSpace, Unaccelerated);
        if (!maskerData->maskImage)
            return false;

        if (!drawContentIntoMaskImage(maskerData, colorSpace, &renderer))
            maskerData->maskImage.reset();
    }

    if (!maskerData->maskImage)
        return false;

    SVGRenderingContext::clipToImageBuffer(context, absoluteTransform, repaintRect, maskerData->maskImage, missingMaskerData);
    return true;
}