Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(309)

Unified Diff: Source/WebCore/rendering/svg/RenderSVGText.cpp

Issue 10443073: Merge 117225 (Closed) Base URL: http://svn.webkit.org/repository/webkit/branches/chromium/1132/
Patch Set: Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « Source/WebCore/rendering/svg/RenderSVGText.h ('k') | Source/WebCore/rendering/svg/SVGRenderSupport.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: Source/WebCore/rendering/svg/RenderSVGText.cpp
===================================================================
--- Source/WebCore/rendering/svg/RenderSVGText.cpp (revision 118874)
+++ Source/WebCore/rendering/svg/RenderSVGText.cpp (working copy)
@@ -57,12 +57,17 @@
RenderSVGText::RenderSVGText(SVGTextElement* node)
: RenderSVGBlock(node)
, m_needsReordering(false)
- , m_needsPositioningValuesUpdate(true)
+ , m_needsPositioningValuesUpdate(false)
, m_needsTransformUpdate(true)
- , m_needsTextMetricsUpdate(true)
+ , m_needsTextMetricsUpdate(false)
{
}
+RenderSVGText::~RenderSVGText()
+{
+ ASSERT(m_layoutAttributes.isEmpty());
+}
+
bool RenderSVGText::isChildAllowed(RenderObject* child, RenderStyle*) const
{
return child->isInline();
@@ -110,31 +115,19 @@
SVGRenderSupport::mapLocalToContainer(this, repaintContainer, transformState, wasFixed);
}
-static inline void recursiveUpdateLayoutAttributes(RenderObject* start, SVGTextLayoutAttributesBuilder& builder)
+static inline void collectLayoutAttributes(RenderObject* text, Vector<SVGTextLayoutAttributes*>& attributes)
{
- if (start->isSVGInlineText()) {
- builder.buildLayoutAttributesForTextRenderer(toRenderSVGInlineText(start));
- return;
+ for (RenderObject* descendant = text; descendant; descendant = descendant->nextInPreOrder(text)) {
+ if (descendant->isSVGInlineText())
+ attributes.append(toRenderSVGInlineText(descendant)->layoutAttributes());
}
-
- for (RenderObject* child = start->firstChild(); child; child = child->nextSibling())
- recursiveUpdateLayoutAttributes(child, builder);
}
-void RenderSVGText::layoutAttributesChanged(RenderObject* child)
-{
- ASSERT(child);
- if (m_needsPositioningValuesUpdate)
- return;
- FontCachePurgePreventer fontCachePurgePreventer;
- recursiveUpdateLayoutAttributes(child, m_layoutAttributesBuilder);
- rebuildLayoutAttributes();
-}
-
static inline bool findPreviousAndNextAttributes(RenderObject* start, RenderSVGInlineText* locateElement, bool& stopAfterNext, SVGTextLayoutAttributes*& previous, SVGTextLayoutAttributes*& next)
{
ASSERT(start);
ASSERT(locateElement);
+ // FIXME: Make this iterative.
for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) {
if (child->isSVGInlineText()) {
RenderSVGInlineText* text = toRenderSVGInlineText(child);
@@ -162,40 +155,177 @@
return false;
}
-void RenderSVGText::layoutAttributesWillBeDestroyed(RenderSVGInlineText* text, Vector<SVGTextLayoutAttributes*>& affectedAttributes)
+inline bool RenderSVGText::shouldHandleSubtreeMutations() const
{
+ if (beingDestroyed() || !everHadLayout()) {
+ ASSERT(m_layoutAttributes.isEmpty());
+ ASSERT(!m_layoutAttributesBuilder.numberOfTextPositioningElements());
+ return false;
+ }
+ return true;
+}
+
+void RenderSVGText::subtreeChildWasAdded(RenderObject* child)
+{
+ ASSERT(child);
+ if (!shouldHandleSubtreeMutations() || documentBeingDestroyed())
+ return;
+
+ // The positioning elements cache doesn't include the new 'child' yet. Clear the
+ // cache, as the next buildLayoutAttributesForTextRenderer() call rebuilds it.
+ m_layoutAttributesBuilder.clearTextPositioningElements();
+
+ // Detect changes in layout attributes and only measure those text parts that have changed!
+ Vector<SVGTextLayoutAttributes*> newLayoutAttributes;
+ collectLayoutAttributes(this, newLayoutAttributes);
+ if (newLayoutAttributes.isEmpty()) {
+ ASSERT(m_layoutAttributes.isEmpty());
+ return;
+ }
+
+ // Compare m_layoutAttributes with newLayoutAttributes to figure out which attribute got added.
+ size_t size = newLayoutAttributes.size();
+ SVGTextLayoutAttributes* attributes = 0;
+ for (size_t i = 0; i < size; ++i) {
+ attributes = newLayoutAttributes[i];
+ if (m_layoutAttributes.find(attributes) == notFound) {
+ // Every time this is invoked, there's only a single new entry in the newLayoutAttributes list, compared to the old in m_layoutAttributes.
+ bool stopAfterNext = false;
+ SVGTextLayoutAttributes* previous = 0;
+ SVGTextLayoutAttributes* next = 0;
+ ASSERT_UNUSED(child, attributes->context() == child);
+ findPreviousAndNextAttributes(this, attributes->context(), stopAfterNext, previous, next);
+
+ if (previous)
+ m_layoutAttributesBuilder.buildLayoutAttributesForTextRenderer(previous->context());
+ m_layoutAttributesBuilder.buildLayoutAttributesForTextRenderer(attributes->context());
+ if (next)
+ m_layoutAttributesBuilder.buildLayoutAttributesForTextRenderer(next->context());
+ break;
+ }
+ }
+
+#ifndef NDEBUG
+ // Verify that m_layoutAttributes only differs by a maximum of one entry.
+ for (size_t i = 0; i < size; ++i)
+ ASSERT(m_layoutAttributes.find(newLayoutAttributes[i]) != notFound || newLayoutAttributes[i] == attributes);
+#endif
+
+ m_layoutAttributes = newLayoutAttributes;
+}
+
+static inline void checkLayoutAttributesConsistency(RenderSVGText* text, Vector<SVGTextLayoutAttributes*>& expectedLayoutAttributes)
+{
+#ifndef NDEBUG
+ Vector<SVGTextLayoutAttributes*> newLayoutAttributes;
+ collectLayoutAttributes(text, newLayoutAttributes);
+ ASSERT(newLayoutAttributes == expectedLayoutAttributes);
+#else
+ UNUSED_PARAM(text);
+ UNUSED_PARAM(expectedLayoutAttributes);
+#endif
+}
+
+void RenderSVGText::willBeDestroyed()
+{
+ m_layoutAttributes.clear();
+ m_layoutAttributesBuilder.clearTextPositioningElements();
+
+ RenderSVGBlock::willBeDestroyed();
+}
+
+void RenderSVGText::subtreeChildWillBeRemoved(RenderSVGInlineText* text, Vector<SVGTextLayoutAttributes*, 2>& affectedAttributes)
+{
ASSERT(text);
- if (m_needsPositioningValuesUpdate)
+ if (!shouldHandleSubtreeMutations())
return;
+ checkLayoutAttributesConsistency(this, m_layoutAttributes);
+
+ // The positioning elements cache depends on the size of each text renderer in the
+ // subtree. If this changes, clear the cache. It's going to be rebuilt below.
+ m_layoutAttributesBuilder.clearTextPositioningElements();
+ if (m_layoutAttributes.isEmpty())
+ return;
+
+ // This logic requires that the 'text' child is still inserted in the tree.
bool stopAfterNext = false;
SVGTextLayoutAttributes* previous = 0;
SVGTextLayoutAttributes* next = 0;
- findPreviousAndNextAttributes(this, text, stopAfterNext, previous, next);
+ if (!documentBeingDestroyed())
+ findPreviousAndNextAttributes(this, text, stopAfterNext, previous, next);
+
if (previous)
affectedAttributes.append(previous);
if (next)
affectedAttributes.append(next);
+
+ size_t position = m_layoutAttributes.find(text->layoutAttributes());
+ ASSERT(position != notFound);
+ m_layoutAttributes.remove(position);
}
-void RenderSVGText::invalidateTextPositioningElements()
+void RenderSVGText::subtreeChildWasRemoved(const Vector<SVGTextLayoutAttributes*, 2>& affectedAttributes)
{
- // Clear the text positioning elements. This should be called when either the children
- // of a DOM text element have changed, or the length of the text in any child element
- // has changed. Failure to clear may leave us with invalid elements, as other code paths
- // do not always cause the position elements to be marked invalid before use.
+ if (!shouldHandleSubtreeMutations() || documentBeingDestroyed()) {
+ ASSERT(affectedAttributes.isEmpty());
+ return;
+ }
+
+ // This is called immediately after subtreeChildWillBeDestroyed, once the RenderSVGInlineText::willBeDestroyed() method
+ // passes on to the base class, which removes us from the render tree. At this point we can update the layout attributes.
+ unsigned size = affectedAttributes.size();
+ for (unsigned i = 0; i < size; ++i)
+ m_layoutAttributesBuilder.buildLayoutAttributesForTextRenderer(affectedAttributes[i]->context());
+}
+
+void RenderSVGText::subtreeStyleDidChange(RenderSVGInlineText* text)
+{
+ ASSERT(text);
+ if (!shouldHandleSubtreeMutations() || documentBeingDestroyed())
+ return;
+
+ checkLayoutAttributesConsistency(this, m_layoutAttributes);
+
+ // Only update the metrics cache, but not the text positioning element cache
+ // nor the layout attributes cached in the leaf #text renderers.
+ FontCachePurgePreventer fontCachePurgePreventer;
+ for (RenderObject* descendant = text; descendant; descendant = descendant->nextInPreOrder(text)) {
+ if (descendant->isSVGInlineText())
+ m_layoutAttributesBuilder.rebuildMetricsForTextRenderer(toRenderSVGInlineText(descendant));
+ }
+}
+
+void RenderSVGText::subtreeTextDidChange(RenderSVGInlineText* text)
+{
+ ASSERT(text);
+ ASSERT(!beingDestroyed());
+ if (!everHadLayout()) {
+ ASSERT(m_layoutAttributes.isEmpty());
+ ASSERT(!m_layoutAttributesBuilder.numberOfTextPositioningElements());
+ return;
+ }
+
+ // The positioning elements cache depends on the size of each text renderer in the
+ // subtree. If this changes, clear the cache. It's going to be rebuilt below.
m_layoutAttributesBuilder.clearTextPositioningElements();
+
+ checkLayoutAttributesConsistency(this, m_layoutAttributes);
+ for (RenderObject* descendant = text; descendant; descendant = descendant->nextInPreOrder(text)) {
+ if (descendant->isSVGInlineText())
+ m_layoutAttributesBuilder.buildLayoutAttributesForTextRenderer(toRenderSVGInlineText(descendant));
+ }
}
-static inline void recursiveUpdateScaledFont(RenderObject* start)
+static inline void updateFontInAllDescendants(RenderObject* start, SVGTextLayoutAttributesBuilder* builder = 0)
{
- for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) {
- if (child->isSVGInlineText()) {
- toRenderSVGInlineText(child)->updateScaledFont();
+ for (RenderObject* descendant = start; descendant; descendant = descendant->nextInPreOrder(start)) {
+ if (!descendant->isSVGInlineText())
continue;
- }
-
- recursiveUpdateScaledFont(child);
+ RenderSVGInlineText* text = toRenderSVGInlineText(descendant);
+ text->updateScaledFont();
+ if (builder)
+ builder->rebuildMetricsForTextRenderer(text);
}
}
@@ -212,23 +342,43 @@
updateCachedBoundariesInParents = true;
}
- // If the root layout size changed (eg. window size changes) or the positioning values change
- // or the transform to the root context has changed then recompute the on-screen font size.
- if (m_needsTextMetricsUpdate || SVGRenderSupport::findTreeRootObject(this)->isLayoutSizeChanged()) {
- recursiveUpdateScaledFont(this);
- rebuildLayoutAttributes(true);
+ if (!everHadLayout()) {
+ // When laying out initially, collect all layout attributes, build the character data map,
+ // and propogate resulting SVGLayoutAttributes to all RenderSVGInlineText children in the subtree.
+ ASSERT(m_layoutAttributes.isEmpty());
+ collectLayoutAttributes(this, m_layoutAttributes);
+ updateFontInAllDescendants(this);
+ m_layoutAttributesBuilder.buildLayoutAttributesForForSubtree(this);
+
+ m_needsReordering = true;
+ m_needsTextMetricsUpdate = false;
+ m_needsPositioningValuesUpdate = false;
updateCachedBoundariesInParents = true;
- m_needsTextMetricsUpdate = false;
- }
+ } else if (m_needsPositioningValuesUpdate) {
+ // When the x/y/dx/dy/rotate lists change, recompute the layout attributes, and eventually
+ // update the on-screen font objects as well in all descendants.
+ if (m_needsTextMetricsUpdate) {
+ updateFontInAllDescendants(this);
+ m_needsTextMetricsUpdate = false;
+ }
- if (m_needsPositioningValuesUpdate) {
- // Perform SVG text layout phase one (see SVGTextLayoutAttributesBuilder for details).
- m_layoutAttributesBuilder.buildLayoutAttributesForWholeTree(this);
+ m_layoutAttributesBuilder.buildLayoutAttributesForForSubtree(this);
m_needsReordering = true;
m_needsPositioningValuesUpdate = false;
updateCachedBoundariesInParents = true;
+ } else if (m_needsTextMetricsUpdate || SVGRenderSupport::findTreeRootObject(this)->isLayoutSizeChanged()) {
+ // If the root layout size changed (eg. window size changes) or the transform to the root
+ // context has changed then recompute the on-screen font size.
+ updateFontInAllDescendants(this, &m_layoutAttributesBuilder);
+
+ ASSERT(!m_needsReordering);
+ ASSERT(!m_needsPositioningValuesUpdate);
+ m_needsTextMetricsUpdate = false;
+ updateCachedBoundariesInParents = true;
}
+ checkLayoutAttributesConsistency(this, m_layoutAttributes);
+
// Reduced version of RenderBlock::layoutBlock(), which only takes care of SVG text.
// All if branches that could cause early exit in RenderBlocks layoutBlock() method are turned into assertions.
ASSERT(!isInline());
@@ -364,9 +514,23 @@
void RenderSVGText::addChild(RenderObject* child, RenderObject* beforeChild)
{
RenderSVGBlock::addChild(child, beforeChild);
- layoutAttributesChanged(child);
+ subtreeChildWasAdded(child);
}
+void RenderSVGText::removeChild(RenderObject* child)
+{
+ if (!child->isSVGInlineText()) {
+ RenderSVGBlock::removeChild(child);
+ return;
+ }
+
+ RenderSVGInlineText* text = toRenderSVGInlineText(child);
+ Vector<SVGTextLayoutAttributes*, 2> affectedAttributes;
+ subtreeChildWillBeRemoved(text, affectedAttributes);
+ RenderSVGBlock::removeChild(child);
+ subtreeChildWasRemoved(affectedAttributes);
+}
+
// Fix for <rdar://problem/8048875>. We should not render :first-line CSS Style
// in a SVG text element context.
RenderBlock* RenderSVGText::firstLineBlock() const
@@ -380,61 +544,6 @@
{
}
-static inline void recursiveCollectLayoutAttributes(RenderObject* start, Vector<SVGTextLayoutAttributes*>& attributes)
-{
- for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) {
- if (child->isSVGInlineText()) {
- attributes.append(toRenderSVGInlineText(child)->layoutAttributes());
- continue;
- }
-
- recursiveCollectLayoutAttributes(child, attributes);
- }
}
-void RenderSVGText::rebuildLayoutAttributes(bool performFullRebuild)
-{
- if (performFullRebuild)
- m_layoutAttributes.clear();
-
- if (m_layoutAttributes.isEmpty()) {
- recursiveCollectLayoutAttributes(this, m_layoutAttributes);
- if (m_layoutAttributes.isEmpty() || !performFullRebuild)
- return;
-
- m_layoutAttributesBuilder.rebuildMetricsForWholeTree(this);
- return;
- }
-
- Vector<SVGTextLayoutAttributes*> affectedAttributes;
- rebuildLayoutAttributes(affectedAttributes);
-}
-
-void RenderSVGText::rebuildLayoutAttributes(Vector<SVGTextLayoutAttributes*>& affectedAttributes)
-{
- // Detect changes in layout attributes and only measure those text parts that have changed!
- Vector<SVGTextLayoutAttributes*> newLayoutAttributes;
- recursiveCollectLayoutAttributes(this, newLayoutAttributes);
- if (newLayoutAttributes.isEmpty()) {
- m_layoutAttributes.clear();
- return;
- }
-
- // Compare m_layoutAttributes with newLayoutAttributes to figure out which attributes got added/removed.
- size_t size = newLayoutAttributes.size();
- for (size_t i = 0; i < size; ++i) {
- SVGTextLayoutAttributes* attributes = newLayoutAttributes[i];
- if (m_layoutAttributes.find(attributes) == notFound)
- m_layoutAttributesBuilder.rebuildMetricsForTextRenderer(attributes->context());
- }
-
- size = affectedAttributes.size();
- for (size_t i = 0; i < size; ++i)
- m_layoutAttributesBuilder.rebuildMetricsForTextRenderer(affectedAttributes[i]->context());
-
- m_layoutAttributes = newLayoutAttributes;
-}
-
-}
-
#endif // ENABLE(SVG)
« no previous file with comments | « Source/WebCore/rendering/svg/RenderSVGText.h ('k') | Source/WebCore/rendering/svg/SVGRenderSupport.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698