Rename first/second to key/value in HashMap iterators
[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-2012. All rights reserved.
9  * Copyright (C) 2012 Google Inc.
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Library General Public
13  * License as published by the Free Software Foundation; either
14  * version 2 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Library General Public License for more details.
20  *
21  * You should have received a copy of the GNU Library General Public License
22  * along with this library; see the file COPYING.LIB.  If not, write to
23  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24  * Boston, MA 02110-1301, USA.
25  */
26
27 #include "config.h"
28
29 #if ENABLE(SVG)
30 #include "RenderSVGText.h"
31
32 #include "FloatConversion.h"
33 #include "FloatQuad.h"
34 #include "FontCache.h"
35 #include "GraphicsContext.h"
36 #include "HitTestRequest.h"
37 #include "HitTestResult.h"
38 #include "LayoutRepainter.h"
39 #include "PointerEventsHitRules.h"
40 #include "RenderSVGInlineText.h"
41 #include "RenderSVGResource.h"
42 #include "RenderSVGRoot.h"
43 #include "SVGLengthList.h"
44 #include "SVGRenderSupport.h"
45 #include "SVGResourcesCache.h"
46 #include "SVGRootInlineBox.h"
47 #include "SVGTextElement.h"
48 #include "SVGTextLayoutAttributesBuilder.h"
49 #include "SVGTextRunRenderingContext.h"
50 #include "SVGTransformList.h"
51 #include "SVGURIReference.h"
52 #include "SimpleFontData.h"
53 #include "TransformState.h"
54 #include "VisiblePosition.h"
55
56 namespace WebCore {
57
58 RenderSVGText::RenderSVGText(SVGTextElement* node) 
59     : RenderSVGBlock(node)
60     , m_needsReordering(false)
61     , m_needsPositioningValuesUpdate(false)
62     , m_needsTransformUpdate(true)
63     , m_needsTextMetricsUpdate(false)
64 {
65 }
66
67 RenderSVGText::~RenderSVGText()
68 {
69     ASSERT(m_layoutAttributes.isEmpty());
70 }
71
72 bool RenderSVGText::isChildAllowed(RenderObject* child, RenderStyle*) const
73 {
74     return child->isInline();
75 }
76
77 RenderSVGText* RenderSVGText::locateRenderSVGTextAncestor(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 const RenderSVGText* RenderSVGText::locateRenderSVGTextAncestor(const RenderObject* start)
88 {
89     ASSERT(start);
90     while (start && !start->isSVGText())
91         start = start->parent();
92     if (!start || !start->isSVGText())
93         return 0;
94     return toRenderSVGText(start);
95 }
96
97 LayoutRect RenderSVGText::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer) const
98 {
99     return SVGRenderSupport::clippedOverflowRectForRepaint(this, repaintContainer);
100 }
101
102 void RenderSVGText::computeRectForRepaint(RenderBoxModelObject* repaintContainer, LayoutRect& rect, bool fixed) const
103 {
104     FloatRect repaintRect = rect;
105     computeFloatRectForRepaint(repaintContainer, repaintRect, fixed);
106     rect = enclosingLayoutRect(repaintRect);
107 }
108
109 void RenderSVGText::computeFloatRectForRepaint(RenderBoxModelObject* repaintContainer, FloatRect& repaintRect, bool fixed) const
110 {
111     SVGRenderSupport::computeFloatRectForRepaint(this, repaintContainer, repaintRect, fixed);
112 }
113
114 void RenderSVGText::mapLocalToContainer(RenderBoxModelObject* repaintContainer, TransformState& transformState, MapLocalToContainerFlags mode, bool* wasFixed) const
115 {
116     SVGRenderSupport::mapLocalToContainer(this, repaintContainer, transformState, mode & SnapOffsetForTransforms, wasFixed);
117 }
118
119 const RenderObject* RenderSVGText::pushMappingToContainer(const RenderBoxModelObject* ancestorToStopAt, RenderGeometryMap& geometryMap) const
120 {
121     return SVGRenderSupport::pushMappingToContainer(this, ancestorToStopAt, geometryMap);
122 }
123
124 static inline void collectLayoutAttributes(RenderObject* text, Vector<SVGTextLayoutAttributes*>& attributes)
125 {
126     for (RenderObject* descendant = text; descendant; descendant = descendant->nextInPreOrder(text)) {
127         if (descendant->isSVGInlineText())
128             attributes.append(toRenderSVGInlineText(descendant)->layoutAttributes());
129     }
130 }
131
132 static inline bool findPreviousAndNextAttributes(RenderObject* start, RenderSVGInlineText* locateElement, bool& stopAfterNext, SVGTextLayoutAttributes*& previous, SVGTextLayoutAttributes*& next)
133 {
134     ASSERT(start);
135     ASSERT(locateElement);
136     // FIXME: Make this iterative.
137     for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) {
138         if (child->isSVGInlineText()) {
139             RenderSVGInlineText* text = toRenderSVGInlineText(child);
140             if (locateElement != text) {
141                 if (stopAfterNext) {
142                     next = text->layoutAttributes();
143                     return true;
144                 }
145
146                 previous = text->layoutAttributes();
147                 continue;
148             }
149
150             stopAfterNext = true;
151             continue;
152         }
153
154         if (!child->isSVGInline())
155             continue;
156
157         if (findPreviousAndNextAttributes(child, locateElement, stopAfterNext, previous, next))
158             return true;
159     }
160
161     return false;
162 }
163
164 inline bool RenderSVGText::shouldHandleSubtreeMutations() const
165 {
166     if (beingDestroyed() || !everHadLayout()) {
167         ASSERT(m_layoutAttributes.isEmpty());
168         ASSERT(!m_layoutAttributesBuilder.numberOfTextPositioningElements());
169         return false;
170     }
171     return true;
172 }
173
174 void RenderSVGText::subtreeChildWasAdded(RenderObject* child)
175 {
176     ASSERT(child);
177     if (!shouldHandleSubtreeMutations() || documentBeingDestroyed())
178         return;
179
180     // Always protect the cache before clearing text positioning elements when the cache will subsequently be rebuilt.
181     FontCachePurgePreventer fontCachePurgePreventer;
182
183     // The positioning elements cache doesn't include the new 'child' yet. Clear the
184     // cache, as the next buildLayoutAttributesForTextRenderer() call rebuilds it.
185     m_layoutAttributesBuilder.clearTextPositioningElements();
186
187     if (!child->isSVGInlineText() && !child->isSVGInline())
188         return;
189
190     // Detect changes in layout attributes and only measure those text parts that have changed!
191     Vector<SVGTextLayoutAttributes*> newLayoutAttributes;
192     collectLayoutAttributes(this, newLayoutAttributes);
193     if (newLayoutAttributes.isEmpty()) {
194         ASSERT(m_layoutAttributes.isEmpty());
195         return;
196     }
197
198     // Compare m_layoutAttributes with newLayoutAttributes to figure out which attribute got added.
199     size_t size = newLayoutAttributes.size();
200     SVGTextLayoutAttributes* attributes = 0;
201     for (size_t i = 0; i < size; ++i) {
202         attributes = newLayoutAttributes[i];
203         if (m_layoutAttributes.find(attributes) == notFound) {
204             // Every time this is invoked, there's only a single new entry in the newLayoutAttributes list, compared to the old in m_layoutAttributes.
205             bool stopAfterNext = false;
206             SVGTextLayoutAttributes* previous = 0;
207             SVGTextLayoutAttributes* next = 0;
208             ASSERT_UNUSED(child, attributes->context() == child);
209             findPreviousAndNextAttributes(this, attributes->context(), stopAfterNext, previous, next);
210
211             if (previous)
212                 m_layoutAttributesBuilder.buildLayoutAttributesForTextRenderer(previous->context());
213             m_layoutAttributesBuilder.buildLayoutAttributesForTextRenderer(attributes->context());
214             if (next)
215                 m_layoutAttributesBuilder.buildLayoutAttributesForTextRenderer(next->context());
216             break;
217         }
218     }
219
220 #ifndef NDEBUG
221     // Verify that m_layoutAttributes only differs by a maximum of one entry.
222     for (size_t i = 0; i < size; ++i)
223         ASSERT(m_layoutAttributes.find(newLayoutAttributes[i]) != notFound || newLayoutAttributes[i] == attributes);
224 #endif
225
226     m_layoutAttributes = newLayoutAttributes;
227 }
228
229 static inline void checkLayoutAttributesConsistency(RenderSVGText* text, Vector<SVGTextLayoutAttributes*>& expectedLayoutAttributes)
230 {
231 #ifndef NDEBUG
232     Vector<SVGTextLayoutAttributes*> newLayoutAttributes;
233     collectLayoutAttributes(text, newLayoutAttributes);
234     ASSERT(newLayoutAttributes == expectedLayoutAttributes);
235 #else
236     UNUSED_PARAM(text);
237     UNUSED_PARAM(expectedLayoutAttributes);
238 #endif
239 }
240
241 void RenderSVGText::willBeDestroyed()
242 {
243     m_layoutAttributes.clear();
244     m_layoutAttributesBuilder.clearTextPositioningElements();
245
246     RenderSVGBlock::willBeDestroyed();
247 }
248
249 void RenderSVGText::subtreeChildWillBeRemoved(RenderObject* child, Vector<SVGTextLayoutAttributes*, 2>& affectedAttributes)
250 {
251     ASSERT(child);
252     if (!shouldHandleSubtreeMutations())
253         return;
254
255     checkLayoutAttributesConsistency(this, m_layoutAttributes);
256
257     // The positioning elements cache depends on the size of each text renderer in the
258     // subtree. If this changes, clear the cache. It's going to be rebuilt below.
259     m_layoutAttributesBuilder.clearTextPositioningElements();
260     if (m_layoutAttributes.isEmpty() || !child->isSVGInlineText())
261         return;
262
263     // This logic requires that the 'text' child is still inserted in the tree.
264     RenderSVGInlineText* text = toRenderSVGInlineText(child);
265     bool stopAfterNext = false;
266     SVGTextLayoutAttributes* previous = 0;
267     SVGTextLayoutAttributes* next = 0;
268     if (!documentBeingDestroyed())
269         findPreviousAndNextAttributes(this, text, stopAfterNext, previous, next);
270
271     if (previous)
272         affectedAttributes.append(previous);
273     if (next)
274         affectedAttributes.append(next);
275
276     size_t position = m_layoutAttributes.find(text->layoutAttributes());
277     ASSERT(position != notFound);
278     m_layoutAttributes.remove(position);
279 }
280
281 void RenderSVGText::subtreeChildWasRemoved(const Vector<SVGTextLayoutAttributes*, 2>& affectedAttributes)
282 {
283     if (!shouldHandleSubtreeMutations() || documentBeingDestroyed()) {
284         ASSERT(affectedAttributes.isEmpty());
285         return;
286     }
287
288     // This is called immediately after subtreeChildWillBeDestroyed, once the RenderSVGInlineText::willBeDestroyed() method
289     // passes on to the base class, which removes us from the render tree. At this point we can update the layout attributes.
290     unsigned size = affectedAttributes.size();
291     for (unsigned i = 0; i < size; ++i)
292         m_layoutAttributesBuilder.buildLayoutAttributesForTextRenderer(affectedAttributes[i]->context());
293 }
294
295 void RenderSVGText::subtreeStyleDidChange(RenderSVGInlineText* text)
296 {
297     ASSERT(text);
298     if (!shouldHandleSubtreeMutations() || documentBeingDestroyed())
299         return;
300
301     checkLayoutAttributesConsistency(this, m_layoutAttributes);
302
303     // Only update the metrics cache, but not the text positioning element cache
304     // nor the layout attributes cached in the leaf #text renderers.
305     FontCachePurgePreventer fontCachePurgePreventer;
306     for (RenderObject* descendant = text; descendant; descendant = descendant->nextInPreOrder(text)) {
307         if (descendant->isSVGInlineText())
308             m_layoutAttributesBuilder.rebuildMetricsForTextRenderer(toRenderSVGInlineText(descendant));
309     }
310 }
311
312 void RenderSVGText::subtreeTextDidChange(RenderSVGInlineText* text)
313 {
314     ASSERT(text);
315     ASSERT(!beingDestroyed());
316     if (!everHadLayout()) {
317         ASSERT(m_layoutAttributes.isEmpty());
318         ASSERT(!m_layoutAttributesBuilder.numberOfTextPositioningElements());
319         return;
320     }
321
322     // Always protect the cache before clearing text positioning elements when the cache will subsequently be rebuilt.
323     FontCachePurgePreventer fontCachePurgePreventer;
324
325     // The positioning elements cache depends on the size of each text renderer in the
326     // subtree. If this changes, clear the cache. It's going to be rebuilt below.
327     m_layoutAttributesBuilder.clearTextPositioningElements();
328
329     checkLayoutAttributesConsistency(this, m_layoutAttributes);
330     for (RenderObject* descendant = text; descendant; descendant = descendant->nextInPreOrder(text)) {
331         if (descendant->isSVGInlineText())
332             m_layoutAttributesBuilder.buildLayoutAttributesForTextRenderer(toRenderSVGInlineText(descendant));
333     }
334 }
335
336 static inline void updateFontInAllDescendants(RenderObject* start, SVGTextLayoutAttributesBuilder* builder = 0)
337 {
338     for (RenderObject* descendant = start; descendant; descendant = descendant->nextInPreOrder(start)) {
339         if (!descendant->isSVGInlineText())
340             continue;
341         RenderSVGInlineText* text = toRenderSVGInlineText(descendant);
342         text->updateScaledFont();
343         if (builder)
344             builder->rebuildMetricsForTextRenderer(text);
345     }
346 }
347
348 void RenderSVGText::layout()
349 {
350     ASSERT(needsLayout());
351     LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
352
353     bool updateCachedBoundariesInParents = false;
354     if (m_needsTransformUpdate) {
355         SVGTextElement* text = static_cast<SVGTextElement*>(node());
356         m_localTransform = text->animatedLocalTransform();
357         m_needsTransformUpdate = false;
358         updateCachedBoundariesInParents = true;
359     }
360
361     if (!everHadLayout()) {
362         // When laying out initially, collect all layout attributes, build the character data map,
363         // and propogate resulting SVGLayoutAttributes to all RenderSVGInlineText children in the subtree.
364         ASSERT(m_layoutAttributes.isEmpty());
365         collectLayoutAttributes(this, m_layoutAttributes);
366         updateFontInAllDescendants(this);
367         m_layoutAttributesBuilder.buildLayoutAttributesForForSubtree(this);
368
369         m_needsReordering = true;
370         m_needsTextMetricsUpdate = false;
371         m_needsPositioningValuesUpdate = false;
372         updateCachedBoundariesInParents = true;
373     } else if (m_needsPositioningValuesUpdate) {
374         // When the x/y/dx/dy/rotate lists change, recompute the layout attributes, and eventually
375         // update the on-screen font objects as well in all descendants.
376         if (m_needsTextMetricsUpdate) {
377             updateFontInAllDescendants(this);
378             m_needsTextMetricsUpdate = false;
379         }
380
381         m_layoutAttributesBuilder.buildLayoutAttributesForForSubtree(this);
382         m_needsReordering = true;
383         m_needsPositioningValuesUpdate = false;
384         updateCachedBoundariesInParents = true;
385     } else if (m_needsTextMetricsUpdate || SVGRenderSupport::findTreeRootObject(this)->isLayoutSizeChanged()) {
386         // If the root layout size changed (eg. window size changes) or the transform to the root
387         // context has changed then recompute the on-screen font size.
388         updateFontInAllDescendants(this, &m_layoutAttributesBuilder);
389
390         ASSERT(!m_needsReordering);
391         ASSERT(!m_needsPositioningValuesUpdate);
392         m_needsTextMetricsUpdate = false;
393         updateCachedBoundariesInParents = true;
394     }
395
396     checkLayoutAttributesConsistency(this, m_layoutAttributes);
397
398     // Reduced version of RenderBlock::layoutBlock(), which only takes care of SVG text.
399     // All if branches that could cause early exit in RenderBlocks layoutBlock() method are turned into assertions.
400     ASSERT(!isInline());
401     ASSERT(!simplifiedLayout());
402     ASSERT(!scrollsOverflow());
403     ASSERT(!hasControlClip());
404     ASSERT(!hasColumns());
405     ASSERT(!positionedObjects());
406     ASSERT(!m_overflow);
407     ASSERT(!isAnonymousBlock());
408
409     if (!firstChild())
410         setChildrenInline(true);
411
412     // FIXME: We need to find a way to only layout the child boxes, if needed.
413     FloatRect oldBoundaries = objectBoundingBox();
414     ASSERT(childrenInline());
415     forceLayoutInlineChildren();
416
417     if (m_needsReordering)
418         m_needsReordering = false;
419
420     if (!updateCachedBoundariesInParents)
421         updateCachedBoundariesInParents = oldBoundaries != objectBoundingBox();
422
423     // Invalidate all resources of this client if our layout changed.
424     if (everHadLayout() && selfNeedsLayout())
425         SVGResourcesCache::clientLayoutChanged(this);
426
427     // If our bounds changed, notify the parents.
428     if (updateCachedBoundariesInParents)
429         RenderSVGBlock::setNeedsBoundariesUpdate();
430
431     repainter.repaintAfterLayout();
432     setNeedsLayout(false);
433 }
434
435 RootInlineBox* RenderSVGText::createRootInlineBox() 
436 {
437     RootInlineBox* box = new (renderArena()) SVGRootInlineBox(this);
438     box->setHasVirtualLogicalHeight();
439     return box;
440 }
441
442 bool RenderSVGText::nodeAtFloatPoint(const HitTestRequest& request, HitTestResult& result, const FloatPoint& pointInParent, HitTestAction hitTestAction)
443 {
444     PointerEventsHitRules hitRules(PointerEventsHitRules::SVG_TEXT_HITTESTING, request, style()->pointerEvents());
445     bool isVisible = (style()->visibility() == VISIBLE);
446     if (isVisible || !hitRules.requireVisible) {
447         if ((hitRules.canHitStroke && (style()->svgStyle()->hasStroke() || !hitRules.requireStroke))
448             || (hitRules.canHitFill && (style()->svgStyle()->hasFill() || !hitRules.requireFill))) {
449             FloatPoint localPoint = localToParentTransform().inverse().mapPoint(pointInParent);
450
451             if (!SVGRenderSupport::pointInClippingArea(this, localPoint))
452                 return false;       
453
454             HitTestPoint hitTestPoint(LayoutPoint(flooredIntPoint(localPoint)));
455             return RenderBlock::nodeAtPoint(request, result, hitTestPoint, LayoutPoint(), hitTestAction);
456         }
457     }
458
459     return false;
460 }
461
462 bool RenderSVGText::nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestPoint&, const LayoutPoint&, HitTestAction)
463 {
464     ASSERT_NOT_REACHED();
465     return false;
466 }
467
468 VisiblePosition RenderSVGText::positionForPoint(const LayoutPoint& pointInContents)
469 {
470     RootInlineBox* rootBox = firstRootBox();
471     if (!rootBox)
472         return createVisiblePosition(0, DOWNSTREAM);
473
474     ASSERT(rootBox->isSVGRootInlineBox());
475     ASSERT(!rootBox->nextRootBox());
476     ASSERT(childrenInline());
477
478     InlineBox* closestBox = static_cast<SVGRootInlineBox*>(rootBox)->closestLeafChildForPosition(pointInContents);
479     if (!closestBox)
480         return createVisiblePosition(0, DOWNSTREAM);
481
482     return closestBox->renderer()->positionForPoint(LayoutPoint(pointInContents.x(), closestBox->y()));
483 }
484
485 void RenderSVGText::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const
486 {
487     quads.append(localToAbsoluteQuad(strokeBoundingBox(), false, wasFixed));
488 }
489
490 void RenderSVGText::paint(PaintInfo& paintInfo, const LayoutPoint&)
491 {
492     if (paintInfo.context->paintingDisabled())
493         return;
494
495     if (paintInfo.phase != PaintPhaseForeground
496      && paintInfo.phase != PaintPhaseSelfOutline
497      && paintInfo.phase != PaintPhaseSelection)
498          return;
499
500     PaintInfo blockInfo(paintInfo);
501     GraphicsContextStateSaver stateSaver(*blockInfo.context);
502     blockInfo.applyTransform(localToParentTransform());
503     RenderBlock::paint(blockInfo, LayoutPoint());
504 }
505
506 FloatRect RenderSVGText::strokeBoundingBox() const
507 {
508     FloatRect strokeBoundaries = objectBoundingBox();
509     const SVGRenderStyle* svgStyle = style()->svgStyle();
510     if (!svgStyle->hasStroke())
511         return strokeBoundaries;
512
513     ASSERT(node());
514     ASSERT(node()->isSVGElement());
515     SVGLengthContext lengthContext(static_cast<SVGElement*>(node()));
516     strokeBoundaries.inflate(svgStyle->strokeWidth().value(lengthContext));
517     return strokeBoundaries;
518 }
519
520 FloatRect RenderSVGText::repaintRectInLocalCoordinates() const
521 {
522     FloatRect repaintRect = strokeBoundingBox();
523     SVGRenderSupport::intersectRepaintRectWithResources(this, repaintRect);
524
525     if (const ShadowData* textShadow = style()->textShadow())
526         textShadow->adjustRectForShadow(repaintRect);
527
528     return repaintRect;
529 }
530
531 void RenderSVGText::addChild(RenderObject* child, RenderObject* beforeChild)
532 {
533     RenderSVGBlock::addChild(child, beforeChild);
534
535     SVGResourcesCache::clientWasAddedToTree(child, child->style());
536     subtreeChildWasAdded(child);
537 }
538
539 void RenderSVGText::removeChild(RenderObject* child)
540 {
541     SVGResourcesCache::clientWillBeRemovedFromTree(child);
542
543     Vector<SVGTextLayoutAttributes*, 2> affectedAttributes;
544     FontCachePurgePreventer fontCachePurgePreventer;
545     subtreeChildWillBeRemoved(child, affectedAttributes);
546     RenderSVGBlock::removeChild(child);
547     subtreeChildWasRemoved(affectedAttributes);
548 }
549
550 // Fix for <rdar://problem/8048875>. We should not render :first-line CSS Style
551 // in a SVG text element context.
552 RenderBlock* RenderSVGText::firstLineBlock() const
553 {
554     return 0;
555 }
556
557 // Fix for <rdar://problem/8048875>. We should not render :first-letter CSS Style
558 // in a SVG text element context.
559 void RenderSVGText::updateFirstLetter()
560 {
561 }
562
563 }
564
565 #endif // ENABLE(SVG)