Add WTF::move()
[WebKit-https.git] / Source / WebCore / rendering / svg / RenderSVGText.cpp
1 /*
2  * Copyright (C) 2006 Apple 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 #include "RenderSVGText.h"
29
30 #include "FloatQuad.h"
31 #include "FontCache.h"
32 #include "GraphicsContext.h"
33 #include "HitTestRequest.h"
34 #include "HitTestResult.h"
35 #include "LayoutRepainter.h"
36 #include "PointerEventsHitRules.h"
37 #include "RenderIterator.h"
38 #include "RenderSVGInlineText.h"
39 #include "RenderSVGResource.h"
40 #include "RenderSVGRoot.h"
41 #include "SVGLengthList.h"
42 #include "SVGResourcesCache.h"
43 #include "SVGRootInlineBox.h"
44 #include "SVGTextElement.h"
45 #include "SVGTextRunRenderingContext.h"
46 #include "SVGTransformList.h"
47 #include "SVGURIReference.h"
48 #include "SimpleFontData.h"
49 #include "TransformState.h"
50 #include "VisiblePosition.h"
51 #include <wtf/StackStats.h>
52
53 namespace WebCore {
54
55 RenderSVGText::RenderSVGText(SVGTextElement& element, PassRef<RenderStyle> style)
56     : RenderSVGBlock(element, WTF::move(style))
57     , m_needsReordering(false)
58     , m_needsPositioningValuesUpdate(false)
59     , m_needsTransformUpdate(true)
60     , m_needsTextMetricsUpdate(false)
61 {
62 }
63
64 RenderSVGText::~RenderSVGText()
65 {
66     ASSERT(m_layoutAttributes.isEmpty());
67 }
68
69 SVGTextElement& RenderSVGText::textElement() const
70 {
71     return toSVGTextElement(RenderSVGBlock::graphicsElement());
72 }
73
74 bool RenderSVGText::isChildAllowed(const RenderObject& child, const RenderStyle&) const
75 {
76     return child.isInline();
77 }
78
79 RenderSVGText* RenderSVGText::locateRenderSVGTextAncestor(RenderObject& start)
80 {
81     return lineageOfType<RenderSVGText>(start).first();
82 }
83
84 const RenderSVGText* RenderSVGText::locateRenderSVGTextAncestor(const RenderObject& start)
85 {
86     return lineageOfType<RenderSVGText>(start).first();
87 }
88
89 LayoutRect RenderSVGText::clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const
90 {
91     return SVGRenderSupport::clippedOverflowRectForRepaint(*this, repaintContainer);
92 }
93
94 void RenderSVGText::computeRectForRepaint(const RenderLayerModelObject* repaintContainer, LayoutRect& rect, bool fixed) const
95 {
96     FloatRect repaintRect = rect;
97     computeFloatRectForRepaint(repaintContainer, repaintRect, fixed);
98     rect = enclosingLayoutRect(repaintRect);
99 }
100
101 void RenderSVGText::computeFloatRectForRepaint(const RenderLayerModelObject* repaintContainer, FloatRect& repaintRect, bool fixed) const
102 {
103     SVGRenderSupport::computeFloatRectForRepaint(*this, repaintContainer, repaintRect, fixed);
104 }
105
106 void RenderSVGText::mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState& transformState, MapCoordinatesFlags, bool* wasFixed) const
107 {
108     SVGRenderSupport::mapLocalToContainer(*this, repaintContainer, transformState, wasFixed);
109 }
110
111 const RenderObject* RenderSVGText::pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap& geometryMap) const
112 {
113     return SVGRenderSupport::pushMappingToContainer(*this, ancestorToStopAt, geometryMap);
114 }
115
116 static inline void collectLayoutAttributes(RenderObject* text, Vector<SVGTextLayoutAttributes*>& attributes)
117 {
118     for (RenderObject* descendant = text; descendant; descendant = descendant->nextInPreOrder(text)) {
119         if (descendant->isSVGInlineText())
120             attributes.append(toRenderSVGInlineText(descendant)->layoutAttributes());
121     }
122 }
123
124 static inline bool findPreviousAndNextAttributes(RenderElement* start, RenderSVGInlineText* locateElement, bool& stopAfterNext, SVGTextLayoutAttributes*& previous, SVGTextLayoutAttributes*& next)
125 {
126     ASSERT(start);
127     ASSERT(locateElement);
128     // FIXME: Make this iterative.
129     for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) {
130         if (child->isSVGInlineText()) {
131             RenderSVGInlineText* text = toRenderSVGInlineText(child);
132             if (locateElement != text) {
133                 if (stopAfterNext) {
134                     next = text->layoutAttributes();
135                     return true;
136                 }
137
138                 previous = text->layoutAttributes();
139                 continue;
140             }
141
142             stopAfterNext = true;
143             continue;
144         }
145
146         if (!child->isSVGInline())
147             continue;
148
149         if (findPreviousAndNextAttributes(toRenderElement(child), locateElement, stopAfterNext, previous, next))
150             return true;
151     }
152
153     return false;
154 }
155
156 inline bool RenderSVGText::shouldHandleSubtreeMutations() const
157 {
158     if (beingDestroyed() || !everHadLayout()) {
159         ASSERT(m_layoutAttributes.isEmpty());
160         ASSERT(!m_layoutAttributesBuilder.numberOfTextPositioningElements());
161         return false;
162     }
163     return true;
164 }
165
166 void RenderSVGText::subtreeChildWasAdded(RenderObject* child)
167 {
168     ASSERT(child);
169     if (!shouldHandleSubtreeMutations() || documentBeingDestroyed())
170         return;
171
172     // Always protect the cache before clearing text positioning elements when the cache will subsequently be rebuilt.
173     FontCachePurgePreventer fontCachePurgePreventer;
174
175     // The positioning elements cache doesn't include the new 'child' yet. Clear the
176     // cache, as the next buildLayoutAttributesForTextRenderer() call rebuilds it.
177     m_layoutAttributesBuilder.clearTextPositioningElements();
178
179     if (!child->isSVGInlineText() && !child->isSVGInline())
180         return;
181
182     // Detect changes in layout attributes and only measure those text parts that have changed!
183     Vector<SVGTextLayoutAttributes*> newLayoutAttributes;
184     collectLayoutAttributes(this, newLayoutAttributes);
185     if (newLayoutAttributes.isEmpty()) {
186         ASSERT(m_layoutAttributes.isEmpty());
187         return;
188     }
189
190     // Compare m_layoutAttributes with newLayoutAttributes to figure out which attribute got added.
191     size_t size = newLayoutAttributes.size();
192     SVGTextLayoutAttributes* attributes = 0;
193     for (size_t i = 0; i < size; ++i) {
194         attributes = newLayoutAttributes[i];
195         if (m_layoutAttributes.find(attributes) == notFound) {
196             // Every time this is invoked, there's only a single new entry in the newLayoutAttributes list, compared to the old in m_layoutAttributes.
197             bool stopAfterNext = false;
198             SVGTextLayoutAttributes* previous = 0;
199             SVGTextLayoutAttributes* next = 0;
200             ASSERT_UNUSED(child, &attributes->context() == child);
201             findPreviousAndNextAttributes(this, &attributes->context(), stopAfterNext, previous, next);
202
203             if (previous)
204                 m_layoutAttributesBuilder.buildLayoutAttributesForTextRenderer(previous->context());
205             m_layoutAttributesBuilder.buildLayoutAttributesForTextRenderer(attributes->context());
206             if (next)
207                 m_layoutAttributesBuilder.buildLayoutAttributesForTextRenderer(next->context());
208             break;
209         }
210     }
211
212 #ifndef NDEBUG
213     // Verify that m_layoutAttributes only differs by a maximum of one entry.
214     for (size_t i = 0; i < size; ++i)
215         ASSERT(m_layoutAttributes.find(newLayoutAttributes[i]) != notFound || newLayoutAttributes[i] == attributes);
216 #endif
217
218     m_layoutAttributes = newLayoutAttributes;
219 }
220
221 static inline void checkLayoutAttributesConsistency(RenderSVGText* text, Vector<SVGTextLayoutAttributes*>& expectedLayoutAttributes)
222 {
223 #ifndef NDEBUG
224     Vector<SVGTextLayoutAttributes*> newLayoutAttributes;
225     collectLayoutAttributes(text, newLayoutAttributes);
226     ASSERT(newLayoutAttributes == expectedLayoutAttributes);
227 #else
228     UNUSED_PARAM(text);
229     UNUSED_PARAM(expectedLayoutAttributes);
230 #endif
231 }
232
233 void RenderSVGText::willBeDestroyed()
234 {
235     m_layoutAttributes.clear();
236     m_layoutAttributesBuilder.clearTextPositioningElements();
237
238     RenderSVGBlock::willBeDestroyed();
239 }
240
241 void RenderSVGText::subtreeChildWillBeRemoved(RenderObject* child, Vector<SVGTextLayoutAttributes*, 2>& affectedAttributes)
242 {
243     ASSERT(child);
244     if (!shouldHandleSubtreeMutations())
245         return;
246
247     checkLayoutAttributesConsistency(this, m_layoutAttributes);
248
249     // The positioning elements cache depends on the size of each text renderer in the
250     // subtree. If this changes, clear the cache. It's going to be rebuilt below.
251     m_layoutAttributesBuilder.clearTextPositioningElements();
252     if (m_layoutAttributes.isEmpty() || !child->isSVGInlineText())
253         return;
254
255     // This logic requires that the 'text' child is still inserted in the tree.
256     RenderSVGInlineText* text = toRenderSVGInlineText(child);
257     bool stopAfterNext = false;
258     SVGTextLayoutAttributes* previous = 0;
259     SVGTextLayoutAttributes* next = 0;
260     if (!documentBeingDestroyed())
261         findPreviousAndNextAttributes(this, text, stopAfterNext, previous, next);
262
263     if (previous)
264         affectedAttributes.append(previous);
265     if (next)
266         affectedAttributes.append(next);
267
268     size_t position = m_layoutAttributes.find(text->layoutAttributes());
269     ASSERT(position != notFound);
270     m_layoutAttributes.remove(position);
271 }
272
273 void RenderSVGText::subtreeChildWasRemoved(const Vector<SVGTextLayoutAttributes*, 2>& affectedAttributes)
274 {
275     if (!shouldHandleSubtreeMutations() || documentBeingDestroyed()) {
276         ASSERT(affectedAttributes.isEmpty());
277         return;
278     }
279
280     // This is called immediately after subtreeChildWillBeDestroyed, once the RenderSVGInlineText::willBeDestroyed() method
281     // passes on to the base class, which removes us from the render tree. At this point we can update the layout attributes.
282     unsigned size = affectedAttributes.size();
283     for (unsigned i = 0; i < size; ++i)
284         m_layoutAttributesBuilder.buildLayoutAttributesForTextRenderer(affectedAttributes[i]->context());
285 }
286
287 void RenderSVGText::subtreeStyleDidChange(RenderSVGInlineText* text)
288 {
289     ASSERT(text);
290     if (!shouldHandleSubtreeMutations() || documentBeingDestroyed())
291         return;
292
293     checkLayoutAttributesConsistency(this, m_layoutAttributes);
294
295     // Only update the metrics cache, but not the text positioning element cache
296     // nor the layout attributes cached in the leaf #text renderers.
297     FontCachePurgePreventer fontCachePurgePreventer;
298     for (RenderObject* descendant = text; descendant; descendant = descendant->nextInPreOrder(text)) {
299         if (descendant->isSVGInlineText())
300             m_layoutAttributesBuilder.rebuildMetricsForTextRenderer(toRenderSVGInlineText(descendant));
301     }
302 }
303
304 void RenderSVGText::subtreeTextDidChange(RenderSVGInlineText* text)
305 {
306     ASSERT(text);
307     ASSERT(!beingDestroyed());
308     if (!everHadLayout()) {
309         ASSERT(m_layoutAttributes.isEmpty());
310         ASSERT(!m_layoutAttributesBuilder.numberOfTextPositioningElements());
311         return;
312     }
313     // Text transforms can cause text change to be signaled during addChild before m_layoutAttributes has been updated.
314     if (!m_layoutAttributes.contains(text->layoutAttributes())) {
315         ASSERT(!text->everHadLayout());
316         return;
317     }
318
319     // Always protect the cache before clearing text positioning elements when the cache will subsequently be rebuilt.
320     FontCachePurgePreventer fontCachePurgePreventer;
321
322     // The positioning elements cache depends on the size of each text renderer in the
323     // subtree. If this changes, clear the cache. It's going to be rebuilt below.
324     m_layoutAttributesBuilder.clearTextPositioningElements();
325
326     checkLayoutAttributesConsistency(this, m_layoutAttributes);
327     for (RenderObject* descendant = text; descendant; descendant = descendant->nextInPreOrder(text)) {
328         if (descendant->isSVGInlineText())
329             m_layoutAttributesBuilder.buildLayoutAttributesForTextRenderer(toRenderSVGInlineText(*descendant));
330     }
331 }
332
333 static inline void updateFontInAllDescendants(RenderObject* start, SVGTextLayoutAttributesBuilder* builder = 0)
334 {
335     for (RenderObject* descendant = start; descendant; descendant = descendant->nextInPreOrder(start)) {
336         if (!descendant->isSVGInlineText())
337             continue;
338         RenderSVGInlineText& text = toRenderSVGInlineText(*descendant);
339         text.updateScaledFont();
340         if (builder)
341             builder->rebuildMetricsForTextRenderer(&text);
342     }
343 }
344
345 void RenderSVGText::layout()
346 {
347     StackStats::LayoutCheckPoint layoutCheckPoint;
348     ASSERT(needsLayout());
349     LayoutRepainter repainter(*this, SVGRenderSupport::checkForSVGRepaintDuringLayout(*this));
350
351     bool updateCachedBoundariesInParents = false;
352     if (m_needsTransformUpdate) {
353         m_localTransform = textElement().animatedLocalTransform();
354         m_needsTransformUpdate = false;
355         updateCachedBoundariesInParents = true;
356     }
357
358     if (!everHadLayout()) {
359         // When laying out initially, collect all layout attributes, build the character data map,
360         // and propogate resulting SVGLayoutAttributes to all RenderSVGInlineText children in the subtree.
361         ASSERT(m_layoutAttributes.isEmpty());
362         collectLayoutAttributes(this, m_layoutAttributes);
363         updateFontInAllDescendants(this);
364         m_layoutAttributesBuilder.buildLayoutAttributesForForSubtree(this);
365
366         m_needsReordering = true;
367         m_needsTextMetricsUpdate = false;
368         m_needsPositioningValuesUpdate = false;
369         updateCachedBoundariesInParents = true;
370     } else if (m_needsPositioningValuesUpdate) {
371         // When the x/y/dx/dy/rotate lists change, recompute the layout attributes, and eventually
372         // update the on-screen font objects as well in all descendants.
373         if (m_needsTextMetricsUpdate) {
374             updateFontInAllDescendants(this);
375             m_needsTextMetricsUpdate = false;
376         }
377
378         m_layoutAttributesBuilder.buildLayoutAttributesForForSubtree(this);
379         m_needsReordering = true;
380         m_needsPositioningValuesUpdate = false;
381         updateCachedBoundariesInParents = true;
382     } else if (m_needsTextMetricsUpdate || SVGRenderSupport::findTreeRootObject(*this).isLayoutSizeChanged()) {
383         // If the root layout size changed (eg. window size changes) or the transform to the root
384         // context has changed then recompute the on-screen font size.
385         updateFontInAllDescendants(this, &m_layoutAttributesBuilder);
386
387         ASSERT(!m_needsReordering);
388         ASSERT(!m_needsPositioningValuesUpdate);
389         m_needsTextMetricsUpdate = false;
390         updateCachedBoundariesInParents = true;
391     }
392
393     checkLayoutAttributesConsistency(this, m_layoutAttributes);
394
395     // Reduced version of RenderBlock::layoutBlock(), which only takes care of SVG text.
396     // All if branches that could cause early exit in RenderBlocks layoutBlock() method are turned into assertions.
397     ASSERT(!isInline());
398     ASSERT(!simplifiedLayout());
399     ASSERT(!scrollsOverflow());
400     ASSERT(!hasControlClip());
401     ASSERT(!multiColumnFlowThread());
402     ASSERT(!positionedObjects());
403     ASSERT(!m_overflow);
404     ASSERT(!isAnonymousBlock());
405
406     if (!firstChild())
407         setChildrenInline(true);
408
409     // FIXME: We need to find a way to only layout the child boxes, if needed.
410     FloatRect oldBoundaries = objectBoundingBox();
411     ASSERT(childrenInline());
412     LayoutUnit repaintLogicalTop = 0;
413     LayoutUnit repaintLogicalBottom = 0;
414     rebuildFloatingObjectSetFromIntrudingFloats();
415     layoutInlineChildren(true, repaintLogicalTop, repaintLogicalBottom);
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     clearNeedsLayout();
433 }
434
435 std::unique_ptr<RootInlineBox> RenderSVGText::createRootInlineBox()
436 {
437     auto box = std::make_unique<SVGRootInlineBox>(*this);
438     box->setHasVirtualLogicalHeight();
439     return WTF::move(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             HitTestLocation hitTestLocation(LayoutPoint(flooredIntPoint(localPoint)));
455             return RenderBlock::nodeAtPoint(request, result, hitTestLocation, LayoutPoint(), hitTestAction);
456         }
457     }
458
459     return false;
460 }
461
462 bool RenderSVGText::nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation&, const LayoutPoint&, HitTestAction)
463 {
464     ASSERT_NOT_REACHED();
465     return false;
466 }
467
468 VisiblePosition RenderSVGText::positionForPoint(const LayoutPoint& pointInContents, const RenderRegion* region)
469 {
470     RootInlineBox* rootBox = firstRootBox();
471     if (!rootBox)
472         return createVisiblePosition(0, DOWNSTREAM);
473
474     ASSERT_WITH_SECURITY_IMPLICATION(rootBox->isSVGRootInlineBox());
475     ASSERT(!rootBox->nextRootBox());
476     ASSERT(childrenInline());
477
478     InlineBox* closestBox = toSVGRootInlineBox(rootBox)->closestLeafChildForPosition(pointInContents);
479     if (!closestBox)
480         return createVisiblePosition(0, DOWNSTREAM);
481
482     return closestBox->renderer().positionForPoint(LayoutPoint(pointInContents.x(), closestBox->y()), region);
483 }
484
485 void RenderSVGText::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const
486 {
487     quads.append(localToAbsoluteQuad(strokeBoundingBox(), 0 /* mode */, 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 != PaintPhaseSelection)
497          return;
498
499     PaintInfo blockInfo(paintInfo);
500     GraphicsContextStateSaver stateSaver(*blockInfo.context);
501     blockInfo.applyTransform(localToParentTransform());
502     RenderBlock::paint(blockInfo, LayoutPoint());
503
504     // Paint the outlines, if any
505     if (paintInfo.phase == PaintPhaseForeground) {
506         blockInfo.phase = PaintPhaseSelfOutline;
507         RenderBlock::paint(blockInfo, LayoutPoint());
508     }
509 }
510
511 FloatRect RenderSVGText::strokeBoundingBox() const
512 {
513     FloatRect strokeBoundaries = objectBoundingBox();
514     const SVGRenderStyle& svgStyle = style().svgStyle();
515     if (!svgStyle.hasStroke())
516         return strokeBoundaries;
517
518     SVGLengthContext lengthContext(&textElement());
519     strokeBoundaries.inflate(svgStyle.strokeWidth().value(lengthContext));
520     return strokeBoundaries;
521 }
522
523 FloatRect RenderSVGText::repaintRectInLocalCoordinates() const
524 {
525     FloatRect repaintRect = strokeBoundingBox();
526     SVGRenderSupport::intersectRepaintRectWithResources(*this, repaintRect);
527
528     if (const ShadowData* textShadow = style().textShadow())
529         textShadow->adjustRectForShadow(repaintRect);
530
531     return repaintRect;
532 }
533
534 void RenderSVGText::addChild(RenderObject* child, RenderObject* beforeChild)
535 {
536     RenderSVGBlock::addChild(child, beforeChild);
537
538     SVGResourcesCache::clientWasAddedToTree(*child);
539     subtreeChildWasAdded(child);
540 }
541
542 RenderObject* RenderSVGText::removeChild(RenderObject& child)
543 {
544     SVGResourcesCache::clientWillBeRemovedFromTree(child);
545
546     Vector<SVGTextLayoutAttributes*, 2> affectedAttributes;
547     FontCachePurgePreventer fontCachePurgePreventer;
548     subtreeChildWillBeRemoved(&child, affectedAttributes);
549     RenderObject* next = RenderSVGBlock::removeChild(child);
550     subtreeChildWasRemoved(affectedAttributes);
551     return next;
552 }
553
554 // Fix for <rdar://problem/8048875>. We should not render :first-line CSS Style
555 // in a SVG text element context.
556 RenderBlock* RenderSVGText::firstLineBlock() const
557 {
558     return 0;
559 }
560
561 // Fix for <rdar://problem/8048875>. We should not render :first-letter CSS Style
562 // in a SVG text element context.
563 void RenderSVGText::updateFirstLetter()
564 {
565 }
566
567 }