Remove unnecessary #include SVGResourcesCache.h in SVGDocumentExtensions.h; use forwa...
[WebKit-https.git] / Source / WebCore / rendering / svg / RenderSVGText.cpp
1 /*
2  * Copyright (C) 2006 Apple Computer, Inc.
3  * Copyright (C) 2006 Alexander Kellett <lypanov@kde.org>
4  * Copyright (C) 2006 Oliver Hunt <ojh16@student.canterbury.ac.nz>
5  * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
6  * Copyright (C) 2008 Rob Buis <buis@kde.org>
7  * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
8  * Copyright (C) Research In Motion Limited 2010. All rights reserved.
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Library General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Library General Public License for more details.
19  *
20  * You should have received a copy of the GNU Library General Public License
21  * along with this library; see the file COPYING.LIB.  If not, write to
22  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23  * Boston, MA 02110-1301, USA.
24  */
25
26 #include "config.h"
27
28 #if ENABLE(SVG)
29 #include "RenderSVGText.h"
30
31 #include "FloatConversion.h"
32 #include "FloatQuad.h"
33 #include "GraphicsContext.h"
34 #include "HitTestRequest.h"
35 #include "LayoutRepainter.h"
36 #include "PointerEventsHitRules.h"
37 #include "RenderSVGInlineText.h"
38 #include "RenderSVGResource.h"
39 #include "RenderSVGRoot.h"
40 #include "SVGLengthList.h"
41 #include "SVGRenderSupport.h"
42 #include "SVGResourcesCache.h"
43 #include "SVGRootInlineBox.h"
44 #include "SVGTextElement.h"
45 #include "SVGTextLayoutAttributesBuilder.h"
46 #include "SVGTransformList.h"
47 #include "SVGURIReference.h"
48 #include "SimpleFontData.h"
49 #include "TransformState.h"
50 #include "VisiblePosition.h"
51
52 namespace WebCore {
53
54 RenderSVGText::RenderSVGText(SVGTextElement* node) 
55     : RenderSVGBlock(node)
56     , m_needsReordering(false)
57     , m_needsPositioningValuesUpdate(true)
58     , m_needsTransformUpdate(true)
59 {
60 }
61
62 bool RenderSVGText::isChildAllowed(RenderObject* child, RenderStyle*) const
63 {
64     return child->isInline();
65 }
66
67 RenderSVGText* RenderSVGText::locateRenderSVGTextAncestor(RenderObject* start)
68 {
69     ASSERT(start);
70     while (start && !start->isSVGText())
71         start = start->parent();
72     if (!start || !start->isSVGText())
73         return 0;
74     return toRenderSVGText(start);
75 }
76
77 const RenderSVGText* RenderSVGText::locateRenderSVGTextAncestor(const RenderObject* start)
78 {
79     ASSERT(start);
80     while (start && !start->isSVGText())
81         start = start->parent();
82     if (!start || !start->isSVGText())
83         return 0;
84     return toRenderSVGText(start);
85 }
86
87 LayoutRect RenderSVGText::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer) const
88 {
89     return SVGRenderSupport::clippedOverflowRectForRepaint(this, repaintContainer);
90 }
91
92 void RenderSVGText::computeRectForRepaint(RenderBoxModelObject* repaintContainer, LayoutRect& repaintRect, bool fixed) const
93 {
94     SVGRenderSupport::computeRectForRepaint(this, repaintContainer, repaintRect, fixed);
95 }
96
97 void RenderSVGText::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool /* fixed */, bool /* useTransforms */, TransformState& transformState, bool* wasFixed) const
98 {
99     SVGRenderSupport::mapLocalToContainer(this, repaintContainer, transformState, wasFixed);
100 }
101
102 static inline void recursiveUpdateScaledFont(RenderObject* start)
103 {
104     for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) {
105         if (child->isSVGInlineText()) {
106             toRenderSVGInlineText(child)->updateScaledFont();
107             continue;
108         }
109
110         recursiveUpdateScaledFont(child);
111     }
112 }
113
114 void RenderSVGText::layout()
115 {
116     ASSERT(needsLayout());
117     LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
118
119     bool updateCachedBoundariesInParents = false;
120     if (m_needsTransformUpdate) {
121         SVGTextElement* text = static_cast<SVGTextElement*>(node());
122         m_localTransform = text->animatedLocalTransform();
123         m_needsTransformUpdate = false;
124         updateCachedBoundariesInParents = true;
125     }
126
127     // If the root layout size changed (eg. window size changes) or the positioning values change, recompute the on-screen font size.
128     if (m_needsPositioningValuesUpdate || SVGRenderSupport::findTreeRootObject(this)->isLayoutSizeChanged()) {
129         recursiveUpdateScaledFont(this);
130         m_needsPositioningValuesUpdate = true;
131         updateCachedBoundariesInParents = true;
132     }
133
134     if (m_needsPositioningValuesUpdate) {
135         // Perform SVG text layout phase one (see SVGTextLayoutAttributesBuilder for details).
136         SVGTextLayoutAttributesBuilder layoutAttributesBuilder;
137         layoutAttributesBuilder.buildLayoutAttributesForTextSubtree(this);
138         m_needsReordering = true;
139         m_needsPositioningValuesUpdate = false;
140         updateCachedBoundariesInParents = true;
141     }
142
143     // Reduced version of RenderBlock::layoutBlock(), which only takes care of SVG text.
144     // All if branches that could cause early exit in RenderBlocks layoutBlock() method are turned into assertions.
145     ASSERT(!isInline());
146     ASSERT(!simplifiedLayout());
147     ASSERT(!scrollsOverflow());
148     ASSERT(!hasControlClip());
149     ASSERT(!hasColumns());
150     ASSERT(!positionedObjects());
151     ASSERT(!m_overflow);
152     ASSERT(!isAnonymousBlock());
153
154     if (!firstChild())
155         setChildrenInline(true);
156
157     // FIXME: We need to find a way to only layout the child boxes, if needed.
158     FloatRect oldBoundaries = objectBoundingBox();
159     ASSERT(childrenInline());
160     forceLayoutInlineChildren();
161
162     if (m_needsReordering)
163         m_needsReordering = false;
164
165     if (!updateCachedBoundariesInParents)
166         updateCachedBoundariesInParents = oldBoundaries != objectBoundingBox();
167
168     // Invalidate all resources of this client if our layout changed.
169     if (m_everHadLayout && selfNeedsLayout())
170         SVGResourcesCache::clientLayoutChanged(this);
171
172     // If our bounds changed, notify the parents.
173     if (updateCachedBoundariesInParents)
174         RenderSVGBlock::setNeedsBoundariesUpdate();
175
176     repainter.repaintAfterLayout();
177     setNeedsLayout(false);
178 }
179
180 RootInlineBox* RenderSVGText::createRootInlineBox() 
181 {
182     RootInlineBox* box = new (renderArena()) SVGRootInlineBox(this);
183     box->setHasVirtualLogicalHeight();
184     return box;
185 }
186
187 bool RenderSVGText::nodeAtFloatPoint(const HitTestRequest& request, HitTestResult& result, const FloatPoint& pointInParent, HitTestAction hitTestAction)
188 {
189     PointerEventsHitRules hitRules(PointerEventsHitRules::SVG_TEXT_HITTESTING, request, style()->pointerEvents());
190     bool isVisible = (style()->visibility() == VISIBLE);
191     if (isVisible || !hitRules.requireVisible) {
192         if ((hitRules.canHitStroke && (style()->svgStyle()->hasStroke() || !hitRules.requireStroke))
193             || (hitRules.canHitFill && (style()->svgStyle()->hasFill() || !hitRules.requireFill))) {
194             FloatPoint localPoint = localToParentTransform().inverse().mapPoint(pointInParent);
195
196             if (!SVGRenderSupport::pointInClippingArea(this, localPoint))
197                 return false;       
198
199             return RenderBlock::nodeAtPoint(request, result, flooredIntPoint(localPoint), IntPoint(), hitTestAction);
200         }
201     }
202
203     return false;
204 }
205
206 bool RenderSVGText::nodeAtPoint(const HitTestRequest&, HitTestResult&, const LayoutPoint&, const LayoutPoint&, HitTestAction)
207 {
208     ASSERT_NOT_REACHED();
209     return false;
210 }
211
212 VisiblePosition RenderSVGText::positionForPoint(const LayoutPoint& pointInContents)
213 {
214     RootInlineBox* rootBox = firstRootBox();
215     if (!rootBox)
216         return createVisiblePosition(0, DOWNSTREAM);
217
218     ASSERT(rootBox->isSVGRootInlineBox());
219     ASSERT(!rootBox->nextRootBox());
220     ASSERT(childrenInline());
221
222     InlineBox* closestBox = static_cast<SVGRootInlineBox*>(rootBox)->closestLeafChildForPosition(pointInContents);
223     if (!closestBox)
224         return createVisiblePosition(0, DOWNSTREAM);
225
226     return closestBox->renderer()->positionForPoint(LayoutPoint(pointInContents.x(), closestBox->y()));
227 }
228
229 void RenderSVGText::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const
230 {
231     quads.append(localToAbsoluteQuad(strokeBoundingBox(), false, wasFixed));
232 }
233
234 void RenderSVGText::paint(PaintInfo& paintInfo, const LayoutPoint&)
235 {
236     if (paintInfo.context->paintingDisabled())
237         return;
238
239     if (paintInfo.phase != PaintPhaseForeground
240      && paintInfo.phase != PaintPhaseSelfOutline
241      && paintInfo.phase != PaintPhaseSelection)
242          return;
243
244     PaintInfo blockInfo(paintInfo);
245     GraphicsContextStateSaver stateSaver(*blockInfo.context);
246     blockInfo.applyTransform(localToParentTransform());
247     RenderBlock::paint(blockInfo, IntPoint());
248 }
249
250 FloatRect RenderSVGText::strokeBoundingBox() const
251 {
252     FloatRect strokeBoundaries = objectBoundingBox();
253     const SVGRenderStyle* svgStyle = style()->svgStyle();
254     if (!svgStyle->hasStroke())
255         return strokeBoundaries;
256
257     ASSERT(node());
258     ASSERT(node()->isSVGElement());
259     SVGLengthContext lengthContext(static_cast<SVGElement*>(node()));
260     strokeBoundaries.inflate(svgStyle->strokeWidth().value(lengthContext));
261     return strokeBoundaries;
262 }
263
264 FloatRect RenderSVGText::repaintRectInLocalCoordinates() const
265 {
266     FloatRect repaintRect = strokeBoundingBox();
267     SVGRenderSupport::intersectRepaintRectWithResources(this, repaintRect);
268
269     if (const ShadowData* textShadow = style()->textShadow())
270         textShadow->adjustRectForShadow(repaintRect);
271
272     return repaintRect;
273 }
274
275 // Fix for <rdar://problem/8048875>. We should not render :first-line CSS Style
276 // in a SVG text element context.
277 RenderBlock* RenderSVGText::firstLineBlock() const
278 {
279     return 0;
280 }
281
282 // Fix for <rdar://problem/8048875>. We should not render :first-letter CSS Style
283 // in a SVG text element context.
284 void RenderSVGText::updateFirstLetter()
285 {
286 }
287
288 }
289
290 #endif // ENABLE(SVG)