bool SVGInlineTextBox::acquirePaintingResource(GraphicsContext*& context, float scalingFactor, RenderObject* renderer, RenderStyle* style) { ASSERT(scalingFactor); ASSERT(renderer); ASSERT(style); ASSERT(m_paintingResourceMode != ApplyToDefaultMode); Color fallbackColor; if (m_paintingResourceMode & ApplyToFillMode) m_paintingResource = RenderSVGResource::fillPaintingResource(renderer, style, fallbackColor); else if (m_paintingResourceMode & ApplyToStrokeMode) m_paintingResource = RenderSVGResource::strokePaintingResource(renderer, style, fallbackColor); else { // We're either called for stroking or filling. ASSERT_NOT_REACHED(); } if (!m_paintingResource) return false; if (!m_paintingResource->applyResource(renderer, style, context, m_paintingResourceMode)) { if (fallbackColor.isValid()) { RenderSVGResourceSolidColor* fallbackResource = RenderSVGResource::sharedSolidPaintingResource(); fallbackResource->setColor(fallbackColor); m_paintingResource = fallbackResource; m_paintingResource->applyResource(renderer, style, context, m_paintingResourceMode); } } if (scalingFactor != 1 && m_paintingResourceMode & ApplyToStrokeMode) context->setStrokeThickness(context->strokeThickness() * scalingFactor); return true; }
void SVGTextRunRenderingContext::drawSVGGlyphs(GraphicsContext* context, const SimpleFontData* fontData, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const { auto activePaintingResource = this->activePaintingResource(); if (!activePaintingResource) { // TODO: We're only supporting simple filled HTML text so far. RenderSVGResourceSolidColor* solidPaintingResource = RenderSVGResource::sharedSolidPaintingResource(); solidPaintingResource->setColor(context->fillColor()); activePaintingResource = solidPaintingResource; } auto& elementRenderer = renderer().isRenderElement() ? toRenderElement(renderer()) : *renderer().parent(); RenderStyle& style = elementRenderer.style(); ASSERT(activePaintingResource); RenderSVGResourceMode resourceMode = context->textDrawingMode() == TextModeStroke ? ApplyToStrokeMode : ApplyToFillMode; auto translator(createGlyphToPathTranslator(*fontData, glyphBuffer, from, numGlyphs, point)); while (translator->containsMorePaths()) { Path glyphPath = translator->nextPath(); if (activePaintingResource->applyResource(elementRenderer, style, context, resourceMode)) { float strokeThickness = context->strokeThickness(); if (renderer().isSVGInlineText()) context->setStrokeThickness(strokeThickness * toRenderSVGInlineText(renderer()).scalingFactor()); activePaintingResource->postApplyResource(elementRenderer, context, resourceMode, &glyphPath, 0); context->setStrokeThickness(strokeThickness); } } }
RenderSVGResource* RenderSVGResource::strokePaintingResource(const RenderObject* object, const RenderStyle* style) { ASSERT(object); ASSERT(style); const SVGRenderStyle* svgStyle = style->svgStyle(); if (!svgStyle || !svgStyle->hasStroke()) return 0; SVGPaint* strokePaint = svgStyle->strokePaint(); ASSERT(strokePaint); RenderSVGResource* strokePaintingResource = 0; FloatRect objectBoundingBox = object->objectBoundingBox(); SVGPaint::SVGPaintType paintType = strokePaint->paintType(); if (!objectBoundingBox.isEmpty() && (paintType == SVGPaint::SVG_PAINTTYPE_URI || paintType == SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR)) { AtomicString id(SVGURIReference::getTarget(strokePaint->uri())); strokePaintingResource = getRenderSVGResourceContainerById(object->document(), id); if (!strokePaintingResource) registerPendingResource(id, paintType, object); } if (paintType != SVGPaint::SVG_PAINTTYPE_URI && !strokePaintingResource) { RenderSVGResourceSolidColor* solidResource = sharedSolidPaintingResource(); strokePaintingResource = solidResource; Color strokeColor; if (strokePaint->paintType() == SVGPaint::SVG_PAINTTYPE_CURRENTCOLOR) strokeColor = style->visitedDependentColor(CSSPropertyColor); else strokeColor = strokePaint->color(); adjustColorForPseudoRules(style, false /* useFillPaint */, strokeColor); // FIXME: Ideally invalid colors would never get set on the RenderStyle and this could turn into an ASSERT if (strokeColor.isValid()) solidResource->setColor(strokeColor); else strokePaintingResource = 0; } if (!strokePaintingResource) { // default value (black), see bug 11017 RenderSVGResourceSolidColor* solidResource = sharedSolidPaintingResource(); solidResource->setColor(Color::black); strokePaintingResource = solidResource; } return strokePaintingResource; }
void RenderSVGShape::strokeShape(const RenderStyle& style, GraphicsContext& originalContext) { GraphicsContext* context = &originalContext; Color fallbackColor; if (RenderSVGResource* strokePaintingResource = RenderSVGResource::strokePaintingResource(*this, style, fallbackColor)) { if (strokePaintingResource->applyResource(*this, style, context, ApplyToStrokeMode)) strokePaintingResource->postApplyResource(*this, context, ApplyToStrokeMode, 0, this); else if (fallbackColor.isValid()) { RenderSVGResourceSolidColor* fallbackResource = RenderSVGResource::sharedSolidPaintingResource(); fallbackResource->setColor(fallbackColor); if (fallbackResource->applyResource(*this, style, context, ApplyToStrokeMode)) fallbackResource->postApplyResource(*this, context, ApplyToStrokeMode, 0, this); } } }
// FIXME: This method and strokePaintingResource() should be refactored, to share even more code RenderSVGResource* RenderSVGResource::fillPaintingResource(RenderObject* object, const RenderStyle* style) { ASSERT(object); ASSERT(style); const SVGRenderStyle* svgStyle = style->svgStyle(); if (!svgStyle || !svgStyle->hasFill()) return 0; SVGPaint* fillPaint = svgStyle->fillPaint(); ASSERT(fillPaint); RenderSVGResource* fillPaintingResource = 0; SVGPaint::SVGPaintType paintType = fillPaint->paintType(); if (paintType == SVGPaint::SVG_PAINTTYPE_URI || paintType == SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR) { if (SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(object)) fillPaintingResource = resources->fill(); } if (paintType != SVGPaint::SVG_PAINTTYPE_URI && !fillPaintingResource) { RenderSVGResourceSolidColor* solidResource = sharedSolidPaintingResource(); fillPaintingResource = solidResource; Color fillColor; if (fillPaint->paintType() == SVGPaint::SVG_PAINTTYPE_CURRENTCOLOR) fillColor = style->visitedDependentColor(CSSPropertyColor); else fillColor = fillPaint->color(); adjustColorForPseudoRules(style, true /* useFillPaint */, fillColor); // FIXME: Ideally invalid colors would never get set on the RenderStyle and this could turn into an ASSERT if (fillColor.isValid()) solidResource->setColor(fillColor); else fillPaintingResource = 0; } if (!fillPaintingResource) { // default value (black), see bug 11017 RenderSVGResourceSolidColor* solidResource = sharedSolidPaintingResource(); solidResource->setColor(Color::black); fillPaintingResource = solidResource; } return fillPaintingResource; }
void RenderSVGPath::fillAndStrokePath(GraphicsContext* context) { RenderStyle* style = this->style(); Color fallbackColor; if (RenderSVGResource* fillPaintingResource = RenderSVGResource::fillPaintingResource(this, style, fallbackColor)) { if (fillPaintingResource->applyResource(this, style, context, ApplyToFillMode)) fillPaintingResource->postApplyResource(this, context, ApplyToFillMode, &m_path); else if (fallbackColor.isValid()) { RenderSVGResourceSolidColor* fallbackResource = RenderSVGResource::sharedSolidPaintingResource(); fallbackResource->setColor(fallbackColor); if (fallbackResource->applyResource(this, style, context, ApplyToFillMode)) fallbackResource->postApplyResource(this, context, ApplyToFillMode, &m_path); } } fallbackColor = Color(); RenderSVGResource* strokePaintingResource = RenderSVGResource::strokePaintingResource(this, style, fallbackColor); if (!strokePaintingResource) return; Path path; bool nonScalingStroke = style->svgStyle()->vectorEffect() == VE_NON_SCALING_STROKE; GraphicsContextStateSaver stateSaver(*context, false); if (nonScalingStroke) { SVGStyledTransformableElement* element = static_cast<SVGStyledTransformableElement*>(node()); AffineTransform nonScalingStrokeTransform = element->getScreenCTM(SVGLocatable::DisallowStyleUpdate); if (!nonScalingStrokeTransform.isInvertible()) return; path = m_path; path.transform(nonScalingStrokeTransform); stateSaver.save(); context->concatCTM(nonScalingStrokeTransform.inverse()); } if (strokePaintingResource->applyResource(this, style, context, ApplyToStrokeMode)) strokePaintingResource->postApplyResource(this, context, ApplyToStrokeMode, nonScalingStroke ? &path : &m_path); else if (fallbackColor.isValid()) { RenderSVGResourceSolidColor* fallbackResource = RenderSVGResource::sharedSolidPaintingResource(); fallbackResource->setColor(fallbackColor); if (fallbackResource->applyResource(this, style, context, ApplyToStrokeMode)) fallbackResource->postApplyResource(this, context, ApplyToStrokeMode, nonScalingStroke ? &path : &m_path); } }
static inline RenderSVGResource* requestPaintingResource(RenderSVGResourceMode mode, RenderObject* object, const RenderStyle* style, Color& fallbackColor) { ASSERT(object); ASSERT(style); // If we have no style at all, ignore it. const SVGRenderStyle* svgStyle = style->svgStyle(); if (!svgStyle) return 0; // If we have no fill/stroke, return 0. if (mode == ApplyToFillMode) { if (!svgStyle->hasFill()) return 0; } else { if (!svgStyle->hasStroke()) return 0; } bool applyToFill = mode == ApplyToFillMode; SVGPaint::SVGPaintType paintType = applyToFill ? svgStyle->fillPaintType() : svgStyle->strokePaintType(); if (paintType == SVGPaint::SVG_PAINTTYPE_NONE) return 0; Color color; switch (paintType) { case SVGPaint::SVG_PAINTTYPE_CURRENTCOLOR: case SVGPaint::SVG_PAINTTYPE_RGBCOLOR: case SVGPaint::SVG_PAINTTYPE_RGBCOLOR_ICCCOLOR: case SVGPaint::SVG_PAINTTYPE_URI_CURRENTCOLOR: case SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR: case SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR_ICCCOLOR: color = applyToFill ? svgStyle->fillPaintColor() : svgStyle->strokePaintColor(); default: break; } if (style->insideLink() == InsideVisitedLink) { RenderStyle* visitedStyle = style->getCachedPseudoStyle(VISITED_LINK); ASSERT(visitedStyle); const SVGRenderStyle* svgVisitedStyle = visitedStyle->svgStyle(); SVGPaint::SVGPaintType visitedPaintType = applyToFill ? svgVisitedStyle->fillPaintType() : svgVisitedStyle->strokePaintType(); // For SVG_PAINTTYPE_CURRENTCOLOR, 'color' already contains the 'visitedColor'. if (visitedPaintType < SVGPaint::SVG_PAINTTYPE_URI_NONE && visitedPaintType != SVGPaint::SVG_PAINTTYPE_CURRENTCOLOR) { const Color& visitedColor = applyToFill ? svgVisitedStyle->fillPaintColor() : svgVisitedStyle->strokePaintColor(); if (visitedColor.isValid()) color = Color(visitedColor.red(), visitedColor.green(), visitedColor.blue(), color.alpha()); } } // If the primary resource is just a color, return immediately. RenderSVGResourceSolidColor* colorResource = RenderSVGResource::sharedSolidPaintingResource(); if (paintType < SVGPaint::SVG_PAINTTYPE_URI_NONE) { // If an invalid fill color is specified, fallback to fill/stroke="none". if (!color.isValid()) return 0; colorResource->setColor(color); return colorResource; } // If no resources are associated with the given renderer, return the color resource. SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(object); if (!resources) { // If a paint server is specified, and no or an invalid fallback color is given, default to fill/stroke="black". if (!color.isValid()) color = Color::black; colorResource->setColor(color); return colorResource; } // If the requested resource is not available, return the color resource. RenderSVGResource* uriResource = mode == ApplyToFillMode ? resources->fill() : resources->stroke(); if (!uriResource) { // If a paint server is specified, and no or an invalid fallback color is given, default to fill/stroke="black". if (!color.isValid()) color = Color::black; colorResource->setColor(color); return colorResource; } // The paint server resource exists, though it may be invalid (pattern with width/height=0). Pass the fallback color to our caller // so it can use the solid color painting resource, if applyResource() on the URI resource failed. fallbackColor = color; return uriResource; }
void SVGTextRunRenderingContext::drawSVGGlyphs(GraphicsContext* context, const TextRun& run, const SimpleFontData* fontData, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const { SVGFontElement* fontElement = 0; SVGFontFaceElement* fontFaceElement = 0; const SVGFontData* svgFontData = svgFontAndFontFaceElementForFontData(fontData, fontFaceElement, fontElement); if (!fontElement || !fontFaceElement) return; // We can only paint SVGFonts if a context is available. RenderSVGResource* activePaintingResource = activePaintingResourceFromRun(run); RenderObject* renderObject = renderObjectFromRun(run); RenderObject* parentRenderObject = firstParentRendererForNonTextNode(renderObject); RenderStyle* parentRenderObjectStyle = 0; ASSERT(renderObject); if (!activePaintingResource) { // TODO: We're only supporting simple filled HTML text so far. RenderSVGResourceSolidColor* solidPaintingResource = RenderSVGResource::sharedSolidPaintingResource(); solidPaintingResource->setColor(context->fillColor()); activePaintingResource = solidPaintingResource; } bool isVerticalText = false; if (parentRenderObject) { parentRenderObjectStyle = parentRenderObject->style(); ASSERT(parentRenderObjectStyle); isVerticalText = parentRenderObjectStyle->svgStyle()->isVerticalWritingMode(); } float scale = scaleEmToUnits(fontData->platformData().size(), fontFaceElement->unitsPerEm()); ASSERT(activePaintingResource); FloatPoint glyphOrigin; glyphOrigin.setX(svgFontData->horizontalOriginX() * scale); glyphOrigin.setY(svgFontData->horizontalOriginY() * scale); FloatPoint currentPoint = point; RenderSVGResourceMode resourceMode = context->textDrawingMode() == TextModeStroke ? ApplyToStrokeMode : ApplyToFillMode; for (int i = 0; i < numGlyphs; ++i) { Glyph glyph = glyphBuffer.glyphAt(from + i); if (!glyph) continue; float advance = glyphBuffer.advanceAt(from + i); SVGGlyph svgGlyph = fontElement->svgGlyphForGlyph(glyph); ASSERT(!svgGlyph.isPartOfLigature); ASSERT(svgGlyph.tableEntry == glyph); SVGGlyphElement::inheritUnspecifiedAttributes(svgGlyph, svgFontData); // FIXME: Support arbitary SVG content as glyph (currently limited to <glyph d="..."> situations). if (svgGlyph.pathData.isEmpty()) { if (isVerticalText) currentPoint.move(0, advance); else currentPoint.move(advance, 0); continue; } context->save(); if (isVerticalText) { glyphOrigin.setX(svgGlyph.verticalOriginX * scale); glyphOrigin.setY(svgGlyph.verticalOriginY * scale); } AffineTransform glyphPathTransform; glyphPathTransform.translate(currentPoint.x() + glyphOrigin.x(), currentPoint.y() + glyphOrigin.y()); glyphPathTransform.scale(scale, -scale); Path glyphPath = svgGlyph.pathData; glyphPath.transform(glyphPathTransform); if (activePaintingResource->applyResource(parentRenderObject, parentRenderObjectStyle, context, resourceMode)) { if (renderObject && renderObject->isSVGInlineText()) { const RenderSVGInlineText* textRenderer = toRenderSVGInlineText(renderObject); context->setStrokeThickness(context->strokeThickness() * textRenderer->scalingFactor()); } activePaintingResource->postApplyResource(parentRenderObject, context, resourceMode, &glyphPath, 0); } context->restore(); if (isVerticalText) currentPoint.move(0, advance); else currentPoint.move(advance, 0); } }
static inline RenderSVGResource* requestPaintingResource(RenderSVGResourceMode mode, RenderObject* object, const RenderStyle* style, Color& fallbackColor) { ASSERT(object); ASSERT(style); // If we have no style at all, ignore it. const SVGRenderStyle* svgStyle = style->svgStyle(); if (!svgStyle) return 0; bool isRenderingMask = false; if (object->frame() && object->frame()->view()) isRenderingMask = object->frame()->view()->paintBehavior() & PaintBehaviorRenderingSVGMask; // If we have no fill/stroke, return 0. if (mode == ApplyToFillMode) { // When rendering the mask for a RenderSVGResourceClipper, always use the initial fill paint server, and ignore stroke. if (isRenderingMask) { RenderSVGResourceSolidColor* colorResource = RenderSVGResource::sharedSolidPaintingResource(); colorResource->setColor(SVGRenderStyle::initialFillPaintColor()); return colorResource; } if (!svgStyle->hasFill()) return 0; } else { if (!svgStyle->hasStroke() || isRenderingMask) return 0; } bool applyToFill = mode == ApplyToFillMode; SVGPaint::SVGPaintType paintType = applyToFill ? svgStyle->fillPaintType() : svgStyle->strokePaintType(); if (paintType == SVGPaint::SVG_PAINTTYPE_NONE) return 0; Color color; switch (paintType) { case SVGPaint::SVG_PAINTTYPE_CURRENTCOLOR: case SVGPaint::SVG_PAINTTYPE_RGBCOLOR: case SVGPaint::SVG_PAINTTYPE_RGBCOLOR_ICCCOLOR: case SVGPaint::SVG_PAINTTYPE_URI_CURRENTCOLOR: case SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR: case SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR_ICCCOLOR: color = applyToFill ? svgStyle->fillPaintColor() : svgStyle->strokePaintColor(); default: break; } if (style->insideLink() == InsideVisitedLink) { // FIXME: This code doesn't support the uri component of the visited link paint, https://bugs.webkit.org/show_bug.cgi?id=70006 SVGPaint::SVGPaintType visitedPaintType = applyToFill ? svgStyle->visitedLinkFillPaintType() : svgStyle->visitedLinkStrokePaintType(); // For SVG_PAINTTYPE_CURRENTCOLOR, 'color' already contains the 'visitedColor'. if (visitedPaintType < SVGPaint::SVG_PAINTTYPE_URI_NONE && visitedPaintType != SVGPaint::SVG_PAINTTYPE_CURRENTCOLOR) { const Color& visitedColor = applyToFill ? svgStyle->visitedLinkFillPaintColor() : svgStyle->visitedLinkStrokePaintColor(); if (visitedColor.isValid()) color = Color(visitedColor.red(), visitedColor.green(), visitedColor.blue(), color.alpha()); } } // If the primary resource is just a color, return immediately. RenderSVGResourceSolidColor* colorResource = RenderSVGResource::sharedSolidPaintingResource(); if (paintType < SVGPaint::SVG_PAINTTYPE_URI_NONE) { if (!inheritColorFromParentStyleIfNeeded(object, applyToFill, color)) return 0; colorResource->setColor(color); return colorResource; } // If no resources are associated with the given renderer, return the color resource. SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(object); if (!resources) { if (paintType == SVGPaint::SVG_PAINTTYPE_URI_NONE || !inheritColorFromParentStyleIfNeeded(object, applyToFill, color)) return 0; colorResource->setColor(color); return colorResource; } // If the requested resource is not available, return the color resource. RenderSVGResource* uriResource = mode == ApplyToFillMode ? resources->fill() : resources->stroke(); if (!uriResource) { if (!inheritColorFromParentStyleIfNeeded(object, applyToFill, color)) return 0; colorResource->setColor(color); return colorResource; } // The paint server resource exists, though it may be invalid (pattern with width/height=0). Pass the fallback color to our caller // so it can use the solid color painting resource, if applyResource() on the URI resource failed. fallbackColor = color; return uriResource; }