SVGResource* getResourceById(Document* document, const AtomicString& id) { if (id.isEmpty()) return 0; Element* element = document->getElementById(id); SVGElement* svgElement = 0; if (element && element->isSVGElement()) svgElement = static_cast<SVGElement*>(element); if (svgElement && svgElement->isStyled()) return static_cast<SVGStyledElement*>(svgElement)->canvasResource(); return 0; }
void RenderSVGResource::markForLayoutAndResourceInvalidation(RenderObject* object) { ASSERT(object); ASSERT(object->node()); ASSERT(object->node()->isSVGElement()); // Mark the renderer for layout object->setNeedsLayout(true); // Notify any resources in the ancestor chain, that we've been invalidated SVGElement* element = static_cast<SVGElement*>(object->node()); if (!element->isStyled()) return; static_cast<SVGStyledElement*>(element)->invalidateResourcesInAncestorChain(); }
void FEImage::platformApplySoftware() { RenderObject* renderer = referencedRenderer(); if (!m_image && !renderer) return; ImageBuffer* resultImage = createImageBufferResult(); if (!resultImage) return; SVGFilter* svgFilter = static_cast<SVGFilter*>(filter()); FloatRect destRect = svgFilter->absoluteTransform().mapRect(filterPrimitiveSubregion()); FloatRect srcRect; if (renderer) srcRect = svgFilter->absoluteTransform().mapRect(renderer->repaintRectInLocalCoordinates()); else { srcRect = FloatRect(FloatPoint(), m_image->size()); m_preserveAspectRatio.transformRect(destRect, srcRect); } IntPoint paintLocation = absolutePaintRect().location(); destRect.move(-paintLocation.x(), -paintLocation.y()); if (renderer) { const AffineTransform& absoluteTransform = svgFilter->absoluteTransform(); resultImage->context()->concatCTM(absoluteTransform); SVGElement* contextNode = static_cast<SVGElement*>(renderer->node()); if (contextNode->isStyled() && static_cast<SVGStyledElement*>(contextNode)->hasRelativeLengths()) { SVGLengthContext lengthContext(contextNode); float width = 0; float height = 0; // If we're referencing an element with percentage units, eg. <rect with="30%"> those values were resolved against the viewport. // Build up a transformation that maps from the viewport space to the filter primitive subregion. if (lengthContext.determineViewport(width, height)) resultImage->context()->concatCTM(makeMapBetweenRects(FloatRect(0, 0, width, height), destRect)); } AffineTransform contentTransformation; SVGRenderingContext::renderSubtreeToImageBuffer(resultImage, renderer, contentTransformation); return; } resultImage->context()->drawImage(m_image.get(), ColorSpaceDeviceRGB, destRect, srcRect); }
bool SVGUseElement::selfHasRelativeLengths() const { if (x().isRelative() || y().isRelative() || width().isRelative() || height().isRelative()) return true; if (!m_targetElementInstance) return false; SVGElement* element = m_targetElementInstance->correspondingElement(); if (!element || !element->isStyled()) return false; return static_cast<SVGStyledElement*>(element)->hasRelativeLengths(); }
void SVGStyledElement::invalidateResourcesInAncestorChain() const { Node* node = parentNode(); while (node) { if (!node->isSVGElement()) break; SVGElement* element = static_cast<SVGElement*>(node); if (SVGStyledElement* styledElement = static_cast<SVGStyledElement*>(element->isStyled() ? element : 0)) { styledElement->invalidateResourceClients(); // If we found the first resource in the ancestor chain, immediately stop. break; } node = node->parentNode(); } }
void RenderPath::calculateMarkerBoundsIfNeeded() const { Document* doc = document(); SVGElement* svgElement = static_cast<SVGElement*>(node()); ASSERT(svgElement && svgElement->document()); if (!svgElement->isStyled()) return; SVGStyledElement* styledElement = static_cast<SVGStyledElement*>(svgElement); if (!styledElement->supportsMarkers()) return; const SVGRenderStyle* svgStyle = style()->svgStyle(); AtomicString startMarkerId(svgStyle->startMarker()); AtomicString midMarkerId(svgStyle->midMarker()); AtomicString endMarkerId(svgStyle->endMarker()); SVGResourceMarker* startMarker = getMarkerById(doc, startMarkerId, this); SVGResourceMarker* midMarker = getMarkerById(doc, midMarkerId, this); SVGResourceMarker* endMarker = getMarkerById(doc, endMarkerId, this); if (!startMarker && !startMarkerId.isEmpty()) svgElement->document()->accessSVGExtensions()->addPendingResource(startMarkerId, styledElement); else if (startMarker) startMarker->addClient(styledElement); if (!midMarker && !midMarkerId.isEmpty()) svgElement->document()->accessSVGExtensions()->addPendingResource(midMarkerId, styledElement); else if (midMarker) midMarker->addClient(styledElement); if (!endMarker && !endMarkerId.isEmpty()) svgElement->document()->accessSVGExtensions()->addPendingResource(endMarkerId, styledElement); else if (endMarker) endMarker->addClient(styledElement); if (!startMarker && !midMarker && !endMarker) return; float strokeWidth = SVGRenderStyle::cssPrimitiveToLength(this, svgStyle->strokeWidth(), 1.0f); m_cachedLocalMarkerBBox = m_markerLayoutInfo.calculateBoundaries(startMarker, midMarker, endMarker, strokeWidth, m_path); }
static void getElementCTM(SVGElement* element, AffineTransform& transform) { ASSERT(element); element->document()->updateLayoutIgnorePendingStylesheets(); SVGElement* stopAtElement = SVGLocatable::nearestViewportElement(element); ASSERT(stopAtElement); Node* current = element; while (current && current->isSVGElement()) { SVGElement* currentElement = static_cast<SVGElement*>(current); if (currentElement->isStyled()) transform = const_cast<AffineTransform&>(currentElement->renderer()->localToParentTransform()).multiply(transform); // For getCTM() computation, stop at the nearest viewport element if (currentElement == stopAtElement) break; current = current->parentOrHostNode(); } }
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; }
// FIXME: This funtion will eventually become part of the AnimationCompositor void SVGTimer::applyAnimations(double elapsedSeconds, const SVGTimer::TargetAnimationMap& targetMap) { TargetAnimationMap::const_iterator targetIterator = targetMap.begin(); TargetAnimationMap::const_iterator tend = targetMap.end(); for (; targetIterator != tend; ++targetIterator) { // FIXME: This is still not 100% correct. Correct would be: // 1. Walk backwards through the priority list until a replace (!isAdditive()) is found // -- This optimization is not possible without careful consideration for dependent values (such as cx and fx in SVGRadialGradient) // 2. Set the initial value (or last replace) as the new animVal // 3. Call each enabled animation in turn, to have it apply its changes // 4. After building a new animVal, set it on the element. // Currenly we use the actual animVal on the element as "temporary storage" // and abstract the getting/setting of the attributes into the SVGAnimate* classes unsigned count = targetIterator->second.size(); for (unsigned i = 0; i < count; ++i) { SVGAnimationElement* animation = targetIterator->second[i]; if (!animation->isValidAnimation()) continue; if (!animation->updateAnimationBaseValueFromElement()) continue; if (!animation->updateAnimatedValueForElapsedSeconds(elapsedSeconds)) continue; animation->applyAnimatedValueToElement(); } } // Make a second pass through the map to avoid multiple setChanged calls on the same element. for (targetIterator = targetMap.begin(); targetIterator != tend; ++targetIterator) { SVGElement* key = targetIterator->first; if (key && key->isStyled()) static_cast<SVGStyledElement*>(key)->setChanged(true); } }
void SVGStyledElement::updateRelativeLengthsInformation(bool hasRelativeLengths, SVGStyledElement* element) { // If we're not yet in a document, this function will be called again from insertedIntoDocument(). Do nothing now. if (!inDocument()) return; // An element wants to notify us that its own relative lengths state changed. // Register it in the relative length map, and register us in the parent relative length map. // Register the parent in the grandparents map, etc. Repeat procedure until the root of the SVG tree. if (hasRelativeLengths) m_elementsWithRelativeLengths.add(element); else { if (!m_elementsWithRelativeLengths.contains(element)) { // We were never registered. Do nothing. return; } m_elementsWithRelativeLengths.remove(element); } // Find first styled parent node, and notify it that we've changed our relative length state. Node* node = parent(); while (node) { if (!node->isSVGElement()) break; SVGElement* element = static_cast<SVGElement*>(node); if (!element->isStyled()) { node = node->parent(); continue; } // Register us in the parent element map. static_cast<SVGStyledElement*>(element)->updateRelativeLengthsInformation(hasRelativeLengths, this); break; } }
void writeRenderResources(TextStream &ts, Node *parent) { ASSERT(parent); Node *node = parent; do { if (!node->isSVGElement()) continue; SVGElement *svgElement = static_cast<SVGElement *>(node); if (!svgElement->isStyled()) continue; SVGStyledElement *styled = static_cast<SVGStyledElement *>(svgElement); KCanvasResource *resource = styled->canvasResource(); if (!resource) continue; DeprecatedString elementId = svgElement->getAttribute(HTMLNames::idAttr).deprecatedString(); if (resource->isPaintServer()) ts << "KRenderingPaintServer {id=\"" << elementId << "\" " << *static_cast<KRenderingPaintServer *>(resource) << "}" << endl; else ts << "KCanvasResource {id=\"" << elementId << "\" " << *resource << "}" << endl; } while ((node = node->traverseNextNode(parent))); }
SVGPaintServer* SVGPaintServer::strokePaintServer(const RenderStyle* style, const RenderObject* item) { if (!style->svgStyle()->hasStroke()) return 0; SVGPaint* stroke = style->svgStyle()->strokePaint(); SVGPaintServer* strokePaintServer = 0; SVGPaint::SVGPaintType paintType = stroke->paintType(); if (paintType == SVGPaint::SVG_PAINTTYPE_URI || paintType == SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR) { 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 && paintType == SVGPaint::SVG_PAINTTYPE_URI) svgElement->document()->accessSVGExtensions()->addPendingResource(id, static_cast<SVGStyledElement*>(svgElement)); } if (paintType != SVGPaint::SVG_PAINTTYPE_URI && !strokePaintServer) { strokePaintServer = sharedSolidPaintServer(); SVGPaintServerSolid* strokePaintServerSolid = static_cast<SVGPaintServerSolid*>(strokePaintServer); if (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; }
void writeRenderResources(TextStream& ts, Node* parent) { ASSERT(parent); Node* node = parent; do { if (!node->isSVGElement()) continue; SVGElement* svgElement = static_cast<SVGElement*>(node); if (!svgElement->isStyled()) continue; SVGStyledElement* styled = static_cast<SVGStyledElement*>(svgElement); RefPtr<SVGResource> resource(styled->canvasResource()); if (!resource) continue; String elementId = svgElement->getAttribute(HTMLNames::idAttr); if (resource->isPaintServer()) { RefPtr<SVGPaintServer> paintServer = WTF::static_pointer_cast<SVGPaintServer>(resource); ts << "KRenderingPaintServer {id=\"" << elementId << "\" " << *paintServer << "}" << "\n"; } else ts << "KCanvasResource {id=\"" << elementId << "\" " << *resource << "}" << "\n"; } while ((node = node->traverseNextNode(parent))); }
PassOwnPtr<ImageBuffer> SVGMaskElement::drawMaskerContent(const FloatRect& targetRect, FloatRect& maskDestRect) const { // Determine specified mask size float xValue; float yValue; float widthValue; float heightValue; if (maskUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { xValue = x().valueAsPercentage() * targetRect.width(); yValue = y().valueAsPercentage() * targetRect.height(); widthValue = width().valueAsPercentage() * targetRect.width(); heightValue = height().valueAsPercentage() * targetRect.height(); } else { xValue = x().value(this); yValue = y().value(this); widthValue = width().value(this); heightValue = height().value(this); } IntSize imageSize(lroundf(widthValue), lroundf(heightValue)); clampImageBufferSizeToViewport(document()->view(), imageSize); if (imageSize.width() < static_cast<int>(widthValue)) widthValue = imageSize.width(); if (imageSize.height() < static_cast<int>(heightValue)) heightValue = imageSize.height(); OwnPtr<ImageBuffer> maskImage = ImageBuffer::create(imageSize, false); if (!maskImage) return 0; maskDestRect = FloatRect(xValue, yValue, widthValue, heightValue); if (maskUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) maskDestRect.move(targetRect.x(), targetRect.y()); GraphicsContext* maskImageContext = maskImage->context(); ASSERT(maskImageContext); maskImageContext->save(); maskImageContext->translate(-xValue, -yValue); if (maskContentUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { maskImageContext->save(); maskImageContext->scale(FloatSize(targetRect.width(), targetRect.height())); } // Render subtree into ImageBuffer for (Node* n = firstChild(); n; n = n->nextSibling()) { SVGElement* elem = 0; if (n->isSVGElement()) elem = static_cast<SVGElement*>(n); if (!elem || !elem->isStyled()) continue; SVGStyledElement* e = static_cast<SVGStyledElement*>(elem); RenderObject* item = e->renderer(); if (!item) continue; renderSubtreeToImage(maskImage.get(), item); } if (maskContentUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) maskImageContext->restore(); maskImageContext->restore(); return maskImage.release(); }
void RenderSVGContainer::paint(PaintInfo& paintInfo, int parentX, int parentY) { if (paintInfo.context->paintingDisabled()) return; // This should only exist for <svg> renderers if (hasBoxDecorations() && (paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection)) paintBoxDecorations(paintInfo, m_x + parentX, m_y + parentY); if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && style()->outlineWidth() && style()->visibility() == VISIBLE) paintOutline(paintInfo.context, parentX, parentY, width(), height(), style()); if (paintInfo.phase != PaintPhaseForeground || !drawsContents()) return; const SVGRenderStyle* svgStyle = style()->svgStyle(); AtomicString filterId(SVGURIReference::getTarget(svgStyle->filter())); #if ENABLE(SVG_EXPERIMENTAL_FEATURES) SVGResourceFilter* filter = getFilterById(document(), filterId); #endif if (!firstChild() #if ENABLE(SVG_EXPERIMENTAL_FEATURES) && !filter #endif ) return; // Spec: groups w/o children still may render filter content. paintInfo.context->save(); if (!parent()->isSVGContainer()) { // Translate from parent offsets (html renderers) to a relative transform (svg renderers) IntPoint origin; origin.move(parentX, parentY); origin.move(m_x, m_y); origin.move(borderLeft(), borderTop()); origin.move(paddingLeft(), paddingTop()); if (origin.x() || origin.y()) { paintInfo.context->concatCTM(AffineTransform().translate(origin.x(), origin.y())); paintInfo.rect.move(-origin.x(), -origin.y()); } parentX = parentY = 0; SVGSVGElement* svg = static_cast<SVGSVGElement*>(element()); paintInfo.context->concatCTM(AffineTransform().scale(svg->currentScale())); } else { // Only the root <svg> element should need any translations using the HTML/CSS system // parentX, parentY are also non-zero for first-level kids of these // CSS-transformed <svg> root-elements (due to RenderBox::paint) for any other element // they should be 0. m_x, m_y should always be 0 for non-root svg containers ASSERT(m_x == 0); ASSERT(m_y == 0); } if (!viewport().isEmpty()) { if (style()->overflowX() != OVISIBLE) paintInfo.context->clip(enclosingIntRect(viewport())); // FIXME: Eventually we'll want float-precision clipping paintInfo.context->concatCTM(AffineTransform().translate(viewport().x(), viewport().y())); } if (!localTransform().isIdentity()) paintInfo.context->concatCTM(localTransform()); if (!parent()->isSVGContainer()) { SVGSVGElement* svg = static_cast<SVGSVGElement*>(element()); paintInfo.context->concatCTM(AffineTransform().translate(svg->currentTranslate().x(), svg->currentTranslate().y())); } FloatRect strokeBBox = relativeBBox(true); SVGElement* svgElement = static_cast<SVGElement*>(element()); ASSERT(svgElement && svgElement->document() && svgElement->isStyled()); SVGStyledElement* styledElement = static_cast<SVGStyledElement*>(svgElement); AtomicString clipperId(SVGURIReference::getTarget(svgStyle->clipPath())); AtomicString maskerId(SVGURIReference::getTarget(svgStyle->maskElement())); SVGResourceClipper* clipper = getClipperById(document(), clipperId); SVGResourceMasker* masker = getMaskerById(document(), maskerId); 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); float opacity = style()->opacity(); if (opacity < 1.0f) { paintInfo.context->clip(enclosingIntRect(strokeBBox)); paintInfo.context->beginTransparencyLayer(opacity); } #if ENABLE(SVG_EXPERIMENTAL_FEATURES) if (filter) filter->prepareFilter(paintInfo.context, strokeBBox); else if (!filterId.isEmpty()) svgElement->document()->accessSVGExtensions()->addPendingResource(filterId, styledElement); #endif if (!viewBox().isEmpty()) paintInfo.context->concatCTM(viewportTransform()); RenderContainer::paint(paintInfo, 0, 0); #if ENABLE(SVG_EXPERIMENTAL_FEATURES) if (filter) filter->applyFilter(paintInfo.context, strokeBBox); #endif if (opacity < 1.0f) paintInfo.context->endTransparencyLayer(); paintInfo.context->restore(); }
PassOwnPtr<ImageBuffer> SVGMaskElement::drawMaskerContent(const FloatRect& targetRect, FloatRect& maskDestRect) const { // Determine specified mask size if (maskUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) maskDestRect = FloatRect(x().valueAsPercentage() * targetRect.width(), y().valueAsPercentage() * targetRect.height(), width().valueAsPercentage() * targetRect.width(), height().valueAsPercentage() * targetRect.height()); else maskDestRect = FloatRect(x().value(this), y().value(this), width().value(this), height().value(this)); IntSize imageSize(lroundf(maskDestRect.width()), lroundf(maskDestRect.height())); clampImageBufferSizeToViewport(document()->view(), imageSize); if (imageSize.width() < static_cast<int>(maskDestRect.width())) maskDestRect.setWidth(imageSize.width()); if (imageSize.height() < static_cast<int>(maskDestRect.height())) maskDestRect.setHeight(imageSize.height()); // 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. OwnPtr<ImageBuffer> maskImage = ImageBuffer::create(imageSize, LinearRGB); if (!maskImage) return 0; FloatPoint maskContextLocation = maskDestRect.location(); if (maskUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) maskDestRect.move(targetRect.x(), targetRect.y()); if (maskContentUnits() != SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) maskContextLocation.move(targetRect.x(), targetRect.y()); GraphicsContext* maskImageContext = maskImage->context(); ASSERT(maskImageContext); maskImageContext->save(); maskImageContext->translate(-maskContextLocation.x(), -maskContextLocation.y()); if (maskContentUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { maskImageContext->save(); maskImageContext->scale(FloatSize(targetRect.width(), targetRect.height())); } // Render subtree into ImageBuffer for (Node* n = firstChild(); n; n = n->nextSibling()) { SVGElement* elem = 0; if (n->isSVGElement()) elem = static_cast<SVGElement*>(n); if (!elem || !elem->isStyled()) continue; SVGStyledElement* e = static_cast<SVGStyledElement*>(elem); RenderObject* item = e->renderer(); if (!item) continue; renderSubtreeToImage(maskImage.get(), item); } if (maskContentUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) maskImageContext->restore(); maskImageContext->restore(); return maskImage.release(); }
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(); }
void SVGRenderBase::prepareToRenderSVGContent(RenderObject* object, RenderObject::PaintInfo& paintInfo, const FloatRect& boundingBox, SVGResourceFilter*& filter, SVGResourceFilter* rootFilter) { #if !ENABLE(FILTERS) UNUSED_PARAM(filter); UNUSED_PARAM(rootFilter); #endif ASSERT(object); SVGElement* svgElement = static_cast<SVGElement*>(object->node()); ASSERT(svgElement && svgElement->document() && svgElement->isStyled()); SVGStyledElement* styledElement = static_cast<SVGStyledElement*>(svgElement); const RenderStyle* style = object->style(); ASSERT(style); const SVGRenderStyle* svgStyle = style->svgStyle(); ASSERT(svgStyle); // Setup transparency layers before setting up filters! float opacity = style->opacity(); if (opacity < 1.0f) { paintInfo.context->clip(enclosingIntRect(boundingBox)); paintInfo.context->beginTransparencyLayer(opacity); } #if ENABLE(FILTERS) AtomicString filterId(svgStyle->filter()); #endif AtomicString clipperId(svgStyle->clipPath()); AtomicString maskerId(svgStyle->maskElement()); Document* document = object->document(); #if ENABLE(FILTERS) SVGResourceFilter* newFilter = getFilterById(document, filterId); if (newFilter == rootFilter) { // Catch <text filter="url(#foo)">Test<tspan filter="url(#foo)">123</tspan></text>. // The filter is NOT meant to be applied twice in that case! filter = 0; filterId = String(); } else filter = newFilter; #endif SVGResourceClipper* clipper = getClipperById(document, clipperId); SVGResourceMasker* masker = getMaskerById(document, maskerId); #if ENABLE(FILTERS) if (filter) { filter->addClient(styledElement); filter->prepareFilter(paintInfo.context, object); } 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); }
FloatRect RenderPath::drawMarkersIfNeeded(GraphicsContext* context, const FloatRect&, const Path& path) const { Document* doc = document(); SVGElement* svgElement = static_cast<SVGElement*>(node()); ASSERT(svgElement && svgElement->document() && svgElement->isStyled()); SVGStyledElement* styledElement = static_cast<SVGStyledElement*>(svgElement); const SVGRenderStyle* svgStyle = style()->svgStyle(); AtomicString startMarkerId(svgStyle->startMarker()); AtomicString midMarkerId(svgStyle->midMarker()); AtomicString endMarkerId(svgStyle->endMarker()); SVGResourceMarker* startMarker = getMarkerById(doc, startMarkerId); SVGResourceMarker* midMarker = getMarkerById(doc, midMarkerId); SVGResourceMarker* endMarker = getMarkerById(doc, endMarkerId); if (!startMarker && !startMarkerId.isEmpty()) svgElement->document()->accessSVGExtensions()->addPendingResource(startMarkerId, styledElement); else if (startMarker) startMarker->addClient(styledElement); if (!midMarker && !midMarkerId.isEmpty()) svgElement->document()->accessSVGExtensions()->addPendingResource(midMarkerId, styledElement); else if (midMarker) midMarker->addClient(styledElement); if (!endMarker && !endMarkerId.isEmpty()) svgElement->document()->accessSVGExtensions()->addPendingResource(endMarkerId, styledElement); else if (endMarker) endMarker->addClient(styledElement); if (!startMarker && !midMarker && !endMarker) return FloatRect(); double strokeWidth = SVGRenderStyle::cssPrimitiveToLength(this, svgStyle->strokeWidth(), 1.0f); DrawMarkersData data(context, startMarker, midMarker, strokeWidth); path.apply(&data, drawStartAndMidMarkers); data.previousMarkerData.marker = endMarker; data.previousMarkerData.type = End; drawMarkerWithData(context, data.previousMarkerData); // We know the marker boundaries, only after they're drawn! // Otherwhise we'd need to do all the marker calculation twice // once here (through paint()) and once in absoluteClippedOverflowRect(). FloatRect bounds; if (startMarker) bounds.unite(startMarker->cachedBounds()); if (midMarker) bounds.unite(midMarker->cachedBounds()); if (endMarker) bounds.unite(endMarker->cachedBounds()); return bounds; }
void RenderSVGImage::paint(PaintInfo& paintInfo, int parentX, int parentY) { if (paintInfo.context->paintingDisabled() || (paintInfo.phase != PaintPhaseForeground) || style()->visibility() == HIDDEN) return; paintInfo.context->save(); paintInfo.context->concatCTM(AffineTransform().translate(parentX, parentY)); paintInfo.context->concatCTM(localTransform()); paintInfo.context->concatCTM(translationForAttributes()); FloatRect boundingBox = FloatRect(0, 0, width(), height()); 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, 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); float opacity = style()->opacity(); if (opacity < 1.0f) { paintInfo.context->clip(enclosingIntRect(boundingBox)); paintInfo.context->beginTransparencyLayer(opacity); } PaintInfo pi(paintInfo); pi.rect = absoluteTransform().inverse().mapRect(pi.rect); SVGImageElement* imageElt = static_cast<SVGImageElement*>(node()); FloatRect destRect(m_x, m_y, contentWidth(), contentHeight()); FloatRect srcRect(0, 0, image()->width(), image()->height()); if (imageElt->preserveAspectRatio()->align() != SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_NONE) adjustRectsForAspectRatio(destRect, srcRect, imageElt->preserveAspectRatio()); paintInfo.context->drawImage(image(), destRect, srcRect); #if ENABLE(SVG_EXPERIMENTAL_FEATURES) if (filter) filter->applyFilter(paintInfo.context, boundingBox); #endif if (opacity < 1.0f) paintInfo.context->endTransparencyLayer(); paintInfo.context->restore(); }
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(); }
bool SVGRenderBase::prepareToRenderSVGContent(RenderObject* object, RenderObject::PaintInfo& paintInfo, const FloatRect& repaintRect, RenderSVGResourceFilter*& filter, RenderSVGResourceFilter* rootFilter) { #if !ENABLE(FILTERS) UNUSED_PARAM(filter); UNUSED_PARAM(rootFilter); #endif ASSERT(object); SVGElement* svgElement = static_cast<SVGElement*>(object->node()); ASSERT(svgElement && svgElement->document() && svgElement->isStyled()); SVGStyledElement* styledElement = static_cast<SVGStyledElement*>(svgElement); RenderStyle* style = object->style(); ASSERT(style); const SVGRenderStyle* svgStyle = style->svgStyle(); ASSERT(svgStyle); // Setup transparency layers before setting up filters! float opacity = style->opacity(); if (opacity < 1.0f) { paintInfo.context->clip(repaintRect); paintInfo.context->beginTransparencyLayer(opacity); } if (const ShadowData* shadow = svgStyle->shadow()) { paintInfo.context->clip(repaintRect); paintInfo.context->setShadow(IntSize(shadow->x(), shadow->y()), shadow->blur(), shadow->color(), style->colorSpace()); paintInfo.context->beginTransparencyLayer(1.0f); } #if ENABLE(FILTERS) AtomicString filterId(svgStyle->filterResource()); #endif AtomicString clipperId(svgStyle->clipperResource()); AtomicString maskerId(svgStyle->maskerResource()); Document* document = object->document(); #if ENABLE(FILTERS) RenderSVGResourceFilter* newFilter = getRenderSVGResourceById<RenderSVGResourceFilter>(document, filterId); if (newFilter == rootFilter) { // Catch <text filter="url(#foo)">Test<tspan filter="url(#foo)">123</tspan></text>. // The filter is NOT meant to be applied twice in that case! filter = 0; filterId = String(); } else filter = newFilter; #endif if (RenderSVGResourceMasker* masker = getRenderSVGResourceById<RenderSVGResourceMasker>(document, maskerId)) { if (!masker->applyResource(object, style, paintInfo.context, ApplyToDefaultMode)) return false; } else if (!maskerId.isEmpty()) svgElement->document()->accessSVGExtensions()->addPendingResource(maskerId, styledElement); if (RenderSVGResourceClipper* clipper = getRenderSVGResourceById<RenderSVGResourceClipper>(document, clipperId)) clipper->applyResource(object, style, paintInfo.context, ApplyToDefaultMode); else if (!clipperId.isEmpty()) svgElement->document()->accessSVGExtensions()->addPendingResource(clipperId, styledElement); #if ENABLE(FILTERS) if (filter) { if (!filter->applyResource(object, style, paintInfo.context, ApplyToDefaultMode)) return false; } else if (!filterId.isEmpty()) svgElement->document()->accessSVGExtensions()->addPendingResource(filterId, styledElement); #endif return true; }
void SVGPatternElement::drawPatternContentIntoTile(const SVGPatternElement* target, const IntSize& newSize, KCanvasMatrix patternTransformMatrix) const { KRenderingDevice* device = renderingDevice(); SVGStyledElement* activeElement = static_cast<SVGStyledElement*>(m_paintServer->activeClient()->element()); bool bbox = (patternUnits()->baseVal() == SVG_UNIT_TYPE_OBJECTBOUNDINGBOX); const SVGStyledElement* savedContext = 0; if (bbox) { if (width()->baseVal()->unitType() != SVGLength::SVG_LENGTHTYPE_PERCENTAGE) width()->baseVal()->newValueSpecifiedUnits(SVGLength::SVG_LENGTHTYPE_PERCENTAGE, width()->baseVal()->value() * 100.); if (height()->baseVal()->unitType() != SVGLength::SVG_LENGTHTYPE_PERCENTAGE) height()->baseVal()->newValueSpecifiedUnits(SVGLength::SVG_LENGTHTYPE_PERCENTAGE, height()->baseVal()->value() * 100.); if (activeElement) savedContext = const_cast<SVGPatternElement* >(this)->pushAttributeContext(activeElement); } delete m_tile; m_tile = static_cast<KCanvasImage*>(device->createResource(RS_IMAGE)); m_tile->init(newSize); KRenderingDeviceContext* patternContext = device->contextForImage(m_tile); device->pushContext(patternContext); FloatRect rect(x()->baseVal()->value(), y()->baseVal()->value(), width()->baseVal()->value(), height()->baseVal()->value()); m_paintServer->setBbox(rect); m_paintServer->setPatternTransform(patternTransformMatrix); m_paintServer->setTile(m_tile); OwnPtr<GraphicsContext> context(patternContext->createGraphicsContext()); for(Node *n = target->firstChild(); n != 0; n = n->nextSibling()) { SVGElement* elem = svg_dynamic_cast(n); if (!elem || !elem->isStyled()) continue; SVGStyledElement* e = static_cast<SVGStyledElement* >(elem); RenderObject *item = e->renderer(); if (!item) continue; #if 0 // FIXME: None of this code seems to be necessary // to pass the w3c tests (and infact breaks them) // However, I'm leaving it #if 0'd for now until // I can quiz WildFox on the subject -- ecs 11/24/05 // It's possible that W3C-SVG-1.1/coords-units-01-b // is failing due to lack of this code. KCanvasMatrix savedMatrix = item->localTransform(); const SVGStyledElement* savedContext = 0; if (patternContentUnits()->baseVal() == SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { if (activeElement) savedContext = e->pushAttributeContext(activeElement); } // Take into account viewportElement's viewBox, if existant... if (viewportElement() && viewportElement()->hasTagName(SVGNames::svgTag)) { SVGSVGElement* svgElement = static_cast<SVGSVGElement* >(viewportElement()); RefPtr<SVGMatrix> svgCTM = svgElement->getCTM(); RefPtr<SVGMatrix> ctm = getCTM(); KCanvasMatrix newMatrix(svgCTM->matrix()); newMatrix.multiply(savedMatrix); newMatrix.scale(1.0 / ctm->a(), 1.0 / ctm->d()); item->setLocalTransform(newMatrix.matrix()); } #endif RenderObject::PaintInfo info(context.get(), IntRect(), PaintPhaseForeground, 0, 0, 0); item->paint(info, 0, 0); #if 0 if (savedContext) e->pushAttributeContext(savedContext); item->setLocalTransform(savedMatrix.matrix()); #endif } if (savedContext) const_cast<SVGPatternElement* >(this)->pushAttributeContext(savedContext); device->popContext(); delete patternContext; }