Example #1
0
void GraphicsContext::drawImage(Image* image, const FloatRect& dest, const FloatRect& src, CompositeOperator op, bool useLowQualityScale)
{
    if (paintingDisabled() || !image)
        return;

    float tsw = src.width();
    float tsh = src.height();
    float tw = dest.width();
    float th = dest.height();
        
    if (tsw == -1)
        tsw = image->width();
    if (tsh == -1)
        tsh = image->height();

    if (tw == -1)
        tw = image->width();
    if (th == -1)
        th = image->height();

    if (useLowQualityScale) {
        save();
        setImageInterpolationQuality(InterpolationNone);
    }
    image->draw(this, FloatRect(dest.location(), FloatSize(tw, th)), FloatRect(src.location(), FloatSize(tsw, tsh)), op);
    if (useLowQualityScale)
        restore();
}
bool LinkHighlightImpl::computeHighlightLayerPathAndPosition(const LayoutBoxModelObject& paintInvalidationContainer)
{
    if (!m_node || !m_node->layoutObject() || !m_currentGraphicsLayer)
        return false;

    // FIXME: This is defensive code to avoid crashes such as those described in
    // crbug.com/440887. This should be cleaned up once we fix the root cause of
    // of the paint invalidation container not being composited.
    if (!paintInvalidationContainer.layer()->compositedLayerMapping() && !paintInvalidationContainer.layer()->groupedMapping())
        return false;

    // Get quads for node in absolute coordinates.
    Vector<FloatQuad> quads;
    computeQuads(*m_node, quads);
    DCHECK(quads.size());
    Path newPath;

    for (size_t quadIndex = 0; quadIndex < quads.size(); ++quadIndex) {
        FloatQuad absoluteQuad = quads[quadIndex];

        // Scrolling content layers have the same offset from layout object as the non-scrolling layers. Thus we need
        // to adjust for their scroll offset.
        if (m_isScrollingGraphicsLayer) {
            DoubleSize adjustedScrollOffset = paintInvalidationContainer.layer()->getScrollableArea()->adjustedScrollOffset();
            absoluteQuad.move(adjustedScrollOffset.width(), adjustedScrollOffset.height());
        }

        // Transform node quads in target absolute coords to local coordinates in the compositor layer.
        FloatQuad transformedQuad;
        convertTargetSpaceQuadToCompositedLayer(absoluteQuad, m_node->layoutObject(), paintInvalidationContainer, transformedQuad);

        // FIXME: for now, we'll only use rounded paths if we have a single node quad. The reason for this is that
        // we may sometimes get a chain of adjacent boxes (e.g. for text nodes) which end up looking like sausage
        // links: these should ideally be merged into a single rect before creating the path, but that's
        // another CL.
        if (quads.size() == 1 && transformedQuad.isRectilinear()
                && !m_owningWebViewImpl->settingsImpl()->mockGestureTapHighlightsEnabled()) {
            FloatSize rectRoundingRadii(3, 3);
            newPath.addRoundedRect(transformedQuad.boundingBox(), rectRoundingRadii);
        } else {
            addQuadToPath(transformedQuad, newPath);
        }
    }

    FloatRect boundingRect = newPath.boundingRect();
    newPath.translate(-toFloatSize(boundingRect.location()));

    bool pathHasChanged = !(newPath == m_path);
    if (pathHasChanged) {
        m_path = newPath;
        m_contentLayer->layer()->setBounds(enclosingIntRect(boundingRect).size());
    }

    m_contentLayer->layer()->setPosition(boundingRect.location());

    return pathHasChanged;
}
void SVGImage::draw(SkCanvas* canvas, const SkPaint& paint, const FloatRect& dstRect, const FloatRect& srcRect, RespectImageOrientationEnum, ImageClampingMode)
{
    if (!m_page)
        return;

    FrameView* view = frameView();
    view->resize(containerSize());

    // Always call processUrlFragment, even if the url is empty, because
    // there may have been a previous url/fragment that needs to be reset.
    view->processUrlFragment(m_url);

    SkPictureBuilder imagePicture(dstRect);
    {
        ClipRecorder clipRecorder(imagePicture.context(), *this, DisplayItem::ClipNodeImage, LayoutRect(enclosingIntRect(dstRect)));

        // We can only draw the entire frame, clipped to the rect we want. So compute where the top left
        // of the image would be if we were drawing without clipping, and translate accordingly.
        FloatSize scale(dstRect.width() / srcRect.width(), dstRect.height() / srcRect.height());
        FloatSize topLeftOffset(srcRect.location().x() * scale.width(), srcRect.location().y() * scale.height());
        FloatPoint destOffset = dstRect.location() - topLeftOffset;
        AffineTransform transform = AffineTransform::translation(destOffset.x(), destOffset.y());
        transform.scale(scale.width(), scale.height());
        TransformRecorder transformRecorder(imagePicture.context(), *this, transform);

        view->updateAllLifecyclePhases();
        view->paint(&imagePicture.context(), enclosingIntRect(srcRect));
        ASSERT(!view->needsLayout());
    }

    {
        SkAutoCanvasRestore ar(canvas, false);
        if (drawNeedsLayer(paint)) {
            SkRect layerRect = dstRect;
            canvas->saveLayer(&layerRect, &paint);
        }
        RefPtr<const SkPicture> recording = imagePicture.endRecording();
        canvas->drawPicture(recording.get());
    }

    if (imageObserver())
        imageObserver()->didDraw(this);

    // Start any (SMIL) animations if needed. This will restart or continue
    // animations if preceded by calls to resetAnimation or stopAnimation
    // respectively.
    startAnimation();
}
Example #4
0
bool LinkHighlight::computeHighlightLayerPathAndPosition(RenderLayer* compositingLayer)
{
    if (!m_node || !m_node->renderer() || !m_currentGraphicsLayer)
        return false;

    ASSERT(compositingLayer);

    // Get quads for node in absolute coordinates.
    Vector<FloatQuad> quads;
    computeQuads(m_node.get(), quads);
    ASSERT(quads.size());

    // Adjust for offset between target graphics layer and the node's renderer.
    FloatPoint positionAdjust = IntPoint(m_currentGraphicsLayer->offsetFromRenderer());

    Path newPath;
    for (size_t quadIndex = 0; quadIndex < quads.size(); ++quadIndex) {
        FloatQuad absoluteQuad = quads[quadIndex];
        absoluteQuad.move(-positionAdjust.x(), -positionAdjust.y());

        // Transform node quads in target absolute coords to local coordinates in the compositor layer.
        FloatQuad transformedQuad;
        convertTargetSpaceQuadToCompositedLayer(absoluteQuad, m_node->renderer(), compositingLayer->renderer(), transformedQuad);

        // FIXME: for now, we'll only use rounded paths if we have a single node quad. The reason for this is that
        // we may sometimes get a chain of adjacent boxes (e.g. for text nodes) which end up looking like sausage
        // links: these should ideally be merged into a single rect before creating the path, but that's
        // another CL.
        if (quads.size() == 1 && transformedQuad.isRectilinear()) {
            FloatSize rectRoundingRadii(3, 3);
            newPath.addRoundedRect(transformedQuad.boundingBox(), rectRoundingRadii);
        } else
            addQuadToPath(transformedQuad, newPath);
    }

    FloatRect boundingRect = newPath.boundingRect();
    newPath.translate(-toFloatSize(boundingRect.location()));

    bool pathHasChanged = !(newPath == m_path);
    if (pathHasChanged) {
        m_path = newPath;
        m_contentLayer->layer()->setBounds(enclosingIntRect(boundingRect).size());
    }

    m_contentLayer->layer()->setPosition(boundingRect.location());

    return pathHasChanged;
}
Example #5
0
void RenderEmbeddedObject::paintReplaced(const PaintInfo& paintInfo, const LayoutPoint& paintOffset)
{
    if (!showsUnavailablePluginIndicator())
        return;

    if (paintInfo.phase == PaintPhaseSelection)
        return;

    FloatRect contentRect;
    Path path;
    FloatRect replacementTextRect;
    Font font;
    TextRun run("");
    float textWidth;
    if (!getReplacementTextGeometry(paintOffset, contentRect, path, replacementTextRect, font, run, textWidth))
        return;

    GraphicsContext* context = paintInfo.context;
    GraphicsContextStateSaver stateSaver(*context);
    context->clip(contentRect);
    context->setAlphaAsFloat(replacementTextRoundedRectOpacity);
    context->setFillColor(Color::white);
    context->fillPath(path);

    const FontMetrics& fontMetrics = font.fontMetrics();
    float labelX = roundf(replacementTextRect.location().x() + (replacementTextRect.size().width() - textWidth) / 2);
    float labelY = roundf(replacementTextRect.location().y() + (replacementTextRect.size().height() - fontMetrics.height()) / 2 + fontMetrics.ascent());
    TextRunPaintInfo runInfo(run);
    runInfo.bounds = replacementTextRect;
    context->setAlphaAsFloat(replacementTextTextOpacity);
    context->setFillColor(Color::black);
    context->drawBidiText(font, runInfo, FloatPoint(labelX, labelY));
}
void WebInspectorClient::showPaintRect(const FloatRect& rect)
{
    if (!m_paintRectOverlay) {
        m_paintRectOverlay = PageOverlay::create(this, PageOverlay::OverlayType::Document);
        m_page->installPageOverlay(m_paintRectOverlay, PageOverlay::FadeMode::DoNotFade);
    }

    if (!m_paintIndicatorLayerClient)
        m_paintIndicatorLayerClient = std::make_unique<RepaintIndicatorLayerClient>(*this);

    std::unique_ptr<GraphicsLayer> paintLayer = GraphicsLayer::create(m_page->drawingArea()->graphicsLayerFactory(), *m_paintIndicatorLayerClient);
    
    paintLayer->setAnchorPoint(FloatPoint3D());
    paintLayer->setPosition(rect.location());
    paintLayer->setSize(rect.size());
    paintLayer->setBackgroundColor(Color(1.0f, 0.0f, 0.0f, 0.2f));

    KeyframeValueList fadeKeyframes(AnimatedPropertyOpacity);
    OwnPtr<AnimationValue> intialValue = FloatAnimationValue::create(0, 1);
    fadeKeyframes.insert(intialValue.release());

    OwnPtr<AnimationValue> finalValue = FloatAnimationValue::create(0.25, 0);
    fadeKeyframes.insert(finalValue.release());
    
    RefPtr<Animation> opacityAnimation = Animation::create();
    opacityAnimation->setDuration(0.25);

    paintLayer->addAnimation(fadeKeyframes, FloatSize(), opacityAnimation.get(), ASCIILiteral("opacity"), 0);
    
    m_paintRectLayers.add(paintLayer.get());

    GraphicsLayer* overlayRootLayer = m_paintRectOverlay->layer();
    overlayRootLayer->addChild(paintLayer.release());
}
void RotationViewportAnchor::computeOrigins(
    const FloatSize& innerSize,
    IntPoint& mainFrameOffset,
    FloatPoint& visualViewportOffset) const {
  IntSize outerSize = layoutViewport().visibleContentRect().size();

  // Compute the viewport origins in CSS pixels relative to the document.
  FloatSize absVisualViewportOffset = m_normalizedVisualViewportOffset;
  absVisualViewportOffset.scale(outerSize.width(), outerSize.height());

  FloatPoint innerOrigin = getInnerOrigin(innerSize);
  FloatPoint outerOrigin = innerOrigin - absVisualViewportOffset;

  IntRect outerRect = IntRect(flooredIntPoint(outerOrigin), outerSize);
  FloatRect innerRect = FloatRect(innerOrigin, innerSize);

  moveToEncloseRect(outerRect, innerRect);

  outerRect.setLocation(IntPoint(
      layoutViewport().clampScrollOffset(toIntSize(outerRect.location()))));

  moveIntoRect(innerRect, outerRect);

  mainFrameOffset = outerRect.location();
  visualViewportOffset =
      FloatPoint(innerRect.location() - outerRect.location());
}
void Image::drawTiled(GraphicsContext* ctxt, const FloatRect& destRect, const FloatPoint& srcPoint, const FloatSize& scaledTileSize, SkXfermode::Mode op, const IntSize& repeatSpacing)
{
    FloatSize intrinsicTileSize = size();
    if (hasRelativeWidth())
        intrinsicTileSize.setWidth(scaledTileSize.width());
    if (hasRelativeHeight())
        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();
}
static FloatRect toNormalizedRect(const FloatRect& absoluteRect, const RenderObject* renderer, const RenderBlock* container)
{
    ASSERT(renderer);

    ASSERT(container || renderer->isRenderView());
    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, 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 (renderer->style()->position() == FixedPosition && container->isRenderView())
        normalizedRect.move(-toRenderView(container)->frameView()->scrollOffsetForFixedPosition());

    normalizedRect.scale(1 / containerRect.width(), 1 / containerRect.height());
    return normalizedRect;
}
Example #10
0
void RenderEmbeddedObject::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
{
    if (!showsUnavailablePluginIndicator())
        return;

    if (paintInfo.phase == PaintPhaseSelection)
        return;

    GraphicsContext* context = paintInfo.context;
    if (context->paintingDisabled())
        return;

    FloatRect contentRect;
    Path path;
    FloatRect replacementTextRect;
    FloatRect arrowRect;
    Font font;
    TextRun run("");
    float textWidth;
    if (!getReplacementTextGeometry(paintOffset, contentRect, path, replacementTextRect, arrowRect, font, run, textWidth))
        return;

    GraphicsContextStateSaver stateSaver(*context);
    context->clip(contentRect);
    context->setAlpha(replacementTextRoundedRectOpacity);
    context->setFillColor(m_unavailablePluginIndicatorIsPressed ? replacementTextRoundedRectPressedColor() : replacementTextRoundedRectColor(), style()->colorSpace());
    context->fillPath(path);

    const FontMetrics& fontMetrics = font.fontMetrics();
    float labelX = roundf(replacementTextRect.location().x() + (replacementTextRect.size().width() - textWidth) / 2);
    float labelY = roundf(replacementTextRect.location().y() + (replacementTextRect.size().height() - fontMetrics.height()) / 2 + fontMetrics.ascent());
    context->setFillColor(replacementTextColor(), style()->colorSpace());
    context->drawBidiText(font, run, FloatPoint(labelX, labelY));
}
void SVGImagePainter::paint(const PaintInfo& paintInfo)
{
    if (paintInfo.phase != PaintPhaseForeground
        || m_layoutSVGImage.style()->visibility() == HIDDEN
        || !m_layoutSVGImage.imageResource()->hasImage())
        return;

    FloatRect boundingBox = m_layoutSVGImage.paintInvalidationRectInLocalCoordinates();
    if (!paintInfo.cullRect().intersectsCullRect(m_layoutSVGImage.localToParentTransform(), boundingBox))
        return;

    PaintInfo paintInfoBeforeFiltering(paintInfo);
    // Images cannot have children so do not call updateCullRect.
    TransformRecorder transformRecorder(paintInfoBeforeFiltering.context, m_layoutSVGImage, m_layoutSVGImage.localToParentTransform());
    {
        SVGPaintContext paintContext(m_layoutSVGImage, paintInfoBeforeFiltering);
        if (paintContext.applyClipMaskAndFilterIfNecessary() && !LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(paintContext.paintInfo().context, m_layoutSVGImage, paintContext.paintInfo().phase, LayoutPoint())) {
            LayoutObjectDrawingRecorder recorder(paintContext.paintInfo().context, m_layoutSVGImage, paintContext.paintInfo().phase, boundingBox, LayoutPoint());
            paintForeground(paintContext.paintInfo());
        }
    }

    if (m_layoutSVGImage.style()->outlineWidth()) {
        PaintInfo outlinePaintInfo(paintInfoBeforeFiltering);
        outlinePaintInfo.phase = PaintPhaseSelfOutlineOnly;
        ObjectPainter(m_layoutSVGImage).paintOutline(outlinePaintInfo, LayoutPoint(boundingBox.location()));
    }
}
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;
}
Example #13
0
void SVGImage::draw(GraphicsContext& context, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator compositeOp, BlendMode blendMode, ImageOrientationDescription)
{
    if (!m_page)
        return;

    FrameView* view = frameView();
    ASSERT(view);

    GraphicsContextStateSaver stateSaver(context);
    context.setCompositeOperation(compositeOp, blendMode);
    context.clip(enclosingIntRect(dstRect));

    float alpha = context.alpha();
    bool compositingRequiresTransparencyLayer = compositeOp != CompositeSourceOver || blendMode != BlendModeNormal || alpha < 1;
    if (compositingRequiresTransparencyLayer) {
        context.beginTransparencyLayer(alpha);
        context.setCompositeOperation(CompositeSourceOver, BlendModeNormal);
    }

    FloatSize scale(dstRect.width() / srcRect.width(), dstRect.height() / srcRect.height());
    
    // We can only draw the entire frame, clipped to the rect we want. So compute where the top left
    // of the image would be if we were drawing without clipping, and translate accordingly.
    FloatSize topLeftOffset(srcRect.location().x() * scale.width(), srcRect.location().y() * scale.height());
    FloatPoint destOffset = dstRect.location() - topLeftOffset;

    context.translate(destOffset.x(), destOffset.y());
    context.scale(scale);

    view->resize(containerSize());

    if (!m_url.isEmpty())
        view->scrollToFragment(m_url);
    
    if (view->needsLayout())
        view->layout();

    view->paint(context, intersection(context.clipBounds(), enclosingIntRect(srcRect)));

    if (compositingRequiresTransparencyLayer)
        context.endTransparencyLayer();

    stateSaver.restore();

    if (imageObserver())
        imageObserver()->didDraw(this);
}
Example #14
0
void RenderEmbeddedObject::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
{
    if (!showsUnavailablePluginIndicator())
        return;

    if (paintInfo.phase == PaintPhaseSelection)
        return;

    GraphicsContext* context = paintInfo.context;
    if (context->paintingDisabled())
        return;

    FloatRect contentRect;
    FloatRect indicatorRect;
    FloatRect replacementTextRect;
    FloatRect arrowRect;
    Font font;
    TextRun run("");
    float textWidth;
    if (!getReplacementTextGeometry(paintOffset, contentRect, indicatorRect, replacementTextRect, arrowRect, font, run, textWidth))
        return;

    Path background;
    background.addRoundedRect(indicatorRect, FloatSize(replacementTextRoundedRectRadius, replacementTextRoundedRectRadius));

    GraphicsContextStateSaver stateSaver(*context);
    context->clip(contentRect);
    context->setFillColor(m_unavailablePluginIndicatorIsPressed ? replacementTextRoundedRectPressedColor() : replacementTextRoundedRectColor(), style()->colorSpace());
    context->fillPath(background);

    Path strokePath;
    FloatRect strokeRect(indicatorRect);
    strokeRect.inflate(1);
    strokePath.addRoundedRect(strokeRect, FloatSize(replacementTextRoundedRectRadius + 1, replacementTextRoundedRectRadius + 1));

    context->setStrokeColor(unavailablePluginBorderColor(), style()->colorSpace());
    context->setStrokeThickness(2);
    context->strokePath(strokePath);

    const FontMetrics& fontMetrics = font.fontMetrics();
    float labelX = roundf(replacementTextRect.location().x() + replacementTextRoundedRectLeftTextMargin);
    float labelY = roundf(replacementTextRect.location().y() + (replacementTextRect.size().height() - fontMetrics.height()) / 2 + fontMetrics.ascent() + replacementTextRoundedRectTopTextMargin);
    context->setFillColor(replacementTextColor(), style()->colorSpace());
    context->drawBidiText(font, run, FloatPoint(labelX, labelY));

    if (shouldUnavailablePluginMessageBeButton(document(), m_pluginUnavailabilityReason)) {
        arrowRect.inflate(-replacementArrowCirclePadding);

        context->beginTransparencyLayer(1.0);
        context->setFillColor(replacementTextColor(), style()->colorSpace());
        context->fillEllipse(arrowRect);

        context->setCompositeOperation(CompositeClear);
        drawReplacementArrow(context, arrowRect);
        context->endTransparencyLayer();
    }
}
Example #15
0
void SVGImage::draw(GraphicsContext* context, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator compositeOp, blink::WebBlendMode blendMode)
{
    if (!m_page)
        return;

    GraphicsContextStateSaver stateSaver(*context);
    context->setCompositeOperation(compositeOp, blendMode);
    context->clip(enclosingIntRect(dstRect));

    bool compositingRequiresTransparencyLayer = compositeOp != CompositeSourceOver || blendMode != blink::WebBlendModeNormal;
    float opacity = context->getNormalizedAlpha() / 255.f;
    bool requiresTransparencyLayer = compositingRequiresTransparencyLayer || opacity < 1;
    if (requiresTransparencyLayer) {
        context->beginTransparencyLayer(opacity);
        if (compositingRequiresTransparencyLayer)
            context->setCompositeOperation(CompositeSourceOver, blink::WebBlendModeNormal);
    }

    FloatSize scale(dstRect.width() / srcRect.width(), dstRect.height() / srcRect.height());

    // We can only draw the entire frame, clipped to the rect we want. So compute where the top left
    // of the image would be if we were drawing without clipping, and translate accordingly.
    FloatSize topLeftOffset(srcRect.location().x() * scale.width(), srcRect.location().y() * scale.height());
    FloatPoint destOffset = dstRect.location() - topLeftOffset;

    context->translate(destOffset.x(), destOffset.y());
    context->scale(scale);

    FrameView* view = frameView();
    view->resize(containerSize());

    if (view->needsLayout())
        view->layout();

    view->paint(context, enclosingIntRect(srcRect));

    if (requiresTransparencyLayer)
        context->endLayer();

    stateSaver.restore();

    if (imageObserver())
        imageObserver()->didDraw(this);
}
Example #16
0
FloatRect PinchViewport::visibleRectInDocument() const
{
    if (!mainFrame() || !mainFrame()->view())
        return FloatRect();

    FloatRect viewRect = mainFrame()->view()->visibleContentRect();
    FloatRect pinchRect = visibleRect();
    pinchRect.moveBy(viewRect.location());
    return pinchRect;
}
Example #17
0
void ImageBitmap::adjustDrawRects(FloatRect* srcRect, FloatRect* dstRect) const
{
    FloatRect intersectRect = intersection(m_bitmapRect, *srcRect);
    FloatRect newSrcRect = intersectRect;
    newSrcRect.move(m_bitmapOffset - m_bitmapRect.location());
    FloatRect newDstRect(FloatPoint(intersectRect.location() - srcRect->location()), m_bitmapRect.size());
    newDstRect.scale(dstRect->width() / srcRect->width() * intersectRect.width() / m_bitmapRect.width(),
        dstRect->height() / srcRect->height() * intersectRect.height() / m_bitmapRect.height());
    newDstRect.moveBy(dstRect->location());
    *srcRect = newSrcRect;
    *dstRect = newDstRect;
}
void CoordinatedGraphicsScene::paintToCurrentGLContext(const TransformationMatrix& matrix, float opacity, const FloatRect& clipRect, const Color& backgroundColor, bool drawsBackground, const FloatPoint& contentPosition, TextureMapper::PaintFlags PaintFlags)
{
    if (!m_textureMapper) {
        m_textureMapper = TextureMapper::create();
        static_cast<TextureMapperGL*>(m_textureMapper.get())->setEnableEdgeDistanceAntialiasing(true);
    }

    syncRemoteContent();

    adjustPositionForFixedLayers(contentPosition);
    TextureMapperLayer* currentRootLayer = rootLayer();
    if (!currentRootLayer)
        return;

#if USE(COORDINATED_GRAPHICS_THREADED)
    for (auto& proxy : m_platformLayerProxies.values())
        proxy->swapBuffer();
#endif

    currentRootLayer->setTextureMapper(m_textureMapper.get());
    currentRootLayer->applyAnimationsRecursively();
    m_textureMapper->beginPainting(PaintFlags);
    m_textureMapper->beginClip(TransformationMatrix(), clipRect);

    if (drawsBackground) {
        RGBA32 rgba = makeRGBA32FromFloats(backgroundColor.red(),
                                           backgroundColor.green(), backgroundColor.blue(),
                                           backgroundColor.alpha() * opacity);
        m_textureMapper->drawSolidColor(clipRect, TransformationMatrix(), Color(rgba));
    } else {
        GraphicsContext3D* context = static_cast<TextureMapperGL*>(m_textureMapper.get())->graphicsContext3D();
        context->clearColor(m_viewBackgroundColor.red() / 255.0f, m_viewBackgroundColor.green() / 255.0f, m_viewBackgroundColor.blue() / 255.0f, m_viewBackgroundColor.alpha() / 255.0f);
        context->clear(GraphicsContext3D::COLOR_BUFFER_BIT);
    }

    if (currentRootLayer->opacity() != opacity || currentRootLayer->transform() != matrix) {
        currentRootLayer->setOpacity(opacity);
        currentRootLayer->setTransform(matrix);
    }

    currentRootLayer->paint();
    m_fpsCounter.updateFPSAndDisplay(*m_textureMapper, clipRect.location(), matrix);
    m_textureMapper->endClip();
    m_textureMapper->endPainting();

    if (currentRootLayer->descendantsOrSelfHaveRunningAnimations()) {
        RefPtr<CoordinatedGraphicsScene> protector(this);
        dispatchOnClientRunLoop([=] {
            protector->updateViewport();
        });
    }
}
Example #19
0
void SVGImage::draw(GraphicsContext* context, const FloatRect& dstRect, const FloatRect& srcRect, ColorSpace, CompositeOperator compositeOp, BlendMode)
{
    if (!m_page)
        return;

    FrameView* view = frameView();

    GraphicsContextStateSaver stateSaver(*context);
    context->setCompositeOperation(compositeOp);
    context->clip(enclosingIntRect(dstRect));
    if (compositeOp != CompositeSourceOver)
        context->beginTransparencyLayer(1);

    FloatSize scale(dstRect.width() / srcRect.width(), dstRect.height() / srcRect.height());

    // We can only draw the entire frame, clipped to the rect we want. So compute where the top left
    // of the image would be if we were drawing without clipping, and translate accordingly.
    FloatSize topLeftOffset(srcRect.location().x() * scale.width(), srcRect.location().y() * scale.height());
    FloatPoint destOffset = dstRect.location() - topLeftOffset;

    context->translate(destOffset.x(), destOffset.y());
    context->scale(scale);

    view->resize(containerSize());

    if (view->needsLayout())
        view->layout();

    view->paint(context, IntRect(0, 0, view->width(), view->height()));

    if (compositeOp != CompositeSourceOver)
        context->endTransparencyLayer();

    stateSaver.restore();

    if (imageObserver())
        imageObserver()->didDraw(this);
}
void CoordinatedLayerTreeHostProxy::setVisibleContentsRect(const FloatRect& rect, const FloatPoint& trajectoryVector)
{
    // Inform the renderer to adjust viewport-fixed layers.
    RefPtr<CoordinatedGraphicsScene> sceneProtector(m_scene);
    const FloatPoint& scrollPosition = rect.location();
    dispatchUpdate([=] {
        sceneProtector->setScrollPosition(scrollPosition);
    });

    if (rect == m_lastSentVisibleRect && trajectoryVector == m_lastSentTrajectoryVector)
        return;

    m_drawingAreaProxy->page()->process().send(Messages::CoordinatedLayerTreeHost::SetVisibleContentsRect(rect, trajectoryVector), m_drawingAreaProxy->page()->pageID());
    m_lastSentVisibleRect = rect;
    m_lastSentTrajectoryVector = trajectoryVector;
}
Example #21
0
FloatRect AffineTransform::mapRect(const FloatRect& rect) const
{
    if (isIdentityOrTranslation()) {
        if (!m_transform[4] && !m_transform[5])
            return rect;

        FloatRect mappedRect(rect);
        mappedRect.move(narrowPrecisionToFloat(m_transform[4]), narrowPrecisionToFloat(m_transform[5]));
        return mappedRect;
    }

    FloatQuad result;
    result.setP1(mapPoint(rect.location()));
    result.setP2(mapPoint(FloatPoint(rect.maxX(), rect.y())));
    result.setP3(mapPoint(FloatPoint(rect.maxX(), rect.maxY())));
    result.setP4(mapPoint(FloatPoint(rect.x(), rect.maxY())));
    return result.boundingBox();
}
Example #22
0
void Image::drawTiled(GraphicsContext* ctxt, const FloatRect& destRect, const FloatPoint& srcPoint, const FloatSize& scaledTileSize, ColorSpace styleColorSpace, CompositeOperator op)
{    
    if (mayFillWithSolidColor()) {
        fillWithSolidColor(ctxt, destRect, solidColor(), styleColorSpace, op);
        return;
    }

    // See <https://webkit.org/b/59043>.
#if !PLATFORM(WX)
    ASSERT(!isBitmapImage() || notSolidColor());
#endif

    FloatSize intrinsicTileSize = size();
    if (hasRelativeWidth())
        intrinsicTileSize.setWidth(scaledTileSize.width());
    if (hasRelativeHeight())
        intrinsicTileSize.setHeight(scaledTileSize.height());

    FloatSize scale(scaledTileSize.width() / intrinsicTileSize.width(),
                    scaledTileSize.height() / intrinsicTileSize.height());

    FloatRect oneTileRect;
    oneTileRect.setX(destRect.x() + fmodf(fmodf(-srcPoint.x(), scaledTileSize.width()) - scaledTileSize.width(), scaledTileSize.width()));
    oneTileRect.setY(destRect.y() + fmodf(fmodf(-srcPoint.y(), scaledTileSize.height()) - scaledTileSize.height(), scaledTileSize.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());
        draw(ctxt, destRect, visibleSrcRect, styleColorSpace, op);
        return;
    }

    AffineTransform patternTransform = AffineTransform().scaleNonUniform(scale.width(), scale.height());
    FloatRect tileRect(FloatPoint(), intrinsicTileSize);    
    drawPattern(ctxt, tileRect, patternTransform, oneTileRect.location(), styleColorSpace, op, destRect);
    
    startAnimation();
}
Example #23
0
void CoordinatedGraphicsLayer::computePixelAlignment(FloatPoint& position, FloatSize& size, FloatPoint3D& anchorPoint, FloatSize& alignmentOffset)
{
    if (isIntegral(effectiveContentsScale())) {
        position = m_position;
        size = m_size;
        anchorPoint = m_anchorPoint;
        alignmentOffset = FloatSize();
        return;
    }

    FloatPoint positionRelativeToBase = computePositionRelativeToBase();

    FloatRect baseRelativeBounds(positionRelativeToBase, m_size);
    FloatRect scaledBounds = baseRelativeBounds;

    // Scale by the effective scale factor to compute the screen-relative bounds.
    scaledBounds.scale(effectiveContentsScale());

    // Round to integer boundaries.
    // NOTE: When using enclosingIntRect (as mac) it will have different sizes depending on position.
    FloatRect alignedBounds = roundedIntRect(scaledBounds);

    // Convert back to layer coordinates.
    alignedBounds.scale(1 / effectiveContentsScale());

    // Convert back to layer coordinates.
    alignmentOffset = baseRelativeBounds.location() - alignedBounds.location();

    position = m_position - alignmentOffset;
    size = alignedBounds.size();

    // Now we have to compute a new anchor point which compensates for rounding.
    float anchorPointX = m_anchorPoint.x();
    float anchorPointY = m_anchorPoint.y();

    if (alignedBounds.width())
        anchorPointX = (baseRelativeBounds.width() * anchorPointX + alignmentOffset.width()) / alignedBounds.width();

    if (alignedBounds.height())
        anchorPointY = (baseRelativeBounds.height() * anchorPointY + alignmentOffset.height()) / alignedBounds.height();

    anchorPoint = FloatPoint3D(anchorPointX, anchorPointY, m_anchorPoint.z() * effectiveContentsScale());
}
Example #24
0
FloatRect findInPageRectFromAbsoluteRect(const FloatRect& inputRect, const RenderObject* renderer)
{
    if (!renderer || inputRect.isEmpty())
        return FloatRect();

    // Normalize the input rect to its container, saving the container bounding box for the incoming loop.
    FloatRect rendererBoundingBox;
    FloatRect normalizedRect = toNormalizedRect(inputRect, renderer, rendererBoundingBox);
    renderer = renderer->container();

    // Go up across frames.
    while (renderer) {

        // Go up the render tree until we reach the root of the current frame (the RenderView).
        for (const RenderObject* container = renderer->container(); container; renderer = container, container = container->container()) {

            // Compose the normalized rects. The absolute bounding box of the container is calculated in toNormalizedRect
            // and can be reused for the next iteration of the loop.
            FloatRect normalizedBoxRect = toNormalizedRect(rendererBoundingBox, renderer, rendererBoundingBox);
            normalizedRect.scale(normalizedBoxRect.width(), normalizedBoxRect.height());
            normalizedRect.moveBy(normalizedBoxRect.location());

            if (normalizedRect.isEmpty())
                return normalizedRect;
        }

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

        // Update the absolute coordinates to the new frame.
        if (renderer)
            rendererBoundingBox = renderer->absoluteBoundingBoxRect();
    }

    return normalizedRect;
}
void SVGShapePainter::paint(const PaintInfo& paintInfo)
{
    if (paintInfo.phase != PaintPhaseForeground
        || m_layoutSVGShape.style()->visibility() == HIDDEN
        || m_layoutSVGShape.isShapeEmpty())
        return;

    FloatRect boundingBox = m_layoutSVGShape.paintInvalidationRectInLocalCoordinates();
    if (!paintInfo.cullRect().intersectsCullRect(m_layoutSVGShape.localTransform(), boundingBox))
        return;

    PaintInfo paintInfoBeforeFiltering(paintInfo);
    // Shapes cannot have children so do not call updateCullRect.
    TransformRecorder transformRecorder(paintInfoBeforeFiltering.context, m_layoutSVGShape, m_layoutSVGShape.localTransform());
    {
        SVGPaintContext paintContext(m_layoutSVGShape, paintInfoBeforeFiltering);
        if (paintContext.applyClipMaskAndFilterIfNecessary() && !LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(paintContext.paintInfo().context, m_layoutSVGShape, paintContext.paintInfo().phase, LayoutPoint())) {
            LayoutObjectDrawingRecorder recorder(paintContext.paintInfo().context, m_layoutSVGShape, paintContext.paintInfo().phase, boundingBox, LayoutPoint());
            const SVGComputedStyle& svgStyle = m_layoutSVGShape.style()->svgStyle();

            bool shouldAntiAlias = svgStyle.shapeRendering() != SR_CRISPEDGES;

            for (int i = 0; i < 3; i++) {
                switch (svgStyle.paintOrderType(i)) {
                case PT_FILL: {
                    SkPaint fillPaint;
                    if (!SVGPaintContext::paintForLayoutObject(paintContext.paintInfo(), m_layoutSVGShape.styleRef(), m_layoutSVGShape, ApplyToFillMode, fillPaint))
                        break;
                    fillPaint.setAntiAlias(shouldAntiAlias);
                    fillShape(paintContext.paintInfo().context, fillPaint, fillRuleFromStyle(paintContext.paintInfo(), svgStyle));
                    break;
                }
                case PT_STROKE:
                    if (svgStyle.hasVisibleStroke()) {
                        GraphicsContextStateSaver stateSaver(paintContext.paintInfo().context, false);
                        AffineTransform nonScalingTransform;
                        const AffineTransform* additionalPaintServerTransform = 0;

                        if (m_layoutSVGShape.hasNonScalingStroke()) {
                            nonScalingTransform = m_layoutSVGShape.nonScalingStrokeTransform();
                            if (!setupNonScalingStrokeContext(nonScalingTransform, stateSaver))
                                return;

                            // Non-scaling stroke needs to reset the transform back to the host transform.
                            additionalPaintServerTransform = &nonScalingTransform;
                        }

                        SkPaint strokePaint;
                        if (!SVGPaintContext::paintForLayoutObject(paintContext.paintInfo(), m_layoutSVGShape.styleRef(), m_layoutSVGShape, ApplyToStrokeMode, strokePaint, additionalPaintServerTransform))
                            break;
                        strokePaint.setAntiAlias(shouldAntiAlias);

                        StrokeData strokeData;
                        SVGLayoutSupport::applyStrokeStyleToStrokeData(strokeData, m_layoutSVGShape.styleRef(), m_layoutSVGShape, m_layoutSVGShape.dashScaleFactor());
                        strokeData.setupPaint(&strokePaint);

                        strokeShape(paintContext.paintInfo().context, strokePaint);
                    }
                    break;
                case PT_MARKERS:
                    paintMarkers(paintContext.paintInfo(), boundingBox);
                    break;
                default:
                    ASSERT_NOT_REACHED();
                    break;
                }
            }
        }
    }

    if (m_layoutSVGShape.style()->outlineWidth()) {
        PaintInfo outlinePaintInfo(paintInfoBeforeFiltering);
        outlinePaintInfo.phase = PaintPhaseSelfOutlineOnly;
        ObjectPainter(m_layoutSVGShape).paintOutline(outlinePaintInfo, LayoutPoint(boundingBox.location()));
    }
}
void RenderSVGResourceMasker::createMaskImage(MaskerData* maskerData, const SVGMaskElement* maskElement, RenderObject* object)
{
    FloatRect objectBoundingBox = object->objectBoundingBox();

    // Mask rect clipped with clippingBoundingBox and filterBoundingBox as long as they are present.
    maskerData->maskRect = object->repaintRectInLocalCoordinates();
    if (maskerData->maskRect.isEmpty()) {
        maskerData->emptyMask = true;
        return;
    }
    
    if (m_maskBoundaries.isEmpty())
        calculateMaskContentRepaintRect();

    FloatRect repaintRect = m_maskBoundaries;
    AffineTransform contextTransform;
    // We need to scale repaintRect for objectBoundingBox to get the drawing area.
    if (maskElement->maskContentUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
        contextTransform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height());
        FloatPoint contextAdjustment = repaintRect.location();
        repaintRect = contextTransform.mapRect(repaintRect);
        repaintRect.move(objectBoundingBox.x(), objectBoundingBox.y());
        contextTransform.translate(-contextAdjustment.x(), -contextAdjustment.y());
    }
    repaintRect.intersect(maskerData->maskRect);
    maskerData->maskRect = repaintRect;
    IntRect maskImageRect = enclosingIntRect(maskerData->maskRect);

    maskImageRect.setLocation(IntPoint());

    // Don't create ImageBuffers with image size of 0
    if (maskImageRect.isEmpty()) {
        maskerData->emptyMask = true;
        return;
    }

    // FIXME: This changes color space to linearRGB, the default color space
    // for masking operations in SVG. We need a switch for the other color-space
    // attribute values sRGB, inherit and auto.
    maskerData->maskImage = ImageBuffer::create(maskImageRect.size(), LinearRGB);
    if (!maskerData->maskImage)
        return;

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

    maskImageContext->save();

    if (maskElement->maskContentUnits() == SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE)
        maskImageContext->translate(-maskerData->maskRect.x(), -maskerData->maskRect.y());
    maskImageContext->concatCTM(contextTransform);

    // draw the content into the ImageBuffer
    for (Node* node = maskElement->firstChild(); node; node = node->nextSibling()) {
        RenderObject* renderer = node->renderer();
        if (!node->isSVGElement() || !static_cast<SVGElement*>(node)->isStyled() || !renderer)
            continue;
        RenderStyle* style = renderer->style();
        if (!style || style->display() == NONE || style->visibility() != VISIBLE)
            continue;
        renderSubtreeToImage(maskerData->maskImage.get(), renderer);
    }

    maskImageContext->restore();

    // create the luminance mask
    RefPtr<ImageData> imageData(maskerData->maskImage->getUnmultipliedImageData(maskImageRect));
    CanvasPixelArray* srcPixelArray(imageData->data());

    for (unsigned pixelOffset = 0; pixelOffset < srcPixelArray->length(); pixelOffset += 4) {
        unsigned char a = srcPixelArray->get(pixelOffset + 3);
        if (!a)
            continue;
        unsigned char r = srcPixelArray->get(pixelOffset);
        unsigned char g = srcPixelArray->get(pixelOffset + 1);
        unsigned char b = srcPixelArray->get(pixelOffset + 2);

        double luma = (r * 0.2125 + g * 0.7154 + b * 0.0721) * ((double)a / 255.0);
        srcPixelArray->set(pixelOffset + 3, luma);
    }

    maskerData->maskImage->putUnmultipliedImageData(imageData.get(), maskImageRect, IntPoint());
}
bool RenderEmbeddedObject::getReplacementTextGeometry(const LayoutPoint& accumulatedOffset, FloatRect& contentRect, Path& path, FloatRect& replacementTextRect, Font& font, TextRun& run, float& textWidth) const
{
    contentRect = contentBoxRect();
    contentRect.moveBy(roundedIntPoint(accumulatedOffset));

    FontDescription fontDescription;
    RenderTheme::theme().systemFont(CSSValueWebkitSmallControl, fontDescription);
    fontDescription.setWeight(FontWeightBold);
    Settings* settings = document().settings();
    ASSERT(settings);
    if (!settings)
        return false;
    fontDescription.setComputedSize(fontDescription.specifiedSize());
    font = Font(fontDescription, 0, 0);
    font.update(0);

    run = TextRun(m_unavailablePluginReplacementText);
    textWidth = font.width(run);

    replacementTextRect.setSize(FloatSize(textWidth + replacementTextRoundedRectLeftRightTextMargin * 2, replacementTextRoundedRectHeight));
    float x = (contentRect.size().width() / 2 - replacementTextRect.size().width() / 2) + contentRect.location().x();
    float y = (contentRect.size().height() / 2 - replacementTextRect.size().height() / 2) + contentRect.location().y();
    replacementTextRect.setLocation(FloatPoint(x, y));

    path.addRoundedRect(replacementTextRect, FloatSize(replacementTextRoundedRectRadius, replacementTextRoundedRectRadius));

    return true;
}
IntRect HTMLCanvasElement::convertLogicalToDevice(const FloatRect& logicalRect) const
{
    return IntRect(convertLogicalToDevice(logicalRect.location()), convertLogicalToDevice(logicalRect.size()));
}
Example #29
0
IntRect CanvasSurface::convertLogicalToDevice(const FloatRect& logicalRect) const
{
    return IntRect(convertLogicalToDevice(logicalRect.location()), convertLogicalToDevice(logicalRect.size()));
}
Example #30
0
bool RenderEmbeddedObject::getReplacementTextGeometry(const LayoutPoint& accumulatedOffset, FloatRect& contentRect, Path& path, FloatRect& replacementTextRect, FloatRect& arrowRect, Font& font, TextRun& run, float& textWidth) const
{
    contentRect = contentBoxRect();
    contentRect.moveBy(roundedIntPoint(accumulatedOffset));

    FontDescription fontDescription;
    RenderTheme::defaultTheme()->systemFont(CSSValueWebkitSmallControl, fontDescription);
    fontDescription.setWeight(FontWeightBold);
    Settings* settings = document()->settings();
    ASSERT(settings);
    if (!settings)
        return false;
    fontDescription.setRenderingMode(settings->fontRenderingMode());
    fontDescription.setComputedSize(fontDescription.specifiedSize());
    font = Font(fontDescription, 0, 0);
    font.update(0);

    run = TextRun(m_unavailablePluginReplacementText);
    textWidth = font.width(run);

    replacementTextRect.setSize(FloatSize(textWidth + replacementTextRoundedRectLeftRightTextMargin * 2, replacementTextRoundedRectHeight));
    float x = (contentRect.size().width() / 2 - replacementTextRect.size().width() / 2) + contentRect.location().x();
    float y = (contentRect.size().height() / 2 - replacementTextRect.size().height() / 2) + contentRect.location().y();
    replacementTextRect.setLocation(FloatPoint(x, y));

    replacementTextRect.setHeight(replacementTextRect.height() + replacementTextRoundedRectBottomTextPadding);

    path.addRoundedRect(replacementTextRect, FloatSize(replacementTextRoundedRectRadius, replacementTextRoundedRectRadius));

    if (shouldUnavailablePluginMessageBeButton(document(), m_pluginUnavailabilityReason)) {
        arrowRect = path.boundingRect();
        arrowRect.setX(arrowRect.maxX() + replacementArrowLeftMargin);
        arrowRect.setWidth(arrowRect.height());
        path.addEllipse(arrowRect);
        addReplacementArrowPath(path, arrowRect);
    }

    return true;
}