15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/*
25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (C) 2004, 2005, 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (C) 2004, 2005, 2006, 2007, 2008 Rob Buis <buis@kde.org>
45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * This library is free software; you can redistribute it and/or
75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * modify it under the terms of the GNU Library General Public
85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * License as published by the Free Software Foundation; either
95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * version 2 of the License, or (at your option) any later version.
105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * This library is distributed in the hope that it will be useful,
125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * but WITHOUT ANY WARRANTY; without even the implied warranty of
135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Library General Public License for more details.
155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * You should have received a copy of the GNU Library General Public License
175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * along with this library; see the file COPYING.LIB.  If not, write to
185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Boston, MA 02110-1301, USA.
205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "config.h"
235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/rendering/svg/RenderSVGResourceMarker.h"
255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
265d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)#include "core/rendering/PaintInfo.h"
2753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/rendering/svg/RenderSVGContainer.h"
2853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/rendering/svg/SVGRenderSupport.h"
29a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)#include "platform/graphics/GraphicsContextStateSaver.h"
305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
311e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)#include "wtf/TemporaryChange.h"
321e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)
33c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)namespace blink {
345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
35f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)const RenderSVGResourceType RenderSVGResourceMarker::s_resourceType = MarkerResourceType;
365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)RenderSVGResourceMarker::RenderSVGResourceMarker(SVGMarkerElement* node)
385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    : RenderSVGResourceContainer(node)
395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)RenderSVGResourceMarker::~RenderSVGResourceMarker()
435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void RenderSVGResourceMarker::layout()
475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
481e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    ASSERT(needsLayout());
491e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    if (m_isInLayout)
501e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)        return;
511e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)
521e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    TemporaryChange<bool> inLayoutChange(m_isInLayout, true);
531e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)
545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // RenderSVGHiddenContainer overwrites layout(). We need the
555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // layouting of RenderSVGContainer for calculating  local
56e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles)    // transformations and paint invalidation.
575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    RenderSVGContainer::layout();
5851b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)
5951b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    clearInvalidationMask();
605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void RenderSVGResourceMarker::removeAllClientsFromCache(bool markForInvalidation)
635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    markAllClientsForInvalidation(markForInvalidation ? LayoutAndBoundariesInvalidation : ParentOnlyInvalidation);
655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void RenderSVGResourceMarker::removeClientFromCache(RenderObject* client, bool markForInvalidation)
685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ASSERT(client);
705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    markClientForInvalidation(client, markForInvalidation ? BoundariesInvalidation : ParentOnlyInvalidation);
715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void RenderSVGResourceMarker::applyViewportClip(PaintInfo& paintInfo)
745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (SVGRenderSupport::isOverflowHidden(this))
765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        paintInfo.context->clip(m_viewport);
775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)FloatRect RenderSVGResourceMarker::markerBoundaries(const AffineTransform& markerTransformation) const
805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
815d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)    FloatRect coordinates = RenderSVGContainer::paintInvalidationRectInLocalCoordinates();
825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
83e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles)    // Map paint invalidation rect into parent coordinate space, in which the marker boundaries have to be evaluated
845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    coordinates = localToParentTransform().mapRect(coordinates);
855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return markerTransformation.mapRect(coordinates);
875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)const AffineTransform& RenderSVGResourceMarker::localToParentTransform() const
905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_localToParentTransform = AffineTransform::translation(m_viewport.x(), m_viewport.y()) * viewportTransform();
925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return m_localToParentTransform;
935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // If this class were ever given a localTransform(), then the above would read:
945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // return viewportTranslation * localTransform() * viewportTransform();
955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)FloatPoint RenderSVGResourceMarker::referencePoint() const
985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
998abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)    SVGMarkerElement* marker = toSVGMarkerElement(element());
1005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ASSERT(marker);
1015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    SVGLengthContext lengthContext(marker);
10309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    return FloatPoint(marker->refX()->currentValue()->value(lengthContext), marker->refY()->currentValue()->value(lengthContext));
1045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)float RenderSVGResourceMarker::angle() const
1075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1088abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)    SVGMarkerElement* marker = toSVGMarkerElement(element());
1095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ASSERT(marker);
1105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    float angle = -1;
112d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    if (marker->orientType()->currentValue()->enumValue() == SVGMarkerOrientAngle)
113d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        angle = marker->orientAngle()->currentValue()->value();
1145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return angle;
1165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)AffineTransform RenderSVGResourceMarker::markerTransformation(const FloatPoint& origin, float autoAngle, float strokeWidth) const
1195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1208abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)    SVGMarkerElement* marker = toSVGMarkerElement(element());
1215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ASSERT(marker);
1225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    float markerAngle = angle();
124d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    bool useStrokeWidth = marker->markerUnits()->currentValue()->enumValue() == SVGMarkerUnitsStrokeWidth;
1255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    AffineTransform transform;
1275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    transform.translate(origin.x(), origin.y());
1285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    transform.rotate(markerAngle == -1 ? autoAngle : markerAngle);
1295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    transform = markerContentTransformation(transform, referencePoint(), useStrokeWidth ? strokeWidth : -1);
1305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return transform;
1315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void RenderSVGResourceMarker::draw(PaintInfo& paintInfo, const AffineTransform& transform)
1345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
13551b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    clearInvalidationMask();
13651b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)
137926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    // An empty viewBox disables rendering.
1388abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)    SVGMarkerElement* marker = toSVGMarkerElement(element());
139926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    ASSERT(marker);
14009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    if (marker->hasAttribute(SVGNames::viewBoxAttr) && marker->viewBox()->currentValue()->isValid() && marker->viewBox()->currentValue()->value().isEmpty())
141926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        return;
142926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
1435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    PaintInfo info(paintInfo);
14409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    GraphicsContextStateSaver stateSaver(*info.context, false);
1457242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    info.applyTransform(transform, &stateSaver);
1465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    RenderSVGContainer::paint(info, IntPoint());
1475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)AffineTransform RenderSVGResourceMarker::markerContentTransformation(const AffineTransform& contentTransformation, const FloatPoint& origin, float strokeWidth) const
1505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // The 'origin' coordinate maps to SVGs refX/refY, given in coordinates relative to the viewport established by the marker
1525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    FloatPoint mappedOrigin = viewportTransform().mapPoint(origin);
1535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    AffineTransform transformation = contentTransformation;
1555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (strokeWidth != -1)
1565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        transformation.scaleNonUniform(strokeWidth, strokeWidth);
1575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    transformation.translate(-mappedOrigin.x(), -mappedOrigin.y());
1595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return transformation;
1605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)AffineTransform RenderSVGResourceMarker::viewportTransform() const
1635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1648abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)    SVGMarkerElement* marker = toSVGMarkerElement(element());
1655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ASSERT(marker);
1665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return marker->viewBoxToViewTransform(m_viewport.width(), m_viewport.height());
1685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void RenderSVGResourceMarker::calcViewport()
1715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!selfNeedsLayout())
1735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
1745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1758abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)    SVGMarkerElement* marker = toSVGMarkerElement(element());
1765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ASSERT(marker);
17702772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
1785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    SVGLengthContext lengthContext(marker);
17909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    float w = marker->markerWidth()->currentValue()->value(lengthContext);
18009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    float h = marker->markerHeight()->currentValue()->value(lengthContext);
1815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_viewport = FloatRect(0, 0, w, h);
1825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
185