void SVGRadialGradientElement::buildGradient() const { RadialGradientAttributes attributes = collectGradientProperties(); RefPtr<SVGPaintServerRadialGradient> radialGradient = WTF::static_pointer_cast<SVGPaintServerRadialGradient>(m_resource); double adjustedFocusX = attributes.fx(); double adjustedFocusY = attributes.fy(); double fdx = attributes.fx() - attributes.cx(); double fdy = attributes.fy() - attributes.cy(); // Spec: If (fx, fy) lies outside the circle defined by (cx, cy) and // r, set (fx, fy) to the point of intersection of the line through // (fx, fy) and the circle. if (sqrt(fdx * fdx + fdy * fdy) > attributes.r()) { double angle = atan2(attributes.fy() * 100.0, attributes.fx() * 100.0); adjustedFocusX = cos(angle) * attributes.r(); adjustedFocusY = sin(angle) * attributes.r(); } FloatPoint focalPoint = FloatPoint::narrowPrecision(attributes.fx(), attributes.fy()); FloatPoint centerPoint = FloatPoint::narrowPrecision(attributes.cx(), attributes.cy()); RefPtr<Gradient> gradient = Gradient::create( FloatPoint::narrowPrecision(adjustedFocusX, adjustedFocusY), 0.f, // SVG does not support a "focus radius" centerPoint, narrowPrecisionToFloat(attributes.r())); gradient->setSpreadMethod(attributes.spreadMethod()); Vector<SVGGradientStop> stops = attributes.stops(); float previousOffset = 0.0f; for (unsigned i = 0; i < stops.size(); ++i) { float offset = std::min(std::max(previousOffset, stops[i].first), 1.0f); previousOffset = offset; gradient->addColorStop(offset, stops[i].second); } radialGradient->setGradient(gradient); if (attributes.stops().isEmpty()) return; radialGradient->setBoundingBoxMode(attributes.boundingBoxMode()); radialGradient->setGradientTransform(attributes.gradientTransform()); radialGradient->setGradientCenter(centerPoint); radialGradient->setGradientFocal(focalPoint); radialGradient->setGradientRadius(narrowPrecisionToFloat(attributes.r())); radialGradient->setGradientStops(attributes.stops()); }
void SVGRadialGradientElement::buildGradient() const { RadialGradientAttributes attributes = collectGradientProperties(); // If we didn't find any gradient containing stop elements, ignore the request. if (attributes.stops().isEmpty()) return; RefPtr<SVGPaintServerRadialGradient> radialGradient = WTF::static_pointer_cast<SVGPaintServerRadialGradient>(m_resource); radialGradient->setGradientStops(attributes.stops()); radialGradient->setBoundingBoxMode(attributes.boundingBoxMode()); radialGradient->setGradientSpreadMethod(attributes.spreadMethod()); radialGradient->setGradientTransform(attributes.gradientTransform()); radialGradient->setGradientCenter(FloatPoint::narrowPrecision(attributes.cx(), attributes.cy())); radialGradient->setGradientFocal(FloatPoint::narrowPrecision(attributes.fx(), attributes.fy())); radialGradient->setGradientRadius(narrowPrecisionToFloat(attributes.r())); }
bool SVGRadialGradientElement::collectGradientAttributes(RadialGradientAttributes& attributes) { if (!renderer()) return false; WillBeHeapHashSet<RawPtrWillBeMember<SVGGradientElement> > processedGradients; SVGGradientElement* current = this; setGradientAttributes(current, attributes); processedGradients.add(current); while (true) { // Respect xlink:href, take attributes from referenced element Node* refNode = SVGURIReference::targetElementFromIRIString(current->href()->currentValue()->value(), treeScope()); if (refNode && isSVGGradientElement(*refNode)) { current = toSVGGradientElement(refNode); // Cycle detection if (processedGradients.contains(current)) break; if (!current->renderer()) return false; setGradientAttributes(current, attributes, isSVGRadialGradientElement(*current)); processedGradients.add(current); } else { break; } } // Handle default values for fx/fy if (!attributes.hasFx()) attributes.setFx(attributes.cx()); if (!attributes.hasFy()) attributes.setFy(attributes.cy()); return true; }
bool SVGRadialGradientElement::collectGradientAttributes(RadialGradientAttributes& attributes) { if (!renderer()) return false; HashSet<SVGGradientElement*> processedGradients; SVGGradientElement* current = this; setGradientAttributes(*current, attributes); processedGradients.add(current); while (true) { // Respect xlink:href, take attributes from referenced element Node* refNode = SVGURIReference::targetElementFromIRIString(current->href(), document()); if (is<SVGGradientElement>(refNode)) { current = downcast<SVGGradientElement>(refNode); // Cycle detection if (processedGradients.contains(current)) break; if (!current->renderer()) return false; setGradientAttributes(*current, attributes, current->hasTagName(SVGNames::radialGradientTag)); processedGradients.add(current); } else break; } // Handle default values for fx/fy if (!attributes.hasFx()) attributes.setFx(attributes.cx()); if (!attributes.hasFy()) attributes.setFy(attributes.cy()); return true; }
RadialGradientAttributes SVGRadialGradientElement::collectGradientProperties() const { RadialGradientAttributes attributes; HashSet<const SVGGradientElement*> processedGradients; bool isRadial = true; const SVGGradientElement* current = this; while (current) { if (!attributes.hasSpreadMethod() && current->hasAttribute(SVGNames::spreadMethodAttr)) attributes.setSpreadMethod((GradientSpreadMethod) current->spreadMethod()); if (!attributes.hasBoundingBoxMode() && current->hasAttribute(SVGNames::gradientUnitsAttr)) attributes.setBoundingBoxMode(current->gradientUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX); if (!attributes.hasGradientTransform() && current->hasAttribute(SVGNames::gradientTransformAttr)) attributes.setGradientTransform(current->gradientTransform()->consolidate().matrix()); if (!attributes.hasStops()) { const Vector<SVGGradientStop>& stops(current->buildStops()); if (!stops.isEmpty()) attributes.setStops(stops); } if (isRadial) { const SVGRadialGradientElement* radial = static_cast<const SVGRadialGradientElement*>(current); if (!attributes.hasCx() && current->hasAttribute(SVGNames::cxAttr)) attributes.setCx(radial->cx().valueAsPercentage()); if (!attributes.hasCy() && current->hasAttribute(SVGNames::cyAttr)) attributes.setCy(radial->cy().valueAsPercentage()); if (!attributes.hasR() && current->hasAttribute(SVGNames::rAttr)) attributes.setR(radial->r().valueAsPercentage()); if (!attributes.hasFx() && current->hasAttribute(SVGNames::fxAttr)) attributes.setFx(radial->fx().valueAsPercentage()); if (!attributes.hasFy() && current->hasAttribute(SVGNames::fyAttr)) attributes.setFy(radial->fy().valueAsPercentage()); } processedGradients.add(current); // Respect xlink:href, take attributes from referenced element Node* refNode = ownerDocument()->getElementById(SVGURIReference::getTarget(current->href())); if (refNode && (refNode->hasTagName(SVGNames::radialGradientTag) || refNode->hasTagName(SVGNames::linearGradientTag))) { current = static_cast<const SVGGradientElement*>(const_cast<const Node*>(refNode)); // Cycle detection if (processedGradients.contains(current)) return RadialGradientAttributes(); isRadial = current->gradientType() == RadialGradientPaintServer; } else current = 0; } // Handle default values for fx/fy if (!attributes.hasFx()) attributes.setFx(attributes.cx()); if (!attributes.hasFy()) attributes.setFy(attributes.cy()); return attributes; }
FloatPoint RenderSVGResourceRadialGradient::centerPoint(const RadialGradientAttributes& attributes) const { return SVGLengthContext::resolvePoint(static_cast<const SVGElement*>(node()), attributes.gradientUnits(), attributes.cx(), attributes.cy()); }
FloatPoint LayoutSVGResourceRadialGradient::centerPoint(const RadialGradientAttributes& attributes) const { return SVGLengthContext::resolvePoint(element(), attributes.gradientUnits(), *attributes.cx(), *attributes.cy()); }