https://www.w3.org/TR/SVG11/pservers.html#PatternElementHrefAttribute * * Any attributes which are defined on the referenced element which are not defined on this element * are inherited by this element. If this element has no children, and the referenced element does * (possibly due to its own ‘xlink:href’ attribute), then this element inherits the children from * the referenced element. Inh
| 82 | * the current element can inherit those attributes or children. |
| 83 | */ |
| 84 | const SVGPattern* SVGPattern::resolveHref(const SVGRenderContext& context, |
| 85 | PatternAttributes* attrs) const { |
| 86 | const SVGPattern* currentNode = this; |
| 87 | const SVGPattern* contentNode = this; |
| 88 | |
| 89 | do { |
| 90 | // Bitwise OR to avoid short-circuiting. |
| 91 | const bool didInherit = |
| 92 | inherit_if_needed(currentNode->X, attrs->x) | inherit_if_needed(currentNode->Y, attrs->y) | |
| 93 | inherit_if_needed(currentNode->Width, attrs->width) | |
| 94 | inherit_if_needed(currentNode->Height, attrs->height) | |
| 95 | inherit_if_needed(currentNode->PatternTransform, attrs->patternTransform); |
| 96 | |
| 97 | if (!contentNode->hasChildren()) { |
| 98 | contentNode = currentNode; |
| 99 | } |
| 100 | |
| 101 | if (contentNode->hasChildren() && !didInherit) { |
| 102 | // All attributes have been resolved, and a valid content node has been found. |
| 103 | // We can terminate the href chain early. |
| 104 | break; |
| 105 | } |
| 106 | |
| 107 | currentNode = currentNode->hrefTarget(context); |
| 108 | } while (currentNode); |
| 109 | |
| 110 | // To unify with Chrome and macOS preview, the width and height attributes here need to be |
| 111 | // converted to percentages, direct numbers are not supported. |
| 112 | if (PatternUnits.type() == SVGObjectBoundingBoxUnits::Type::UserSpaceOnUse) { |
| 113 | if (attrs->width.has_value() && attrs->width->unit() == SVGLength::Unit::Percentage) { |
| 114 | attrs->width = SVGLength(attrs->width->value() / 100.f, SVGLength::Unit::Number); |
| 115 | } |
| 116 | if (attrs->height.has_value() && attrs->height->unit() == SVGLength::Unit::Percentage) { |
| 117 | attrs->height = SVGLength(attrs->height->value() / 100.f, SVGLength::Unit::Number); |
| 118 | } |
| 119 | } else if (PatternUnits.type() == SVGObjectBoundingBoxUnits::Type::ObjectBoundingBox) { |
| 120 | if (attrs->width.has_value() && attrs->width->unit() == SVGLength::Unit::Number) { |
| 121 | attrs->width = SVGLength(attrs->width->value() * 100.f, SVGLength::Unit::Percentage); |
| 122 | } |
| 123 | if (attrs->height.has_value() && attrs->height->unit() == SVGLength::Unit::Number) { |
| 124 | attrs->height = SVGLength(attrs->height->value() * 100.f, SVGLength::Unit::Percentage); |
| 125 | } |
| 126 | } |
| 127 | |
| 128 | return contentNode; |
| 129 | } |
| 130 | |
| 131 | bool SVGPattern::onAsPaint(const SVGRenderContext& context, Paint* paint) const { |
| 132 | PatternAttributes attrs; |
no test coverage detected