• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KHTML

SVGPatternElement.cpp

Go to the documentation of this file.
00001 /*
00002     Copyright (C) 2004, 2005, 2006, 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
00003                   2004, 2005, 2006, 2007 Rob Buis <buis@kde.org>
00004 
00005     This file is part of the KDE project
00006 
00007     This library is free software; you can redistribute it and/or
00008     modify it under the terms of the GNU Library General Public
00009     License as published by the Free Software Foundation; either
00010     version 2 of the License, or (at your option) any later version.
00011 
00012     This library is distributed in the hope that it will be useful,
00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015     Library General Public License for more details.
00016 
00017     You should have received a copy of the GNU Library General Public License
00018     along with this library; see the file COPYING.LIB.  If not, write to
00019     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00020     Boston, MA 02110-1301, USA.
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     // If we didn't find any pattern content, ignore the request.
00162     if (!attributes.patternContentElement() || !renderer() || !renderer()->style())
00163         return;
00164 
00165     FloatRect patternBoundaries; 
00166     FloatRect patternContentBoundaries;
00167 
00168     // Determine specified pattern size
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     // Clip pattern boundaries to target boundaries
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     // Eventually calculate the pattern content boundaries (only needed with overflow="visible").
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     // Apply objectBoundingBoxMode fixup for patternContentUnits, if viewBox is not set.
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     // Move to pattern start origin
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     // Process viewBox or boundingBoxModeContent correction
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     // Render subtree into ImageBuffer
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         // Respect xlink:href, take attributes from referenced element
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             // Cycle detection
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)

KHTML

Skip menu "KHTML"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.7
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal