Example #1
0
bool SVGRenderSupport::updateGraphicsContext(const PaintInfo& paintInfo, GraphicsContextStateSaver& stateSaver, RenderStyle* style, RenderObject& renderer, RenderSVGResourceMode resourceMode, const AffineTransform* additionalPaintServerTransform)
{
    ASSERT(style);
    ASSERT(paintInfo.context == stateSaver.context());

    GraphicsContext* context = paintInfo.context;
    if (paintInfo.isRenderingClipPathAsMaskImage()) {
        if (resourceMode == ApplyToStrokeMode)
            return false;
        context->setAlphaAsFloat(1);
        context->setFillColor(SVGRenderStyle::initialFillPaintColor());
        return true;
    }

    SVGPaintServer paintServer = SVGPaintServer::requestForRenderer(renderer, style, resourceMode);
    if (!paintServer.isValid())
        return false;

    if (additionalPaintServerTransform && paintServer.isTransformDependent())
        paintServer.prependTransform(*additionalPaintServerTransform);

    paintServer.apply(*context, resourceMode, &stateSaver);

    const SVGRenderStyle& svgStyle = style->svgStyle();

    if (resourceMode == ApplyToFillMode) {
        context->setAlphaAsFloat(svgStyle.fillOpacity());
        context->setFillRule(svgStyle.fillRule());
    } else {
        context->setAlphaAsFloat(svgStyle.strokeOpacity());
        applyStrokeStyleToContext(context, style, &renderer);
    }
    return true;
}
bool SVGLayoutSupport::updateGraphicsContext(const PaintInfo& paintInfo, GraphicsContextStateSaver& stateSaver, const ComputedStyle& style, LayoutObject& layoutObject, LayoutSVGResourceMode resourceMode, const AffineTransform* additionalPaintServerTransform)
{
    ASSERT(paintInfo.context == stateSaver.context());

    GraphicsContext& context = *paintInfo.context;
    if (paintInfo.isRenderingClipPathAsMaskImage()) {
        if (resourceMode == ApplyToStrokeMode)
            return false;
        context.setFillColor(SVGComputedStyle::initialFillPaintColor());
        return true;
    }

    SVGPaintServer paintServer = SVGPaintServer::requestForLayoutObject(layoutObject, style, resourceMode);
    if (!paintServer.isValid())
        return false;

    if (additionalPaintServerTransform && paintServer.isTransformDependent())
        paintServer.prependTransform(*additionalPaintServerTransform);

    const SVGComputedStyle& svgStyle = style.svgStyle();
    float paintAlpha = resourceMode == ApplyToFillMode ? svgStyle.fillOpacity() : svgStyle.strokeOpacity();
    paintServer.apply(context, resourceMode, paintAlpha, stateSaver);

    if (resourceMode == ApplyToFillMode)
        context.setFillRule(svgStyle.fillRule());
    else
        applyStrokeStyleToContext(context, style, layoutObject);

    return true;
}
SVGPaintServer* KSVGPainterFactory::strokePaintServer(const RenderStyle* style, const RenderObject* item)
{
    if (!style->svgStyle()->hasStroke())
        return 0;

    SVGPaint* stroke = style->svgStyle()->strokePaint();

    SVGPaintServer* strokePaintServer = 0;
    if (stroke->paintType() == SVGPaint::SVG_PAINTTYPE_URI) {
        AtomicString id(SVGURIReference::getTarget(stroke->uri()));
        strokePaintServer = getPaintServerById(item->document(), id);

        SVGElement* svgElement = static_cast<SVGElement*>(item->element());
        ASSERT(svgElement && svgElement->document() && svgElement->isStyled());
 
        if (item->isRenderPath() && strokePaintServer)
            strokePaintServer->addClient(static_cast<SVGStyledElement*>(svgElement));
        else if (!strokePaintServer)
            svgElement->document()->accessSVGExtensions()->addPendingResource(id, static_cast<SVGStyledElement*>(svgElement)); 
    } else {
        strokePaintServer = sharedSolidPaintServer();
        SVGPaintServerSolid* strokePaintServerSolid = static_cast<SVGPaintServerSolid*>(strokePaintServer);
        if (stroke->paintType() == SVGPaint::SVG_PAINTTYPE_CURRENTCOLOR)
            strokePaintServerSolid->setColor(style->color());
        else
            strokePaintServerSolid->setColor(stroke->color());
        // FIXME: Ideally invalid colors would never get set on the RenderStyle and this could turn into an ASSERT
        if (!strokePaintServerSolid->color().isValid())
            strokePaintServer = 0;
    }

    return strokePaintServer;
}
SVGPaintServer SVGPaintServer::requestForLayoutObject(const LayoutObject& layoutObject, const ComputedStyle& style, LayoutSVGResourceMode resourceMode)
{
    ASSERT(resourceMode == ApplyToFillMode || resourceMode == ApplyToStrokeMode);

    SVGPaintDescription paintDescription = requestPaint(layoutObject, style, resourceMode);
    if (!paintDescription.isValid)
        return invalid();
    if (!paintDescription.resource)
        return SVGPaintServer(paintDescription.color);
    SVGPaintServer paintServer = paintDescription.resource->preparePaintServer(layoutObject);
    if (paintServer.isValid())
        return paintServer;
    if (paintDescription.hasFallback)
        return SVGPaintServer(paintDescription.color);
    return invalid();
}
Example #5
0
static inline void fillAndStrokePath(const Path& path, GraphicsContext* context, RenderStyle* style, RenderPath* object)
{
    context->beginPath();

    SVGPaintServer* fillPaintServer = SVGPaintServer::fillPaintServer(style, object);
    if (fillPaintServer) {
        context->addPath(path);
        fillPaintServer->draw(context, object, ApplyToFillTargetType);
    }
    
    SVGPaintServer* strokePaintServer = SVGPaintServer::strokePaintServer(style, object);
    if (strokePaintServer) {
        context->addPath(path); // path is cleared when filled.
        strokePaintServer->draw(context, object, ApplyToStrokeTargetType);
    }
}
Example #6
0
bool SVGPaintContext::paintForLayoutObject(
    const PaintInfo& paintInfo,
    const ComputedStyle& style,
    const LayoutObject& layoutObject,
    LayoutSVGResourceMode resourceMode,
    SkPaint& paint,
    const AffineTransform* additionalPaintServerTransform) {
  if (paintInfo.isRenderingClipPathAsMaskImage()) {
    if (resourceMode == ApplyToStrokeMode)
      return false;
    paint.setColor(SVGComputedStyle::initialFillPaintColor().rgb());
    paint.setShader(nullptr);
    return true;
  }

  SVGPaintServer paintServer =
      SVGPaintServer::requestForLayoutObject(layoutObject, style, resourceMode);
  if (!paintServer.isValid())
    return false;

  if (additionalPaintServerTransform && paintServer.isTransformDependent())
    paintServer.prependTransform(*additionalPaintServerTransform);

  const SVGComputedStyle& svgStyle = style.svgStyle();
  float paintAlpha = resourceMode == ApplyToFillMode ? svgStyle.fillOpacity()
                                                     : svgStyle.strokeOpacity();
  paintServer.applyToSkPaint(paint, paintAlpha);

  // We always set filter quality to 'low' here. This value will only have an
  // effect for patterns, which are SkPictures, so using high-order filter
  // should have little effect on the overall quality.
  paint.setFilterQuality(kLow_SkFilterQuality);

  // TODO(fs): The color filter can set when generating a picture for a mask -
  // due to color-interpolation. We could also just apply the
  // color-interpolation property from the the shape itself (which could mean
  // the paintserver if it has it specified), since that would be more in line
  // with the spec for color-interpolation. For now, just steal it from the GC
  // though.
  // Additionally, it's not really safe/guaranteed to be correct, as
  // something down the paint pipe may want to farther tweak the color
  // filter, which could yield incorrect results. (Consider just using
  // saveLayer() w/ this color filter explicitly instead.)
  paint.setColorFilter(sk_ref_sp(paintInfo.context.getColorFilter()));
  return true;
}
Example #7
0
SVGPaintServer* SVGPaintServer::fillPaintServer(const RenderStyle* style, const RenderObject* item)
{
    if (!style->svgStyle()->hasFill())
        return 0;

    SVGPaint* fill = style->svgStyle()->fillPaint();

    SVGPaintServer* fillPaintServer = 0;
    SVGPaint::SVGPaintType paintType = fill->paintType();
    if (paintType == SVGPaint::SVG_PAINTTYPE_URI ||
        paintType == SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR) {
        AtomicString id(SVGURIReference::getTarget(fill->uri()));
        fillPaintServer = getPaintServerById(item->document(), id);

        SVGElement* svgElement = static_cast<SVGElement*>(item->node());
        ASSERT(svgElement && svgElement->document() && svgElement->isStyled());

        if (item->isRenderPath() && fillPaintServer)
            fillPaintServer->addClient(static_cast<SVGStyledElement*>(svgElement));
        else if (!fillPaintServer && paintType == SVGPaint::SVG_PAINTTYPE_URI)
            svgElement->document()->accessSVGExtensions()->addPendingResource(id, static_cast<SVGStyledElement*>(svgElement)); 
    }
    if (paintType != SVGPaint::SVG_PAINTTYPE_URI && !fillPaintServer) {
        fillPaintServer = sharedSolidPaintServer();
        SVGPaintServerSolid* fillPaintServerSolid = static_cast<SVGPaintServerSolid*>(fillPaintServer);
        if (paintType == SVGPaint::SVG_PAINTTYPE_CURRENTCOLOR)
            fillPaintServerSolid->setColor(style->color());
        else
            fillPaintServerSolid->setColor(fill->color());
        // FIXME: Ideally invalid colors would never get set on the RenderStyle and this could turn into an ASSERT
        if (!fillPaintServerSolid->color().isValid())
            fillPaintServer = 0;
    }
    if (!fillPaintServer) {
        // default value (black), see bug 11017
        fillPaintServer = sharedSolidPaintServer();
        static_cast<SVGPaintServerSolid*>(fillPaintServer)->setColor(Color::black);
    }
    return fillPaintServer;
}
Example #8
0
void Font::drawTextUsingSVGFont(GraphicsContext* context, const TextRun& run, 
                                const FloatPoint& point, int from, int to) const
{
    SVGFontElement* fontElement = 0;
    SVGFontFaceElement* fontFaceElement = 0;

    if (const SVGFontData* fontData = svgFontAndFontFaceElementForFontData(primaryFont(), fontFaceElement, fontElement)) {
        if (!fontElement)
            return;

        SVGTextRunWalkerDrawTextData data;
        FloatPoint currentPoint = point;
        float scale = convertEmUnitToPixel(size(), fontFaceElement->unitsPerEm(), 1.0f);

        SVGPaintServer* activePaintServer = run.activePaintServer();

        // If renderObject is not set, we're dealing for HTML text rendered using SVG Fonts.
        if (!run.referencingRenderObject()) {
            ASSERT(!activePaintServer);

            // TODO: We're only supporting simple filled HTML text so far.
            SVGPaintServerSolid* solidPaintServer = SVGPaintServer::sharedSolidPaintServer();
            solidPaintServer->setColor(context->fillColor());

            activePaintServer = solidPaintServer;
        }

        ASSERT(activePaintServer);

        int charsConsumed;
        String glyphName;
        bool isVerticalText = false;
        float xStartOffset = floatWidthOfSubStringUsingSVGFont(this, run, 0, run.rtl() ? to : 0, run.rtl() ? run.length() : from, charsConsumed, glyphName);
        FloatPoint glyphOrigin;

        String language;

        // TODO: language matching & svg glyphs should be possible for HTML text, too.
        if (run.referencingRenderObject()) {
            isVerticalText = isVerticalWritingMode(run.referencingRenderObject()->style()->svgStyle());    

            if (SVGElement* element = static_cast<SVGElement*>(run.referencingRenderObject()->element()))
                language = element->getAttribute(XMLNames::langAttr);
        }

        if (!isVerticalText) {
            glyphOrigin.setX(fontData->horizontalOriginX() * scale);
            glyphOrigin.setY(fontData->horizontalOriginY() * scale);
        }

        data.extraCharsAvailable = 0;
        data.charsConsumed = 0;

        SVGTextRunWalker<SVGTextRunWalkerDrawTextData> runWalker(fontData, fontElement, data, drawTextUsingSVGFontCallback, drawTextMissingGlyphCallback);
        runWalker.walk(run, isVerticalText, language, from, to);

        SVGPaintTargetType targetType = context->textDrawingMode() == cTextStroke ? ApplyToStrokeTargetType : ApplyToFillTargetType;

        unsigned numGlyphs = data.glyphIdentifiers.size();
        unsigned fallbackCharacterIndex = 0;
        for (unsigned i = 0; i < numGlyphs; ++i) {
            const SVGGlyphIdentifier& identifier = data.glyphIdentifiers[run.rtl() ? numGlyphs - i - 1 : i];
            if (identifier.isValid) {
                // FIXME: Support arbitary SVG content as glyph (currently limited to <glyph d="..."> situations).
                if (!identifier.pathData.isEmpty()) {
                    context->save();

                    if (isVerticalText) {
                        glyphOrigin.setX(identifier.verticalOriginX * scale);
                        glyphOrigin.setY(identifier.verticalOriginY * scale);
                    }

                    context->translate(xStartOffset + currentPoint.x() + glyphOrigin.x(), currentPoint.y() + glyphOrigin.y());
                    context->scale(FloatSize(scale, -scale));

                    context->beginPath();
                    context->addPath(identifier.pathData);

                    if (activePaintServer->setup(context, run.referencingRenderObject(), targetType)) {
                        // Spec: Any properties specified on a text elements which represents a length, such as the
                        // 'stroke-width' property, might produce surprising results since the length value will be
                        // processed in the coordinate system of the glyph. (TODO: What other lengths? miter-limit? dash-offset?)
                        if (targetType == ApplyToStrokeTargetType && scale != 0.0f)
                            context->setStrokeThickness(context->strokeThickness() / scale);

                        activePaintServer->renderPath(context, run.referencingRenderObject(), targetType);
                        activePaintServer->teardown(context, run.referencingRenderObject(), targetType);
                    }

                    context->restore();
                }

                if (isVerticalText)
                    currentPoint.move(0.0f, identifier.verticalAdvanceY * scale);
                else
                    currentPoint.move(identifier.horizontalAdvanceX * scale, 0.0f);
            } else {
                // Handle system font fallback
                FontDescription fontDescription(context->font().fontDescription());
                fontDescription.setFamily(FontFamily());
                Font font(fontDescription, 0, 0); // spacing handled by SVG text code.
                font.update(context->font().fontSelector());

                TextRun fallbackCharacterRun(run);
                fallbackCharacterRun.setText(&data.fallbackCharacters[run.rtl() ? data.fallbackCharacters.size() - fallbackCharacterIndex - 1 : fallbackCharacterIndex], 1);
                font.drawText(context, fallbackCharacterRun, currentPoint);

                if (isVerticalText)
                    currentPoint.move(0.0f, font.floatWidth(fallbackCharacterRun));
                else
                    currentPoint.move(font.floatWidth(fallbackCharacterRun), 0.0f);

                fallbackCharacterIndex++;
            }
        }
    }
}
Example #9
0
void paintSVGInlineFlow(InlineFlowBox* flow, RenderObject* object, RenderObject::PaintInfo& paintInfo, int tx, int ty)
{
    if (paintInfo.context->paintingDisabled())
        return;

    paintInfo.context->save();
    paintInfo.context->concatCTM(object->localTransform());

    FloatRect boundingBox(tx + flow->xPos(), ty + flow->yPos(), flow->width(), flow->height());

    SVGElement* svgElement = static_cast<SVGElement*>(object->element());
    ASSERT(svgElement && svgElement->document() && svgElement->isStyled());

    SVGStyledElement* styledElement = static_cast<SVGStyledElement*>(svgElement);
    const SVGRenderStyle* svgStyle = object->style()->svgStyle();

    AtomicString filterId(SVGURIReference::getTarget(svgStyle->filter()));
    AtomicString clipperId(SVGURIReference::getTarget(svgStyle->clipPath()));
    AtomicString maskerId(SVGURIReference::getTarget(svgStyle->maskElement()));

#if ENABLE(SVG_EXPERIMENTAL_FEATURES)
    SVGResourceFilter* filter = getFilterById(object->document(), filterId);
#endif
    SVGResourceClipper* clipper = getClipperById(object->document(), clipperId);
    SVGResourceMasker* masker = getMaskerById(object->document(), maskerId);

#if ENABLE(SVG_EXPERIMENTAL_FEATURES)
    if (filter)
        filter->prepareFilter(paintInfo.context, boundingBox);
    else if (!filterId.isEmpty())
        svgElement->document()->accessSVGExtensions()->addPendingResource(filterId, styledElement);
#endif

    if (clipper) {
        clipper->addClient(styledElement);
        clipper->applyClip(paintInfo.context, boundingBox);
    } else if (!clipperId.isEmpty())
        svgElement->document()->accessSVGExtensions()->addPendingResource(clipperId, styledElement);

    if (masker) {
        masker->addClient(styledElement);
        masker->applyMask(paintInfo.context, boundingBox);
    } else if (!maskerId.isEmpty())
        svgElement->document()->accessSVGExtensions()->addPendingResource(maskerId, styledElement);

    RenderObject::PaintInfo pi(paintInfo);

    if (!flow->isRootInlineBox())
        pi.rect = (object->localTransform()).inverse().mapRect(pi.rect);

    float opacity = object->style()->opacity();
    if (opacity < 1.0f) {
        paintInfo.context->clip(enclosingIntRect(boundingBox));
        paintInfo.context->beginTransparencyLayer(opacity);
    }

    SVGPaintServer* fillPaintServer = KSVGPainterFactory::fillPaintServer(object->style(), object);
    if (fillPaintServer) {
        if (fillPaintServer->setup(pi.context, object, ApplyToFillTargetType, true)) {
            flow->InlineFlowBox::paint(pi, tx, ty);
            fillPaintServer->teardown(pi.context, object, ApplyToFillTargetType, true);
        }
    }

    SVGPaintServer* strokePaintServer = KSVGPainterFactory::strokePaintServer(object->style(), object);
    if (strokePaintServer) {
        if (strokePaintServer->setup(pi.context, object, ApplyToStrokeTargetType, true)) {
            flow->InlineFlowBox::paint(pi, tx, ty);
            strokePaintServer->teardown(pi.context, object, ApplyToStrokeTargetType, true);
        }
    }

#if ENABLE(SVG_EXPERIMENTAL_FEATURES)
    if (filter)
        filter->applyFilter(paintInfo.context, boundingBox);
#endif

    if (opacity < 1.0f)
        paintInfo.context->endTransparencyLayer();

    paintInfo.context->restore();
}
Example #10
0
void RenderPath::paint(PaintInfo& paintInfo, int, int)
{
    if (paintInfo.context->paintingDisabled() || (paintInfo.phase != PaintPhaseForeground) || style()->visibility() == HIDDEN || m_path.isEmpty())
        return;

    paintInfo.context->save();
    paintInfo.context->concatCTM(localTransform());

    FloatRect strokeBBox = relativeBBox(true);

    SVGElement* svgElement = static_cast<SVGElement*>(element());
    ASSERT(svgElement && svgElement->document() && svgElement->isStyled());

    SVGStyledElement* styledElement = static_cast<SVGStyledElement*>(svgElement);
    const SVGRenderStyle* svgStyle = style()->svgStyle();

    AtomicString filterId(SVGURIReference::getTarget(svgStyle->filter()));
    AtomicString clipperId(SVGURIReference::getTarget(svgStyle->clipPath()));
    AtomicString maskerId(SVGURIReference::getTarget(svgStyle->maskElement()));

#if ENABLE(SVG_EXPERIMENTAL_FEATURES)
    SVGResourceFilter* filter = getFilterById(document(), filterId);
#endif
    SVGResourceClipper* clipper = getClipperById(document(), clipperId);
    SVGResourceMasker* masker = getMaskerById(document(), maskerId);

#if ENABLE(SVG_EXPERIMENTAL_FEATURES)
    if (filter)
        filter->prepareFilter(paintInfo.context, strokeBBox);
    else if (!filterId.isEmpty())
        svgElement->document()->accessSVGExtensions()->addPendingResource(filterId, styledElement);
#endif

    if (clipper) {
        clipper->addClient(styledElement);
        clipper->applyClip(paintInfo.context, strokeBBox);
    } else if (!clipperId.isEmpty())
        svgElement->document()->accessSVGExtensions()->addPendingResource(clipperId, styledElement);

    if (masker) {
        masker->addClient(styledElement);
        masker->applyMask(paintInfo.context, strokeBBox);
    } else if (!maskerId.isEmpty())
        svgElement->document()->accessSVGExtensions()->addPendingResource(maskerId, styledElement);

    paintInfo.context->beginPath();

    SVGPaintServer* fillPaintServer = KSVGPainterFactory::fillPaintServer(style(), this);
    if (fillPaintServer) {
        paintInfo.context->addPath(m_path);
        fillPaintServer->draw(paintInfo.context, this, ApplyToFillTargetType);
    }

    SVGPaintServer* strokePaintServer = KSVGPainterFactory::strokePaintServer(style(), this);
    if (strokePaintServer) {
        paintInfo.context->addPath(m_path); // path is cleared when filled.
        strokePaintServer->draw(paintInfo.context, this, ApplyToStrokeTargetType);
    }

    if (styledElement->supportsMarkers())
        m_markerBounds = drawMarkersIfNeeded(paintInfo.context, paintInfo.rect, m_path);

#if ENABLE(SVG_EXPERIMENTAL_FEATURES)
    // actually apply the filter
    if (filter)
        filter->applyFilter(paintInfo.context, strokeBBox);
#endif

    paintInfo.context->restore();
}