Upstream version 8.37.180.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / rendering / svg / RenderSVGForeignObject.cpp
1 /*
2  * Copyright (C) 2006 Apple Computer, Inc.
3  * Copyright (C) 2009 Google, Inc.
4  * Copyright (C) Research In Motion Limited 2010. All rights reserved.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public License
17  * along with this library; see the file COPYING.LIB.  If not, write to
18  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21
22 #include "config.h"
23
24 #include "core/rendering/svg/RenderSVGForeignObject.h"
25
26 #include "core/rendering/HitTestResult.h"
27 #include "core/rendering/LayoutRepainter.h"
28 #include "core/rendering/RenderView.h"
29 #include "core/rendering/svg/SVGRenderSupport.h"
30 #include "core/rendering/svg/SVGRenderingContext.h"
31 #include "core/rendering/svg/SVGResourcesCache.h"
32 #include "core/svg/SVGForeignObjectElement.h"
33 #include "platform/graphics/GraphicsContextStateSaver.h"
34
35 namespace WebCore {
36
37 RenderSVGForeignObject::RenderSVGForeignObject(SVGForeignObjectElement* node)
38     : RenderSVGBlock(node)
39     , m_needsTransformUpdate(true)
40 {
41 }
42
43 RenderSVGForeignObject::~RenderSVGForeignObject()
44 {
45 }
46
47 bool RenderSVGForeignObject::isChildAllowed(RenderObject* child, RenderStyle* style) const
48 {
49     // Disallow arbitary SVG content. Only allow proper <svg xmlns="svgNS"> subdocuments.
50     return !child->isSVG() || child->isSVGRoot();
51 }
52
53 void RenderSVGForeignObject::paint(PaintInfo& paintInfo, const LayoutPoint&)
54 {
55     if (paintInfo.context->paintingDisabled()
56         || (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection))
57         return;
58
59     PaintInfo childPaintInfo(paintInfo);
60     GraphicsContextStateSaver stateSaver(*childPaintInfo.context);
61     childPaintInfo.applyTransform(localTransform());
62
63     if (SVGRenderSupport::isOverflowHidden(this))
64         childPaintInfo.context->clip(m_viewport);
65
66     SVGRenderingContext renderingContext;
67     bool continueRendering = true;
68     if (paintInfo.phase == PaintPhaseForeground) {
69         renderingContext.prepareToRenderSVGContent(this, childPaintInfo);
70         continueRendering = renderingContext.isRenderingPrepared();
71     }
72
73     if (continueRendering) {
74         // Paint all phases of FO elements atomically, as though the FO element established its
75         // own stacking context.
76         bool preservePhase = paintInfo.phase == PaintPhaseSelection || paintInfo.phase == PaintPhaseTextClip;
77         LayoutPoint childPoint = IntPoint();
78         childPaintInfo.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground;
79         RenderBlock::paint(childPaintInfo, IntPoint());
80         if (!preservePhase) {
81             childPaintInfo.phase = PaintPhaseChildBlockBackgrounds;
82             RenderBlock::paint(childPaintInfo, childPoint);
83             childPaintInfo.phase = PaintPhaseFloat;
84             RenderBlock::paint(childPaintInfo, childPoint);
85             childPaintInfo.phase = PaintPhaseForeground;
86             RenderBlock::paint(childPaintInfo, childPoint);
87             childPaintInfo.phase = PaintPhaseOutline;
88             RenderBlock::paint(childPaintInfo, childPoint);
89         }
90     }
91 }
92
93 const AffineTransform& RenderSVGForeignObject::localToParentTransform() const
94 {
95     m_localToParentTransform = localTransform();
96     m_localToParentTransform.translate(m_viewport.x(), m_viewport.y());
97     return m_localToParentTransform;
98 }
99
100 void RenderSVGForeignObject::updateLogicalWidth()
101 {
102     // FIXME: Investigate in size rounding issues
103     // FIXME: Remove unnecessary rounding when layout is off ints: webkit.org/b/63656
104     setWidth(static_cast<int>(roundf(m_viewport.width())));
105 }
106
107 void RenderSVGForeignObject::computeLogicalHeight(LayoutUnit, LayoutUnit logicalTop, LogicalExtentComputedValues& computedValues) const
108 {
109     // FIXME: Investigate in size rounding issues
110     // FIXME: Remove unnecessary rounding when layout is off ints: webkit.org/b/63656
111     // FIXME: Is this correct for vertical writing mode?
112     computedValues.m_extent = static_cast<int>(roundf(m_viewport.height()));
113     computedValues.m_position = logicalTop;
114 }
115
116 void RenderSVGForeignObject::layout()
117 {
118     ASSERT(needsLayout());
119     ASSERT(!view()->layoutStateCachedOffsetsEnabled()); // RenderSVGRoot disables layoutState for the SVG rendering tree.
120
121     LayoutRepainter repainter(*this, SVGRenderSupport::checkForSVGRepaintDuringLayout(this));
122     SVGForeignObjectElement* foreign = toSVGForeignObjectElement(node());
123
124     bool updateCachedBoundariesInParents = false;
125     if (m_needsTransformUpdate) {
126         m_localTransform = foreign->animatedLocalTransform();
127         m_needsTransformUpdate = false;
128         updateCachedBoundariesInParents = true;
129     }
130
131     FloatRect oldViewport = m_viewport;
132
133     // Cache viewport boundaries
134     SVGLengthContext lengthContext(foreign);
135     FloatPoint viewportLocation(foreign->x()->currentValue()->value(lengthContext), foreign->y()->currentValue()->value(lengthContext));
136     m_viewport = FloatRect(viewportLocation, FloatSize(foreign->width()->currentValue()->value(lengthContext), foreign->height()->currentValue()->value(lengthContext)));
137     if (!updateCachedBoundariesInParents)
138         updateCachedBoundariesInParents = oldViewport != m_viewport;
139
140     // Set box origin to the foreignObject x/y translation, so positioned objects in XHTML content get correct
141     // positions. A regular RenderBoxModelObject would pull this information from RenderStyle - in SVG those
142     // properties are ignored for non <svg> elements, so we mimic what happens when specifying them through CSS.
143
144     // FIXME: Investigate in location rounding issues - only affects RenderSVGForeignObject & RenderSVGText
145     setLocation(roundedIntPoint(viewportLocation));
146
147     bool layoutChanged = everHadLayout() && selfNeedsLayout();
148     RenderBlock::layout();
149     ASSERT(!needsLayout());
150
151     // If our bounds changed, notify the parents.
152     if (updateCachedBoundariesInParents)
153         RenderSVGBlock::setNeedsBoundariesUpdate();
154
155     // Invalidate all resources of this client if our layout changed.
156     if (layoutChanged)
157         SVGResourcesCache::clientLayoutChanged(this);
158
159     repainter.repaintAfterLayout();
160 }
161
162 void RenderSVGForeignObject::mapRectToPaintInvalidationBacking(const RenderLayerModelObject* paintInvalidationContainer,
163     LayoutRect& rect, bool fixed) const
164 {
165     FloatRect r(rect);
166     SVGRenderSupport::computeFloatRectForRepaint(this, paintInvalidationContainer, r, fixed);
167     rect = enclosingLayoutRect(r);
168 }
169
170 bool RenderSVGForeignObject::nodeAtFloatPoint(const HitTestRequest& request, HitTestResult& result, const FloatPoint& pointInParent, HitTestAction hitTestAction)
171 {
172     // Embedded content is drawn in the foreground phase.
173     if (hitTestAction != HitTestForeground)
174         return false;
175
176     FloatPoint localPoint = localTransform().inverse().mapPoint(pointInParent);
177
178     // Early exit if local point is not contained in clipped viewport area
179     if (SVGRenderSupport::isOverflowHidden(this) && !m_viewport.contains(localPoint))
180         return false;
181
182     // FOs establish a stacking context, so we need to hit-test all layers.
183     HitTestLocation hitTestLocation(roundedLayoutPoint(localPoint));
184     return RenderBlock::nodeAtPoint(request, result, hitTestLocation, LayoutPoint(), HitTestForeground)
185         || RenderBlock::nodeAtPoint(request, result, hitTestLocation, LayoutPoint(), HitTestFloat)
186         || RenderBlock::nodeAtPoint(request, result, hitTestLocation, LayoutPoint(), HitTestChildBlockBackgrounds);
187 }
188
189 }