00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "config.h"
00024
00025 #if ENABLE(SVG)
00026 #include "SVGPatternElement.h"
00027
00028 #include "AffineTransform.h"
00029 #include "Document.h"
00030 #include "FloatConversion.h"
00031 #include "GraphicsContext.h"
00032 #include "ImageBuffer.h"
00033 #include "PatternAttributes.h"
00034 #include "RenderSVGContainer.h"
00035 #include "SVGLength.h"
00036 #include "SVGNames.h"
00037 #include "SVGPaintServerPattern.h"
00038 #include "SVGRenderSupport.h"
00039 #include "SVGStyledTransformableElement.h"
00040 #include "SVGSVGElement.h"
00041 #include "SVGTransformList.h"
00042 #include "SVGTransformable.h"
00043 #include "SVGUnitTypes.h"
00044
00045 #include <math.h>
00046 #include <wtf/OwnPtr.h>
00047 #include <wtf/MathExtras.h>
00048
00049 using namespace std;
00050
00051 namespace WebCore {
00052
00053 SVGPatternElement::SVGPatternElement(const QualifiedName& tagName, Document* doc)
00054 : SVGStyledElement(tagName, doc)
00055 , SVGURIReference()
00056 , SVGTests()
00057 , SVGLangSpace()
00058 , SVGExternalResourcesRequired()
00059 , SVGFitToViewBox()
00060 , m_x(this, LengthModeWidth)
00061 , m_y(this, LengthModeHeight)
00062 , m_width(this, LengthModeWidth)
00063 , m_height(this, LengthModeHeight)
00064 , m_patternUnits(SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX)
00065 , m_patternContentUnits(SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE)
00066 , m_patternTransform(SVGTransformList::create(SVGNames::patternTransformAttr))
00067 {
00068 }
00069
00070 SVGPatternElement::~SVGPatternElement()
00071 {
00072 }
00073
00074 ANIMATED_PROPERTY_DEFINITIONS(SVGPatternElement, int, Enumeration, enumeration, PatternUnits, patternUnits, SVGNames::patternUnitsAttr, m_patternUnits)
00075 ANIMATED_PROPERTY_DEFINITIONS(SVGPatternElement, int, Enumeration, enumeration, PatternContentUnits, patternContentUnits, SVGNames::patternContentUnitsAttr, m_patternContentUnits)
00076 ANIMATED_PROPERTY_DEFINITIONS(SVGPatternElement, SVGLength, Length, length, X, x, SVGNames::xAttr, m_x)
00077 ANIMATED_PROPERTY_DEFINITIONS(SVGPatternElement, SVGLength, Length, length, Y, y, SVGNames::yAttr, m_y)
00078 ANIMATED_PROPERTY_DEFINITIONS(SVGPatternElement, SVGLength, Length, length, Width, width, SVGNames::widthAttr, m_width)
00079 ANIMATED_PROPERTY_DEFINITIONS(SVGPatternElement, SVGLength, Length, length, Height, height, SVGNames::heightAttr, m_height)
00080 ANIMATED_PROPERTY_DEFINITIONS(SVGPatternElement, SVGTransformList*, TransformList, transformList, PatternTransform, patternTransform, SVGNames::patternTransformAttr, m_patternTransform.get())
00081
00082 void SVGPatternElement::parseMappedAttribute(MappedAttribute* attr)
00083 {
00084 if (attr->name() == SVGNames::patternUnitsAttr) {
00085 if (attr->value() == "userSpaceOnUse")
00086 setPatternUnitsBaseValue(SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE);
00087 else if (attr->value() == "objectBoundingBox")
00088 setPatternUnitsBaseValue(SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX);
00089 } else if (attr->name() == SVGNames::patternContentUnitsAttr) {
00090 if (attr->value() == "userSpaceOnUse")
00091 setPatternContentUnitsBaseValue(SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE);
00092 else if (attr->value() == "objectBoundingBox")
00093 setPatternContentUnitsBaseValue(SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX);
00094 } else if (attr->name() == SVGNames::patternTransformAttr) {
00095 SVGTransformList* patternTransforms = patternTransformBaseValue();
00096 if (!SVGTransformable::parseTransformAttribute(patternTransforms, attr->value())) {
00097 ExceptionCode ec = 0;
00098 patternTransforms->clear(ec);
00099 }
00100 } else if (attr->name() == SVGNames::xAttr)
00101 setXBaseValue(SVGLength(this, LengthModeWidth, attr->value()));
00102 else if (attr->name() == SVGNames::yAttr)
00103 setYBaseValue(SVGLength(this, LengthModeHeight, attr->value()));
00104 else if (attr->name() == SVGNames::widthAttr) {
00105 setWidthBaseValue(SVGLength(this, LengthModeWidth, attr->value()));
00106 if (width().value() < 0.0)
00107 document()->accessSVGExtensions()->reportError("A negative value for pattern attribute <width> is not allowed");
00108 } else if (attr->name() == SVGNames::heightAttr) {
00109 setHeightBaseValue(SVGLength(this, LengthModeHeight, attr->value()));
00110 if (width().value() < 0.0)
00111 document()->accessSVGExtensions()->reportError("A negative value for pattern attribute <height> is not allowed");
00112 } else {
00113 if (SVGURIReference::parseMappedAttribute(attr))
00114 return;
00115 if (SVGTests::parseMappedAttribute(attr))
00116 return;
00117 if (SVGLangSpace::parseMappedAttribute(attr))
00118 return;
00119 if (SVGExternalResourcesRequired::parseMappedAttribute(attr))
00120 return;
00121 if (SVGFitToViewBox::parseMappedAttribute(attr))
00122 return;
00123
00124 SVGStyledElement::parseMappedAttribute(attr);
00125 }
00126 }
00127
00128 void SVGPatternElement::svgAttributeChanged(const QualifiedName& attrName)
00129 {
00130 SVGStyledElement::svgAttributeChanged(attrName);
00131
00132 if (!m_resource)
00133 return;
00134
00135 if (attrName == SVGNames::patternUnitsAttr || attrName == SVGNames::patternContentUnitsAttr ||
00136 attrName == SVGNames::patternTransformAttr || attrName == SVGNames::xAttr || attrName == SVGNames::yAttr ||
00137 attrName == SVGNames::widthAttr || attrName == SVGNames::heightAttr ||
00138 SVGURIReference::isKnownAttribute(attrName) ||
00139 SVGTests::isKnownAttribute(attrName) ||
00140 SVGLangSpace::isKnownAttribute(attrName) ||
00141 SVGExternalResourcesRequired::isKnownAttribute(attrName) ||
00142 SVGFitToViewBox::isKnownAttribute(attrName) ||
00143 SVGStyledElement::isKnownAttribute(attrName))
00144 m_resource->invalidate();
00145 }
00146
00147 void SVGPatternElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
00148 {
00149 SVGStyledElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
00150
00151 if (!m_resource)
00152 return;
00153
00154 m_resource->invalidate();
00155 }
00156
00157 void SVGPatternElement::buildPattern(const FloatRect& targetRect) const
00158 {
00159 PatternAttributes attributes = collectPatternProperties();
00160
00161
00162 if (!attributes.patternContentElement() || !renderer() || !renderer()->style())
00163 return;
00164
00165 FloatRect patternBoundaries;
00166 FloatRect patternContentBoundaries;
00167
00168
00169 if (attributes.boundingBoxMode())
00170 patternBoundaries = FloatRect(attributes.x().valueAsPercentage() * targetRect.width(),
00171 attributes.y().valueAsPercentage() * targetRect.height(),
00172 attributes.width().valueAsPercentage() * targetRect.width(),
00173 attributes.height().valueAsPercentage() * targetRect.height());
00174 else
00175 patternBoundaries = FloatRect(attributes.x().value(),
00176 attributes.y().value(),
00177 attributes.width().value(),
00178 attributes.height().value());
00179
00180
00181 if (patternBoundaries.width() > targetRect.width())
00182 patternBoundaries.setWidth(targetRect.width());
00183
00184 if (patternBoundaries.height() > targetRect.height())
00185 patternBoundaries.setHeight(targetRect.height());
00186
00187 IntSize patternSize(patternBoundaries.width(), patternBoundaries.height());
00188 clampImageBufferSizeToViewport(document()->renderer(), patternSize);
00189
00190 if (patternSize.width() < static_cast<int>(patternBoundaries.width()))
00191 patternBoundaries.setWidth(patternSize.width());
00192
00193 if (patternSize.height() < static_cast<int>(patternBoundaries.height()))
00194 patternBoundaries.setHeight(patternSize.height());
00195
00196
00197 RenderStyle* style = renderer()->style();
00198 if (style->overflowX() == OVISIBLE && style->overflowY() == OVISIBLE) {
00199 for (Node* n = attributes.patternContentElement()->firstChild(); n; n = n->nextSibling()) {
00200 if (!n->isSVGElement() || !static_cast<SVGElement*>(n)->isStyledTransformable() || !n->renderer())
00201 continue;
00202 patternContentBoundaries.unite(n->renderer()->relativeBBox(true));
00203 }
00204 }
00205
00206 AffineTransform viewBoxCTM = viewBoxToViewTransform(patternBoundaries.width(), patternBoundaries.height());
00207 FloatRect patternBoundariesIncludingOverflow = patternBoundaries;
00208
00209
00210 if (!patternContentBoundaries.isEmpty()) {
00211 if (!viewBoxCTM.isIdentity())
00212 patternContentBoundaries = viewBoxCTM.mapRect(patternContentBoundaries);
00213 else if (attributes.boundingBoxModeContent())
00214 patternContentBoundaries = FloatRect(patternContentBoundaries.x() * targetRect.width(),
00215 patternContentBoundaries.y() * targetRect.height(),
00216 patternContentBoundaries.width() * targetRect.width(),
00217 patternContentBoundaries.height() * targetRect.height());
00218
00219 patternBoundariesIncludingOverflow.unite(patternContentBoundaries);
00220 }
00221
00222 IntSize imageSize(lroundf(patternBoundariesIncludingOverflow.width()), lroundf(patternBoundariesIncludingOverflow.height()));
00223 clampImageBufferSizeToViewport(document()->renderer(), imageSize);
00224
00225 auto_ptr<ImageBuffer> patternImage = ImageBuffer::create(imageSize, false);
00226
00227 if (!patternImage.get())
00228 return;
00229
00230 GraphicsContext* context = patternImage->context();
00231 ASSERT(context);
00232
00233 context->save();
00234
00235
00236 if (patternBoundariesIncludingOverflow.location() != patternBoundaries.location()) {
00237 context->translate(patternBoundaries.x() - patternBoundariesIncludingOverflow.x(),
00238 patternBoundaries.y() - patternBoundariesIncludingOverflow.y());
00239
00240 patternBoundaries.setLocation(patternBoundariesIncludingOverflow.location());
00241 }
00242
00243
00244 if (!viewBoxCTM.isIdentity())
00245 context->concatCTM(viewBoxCTM);
00246 else if (attributes.boundingBoxModeContent()) {
00247 context->translate(targetRect.x(), targetRect.y());
00248 context->scale(FloatSize(targetRect.width(), targetRect.height()));
00249 }
00250
00251
00252 for (Node* n = attributes.patternContentElement()->firstChild(); n; n = n->nextSibling()) {
00253 if (!n->isSVGElement() || !static_cast<SVGElement*>(n)->isStyled() || !n->renderer())
00254 continue;
00255 renderSubtreeToImage(patternImage.get(), n->renderer());
00256 }
00257
00258 context->restore();
00259
00260 m_resource->setPatternTransform(attributes.patternTransform());
00261 m_resource->setPatternBoundaries(patternBoundaries);
00262 m_resource->setTile(patternImage);
00263 }
00264
00265 RenderObject* SVGPatternElement::createRenderer(RenderArena* arena, RenderStyle*)
00266 {
00267 RenderSVGContainer* patternContainer = new (arena) RenderSVGContainer(this);
00268 patternContainer->setDrawsContents(false);
00269 return patternContainer;
00270 }
00271
00272 SVGResource* SVGPatternElement::canvasResource()
00273 {
00274 if (!m_resource)
00275 m_resource = SVGPaintServerPattern::create(this);
00276
00277 return m_resource.get();
00278 }
00279
00280 PatternAttributes SVGPatternElement::collectPatternProperties() const
00281 {
00282 PatternAttributes attributes;
00283 HashSet<const SVGPatternElement*> processedPatterns;
00284
00285 const SVGPatternElement* current = this;
00286 while (current) {
00287 if (!attributes.hasX() && current->hasAttribute(SVGNames::xAttr))
00288 attributes.setX(current->x());
00289
00290 if (!attributes.hasY() && current->hasAttribute(SVGNames::yAttr))
00291 attributes.setY(current->y());
00292
00293 if (!attributes.hasWidth() && current->hasAttribute(SVGNames::widthAttr))
00294 attributes.setWidth(current->width());
00295
00296 if (!attributes.hasHeight() && current->hasAttribute(SVGNames::heightAttr))
00297 attributes.setHeight(current->height());
00298
00299 if (!attributes.hasBoundingBoxMode() && current->hasAttribute(SVGNames::patternUnitsAttr))
00300 attributes.setBoundingBoxMode(current->getAttribute(SVGNames::patternUnitsAttr) == "objectBoundingBox");
00301
00302 if (!attributes.hasBoundingBoxModeContent() && current->hasAttribute(SVGNames::patternContentUnitsAttr))
00303 attributes.setBoundingBoxModeContent(current->getAttribute(SVGNames::patternContentUnitsAttr) == "objectBoundingBox");
00304
00305 if (!attributes.hasPatternTransform() && current->hasAttribute(SVGNames::patternTransformAttr))
00306 attributes.setPatternTransform(current->patternTransform()->consolidate().matrix());
00307
00308 if (!attributes.hasPatternContentElement() && current->hasChildNodes())
00309 attributes.setPatternContentElement(current);
00310
00311 processedPatterns.add(current);
00312
00313
00314 Node* refNode = ownerDocument()->getElementById(SVGURIReference::getTarget(current->href()));
00315 if (refNode && refNode->hasTagName(SVGNames::patternTag)) {
00316 current = static_cast<const SVGPatternElement*>(const_cast<const Node*>(refNode));
00317
00318
00319 if (processedPatterns.contains(current))
00320 return PatternAttributes();
00321 } else
00322 current = 0;
00323 }
00324
00325 return attributes;
00326 }
00327
00328 }
00329
00330 #endif // ENABLE(SVG)