summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/rendering/svg
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/rendering/svg')
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGInline.cpp1
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGInlineText.cpp10
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGPath.cpp4
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp4
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.cpp27
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.h2
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGResourceGradient.cpp10
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGResourceGradient.h2
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGResourceMasker.cpp2
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGResourcePattern.cpp4
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGShadowTreeRootContainer.cpp4
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGText.cpp5
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGText.h2
-rw-r--r--Source/WebCore/rendering/svg/SVGInlineFlowBox.cpp14
-rw-r--r--Source/WebCore/rendering/svg/SVGInlineFlowBox.h2
-rw-r--r--Source/WebCore/rendering/svg/SVGInlineTextBox.cpp35
-rw-r--r--Source/WebCore/rendering/svg/SVGInlineTextBox.h2
-rw-r--r--Source/WebCore/rendering/svg/SVGMarkerLayoutInfo.cpp9
-rw-r--r--Source/WebCore/rendering/svg/SVGMarkerLayoutInfo.h1
-rw-r--r--Source/WebCore/rendering/svg/SVGRenderTreeAsText.cpp6
-rw-r--r--Source/WebCore/rendering/svg/SVGResourcesCache.cpp4
-rw-r--r--Source/WebCore/rendering/svg/SVGRootInlineBox.cpp23
-rw-r--r--Source/WebCore/rendering/svg/SVGRootInlineBox.h2
-rw-r--r--Source/WebCore/rendering/svg/SVGShadowTreeElements.cpp16
-rw-r--r--Source/WebCore/rendering/svg/SVGShadowTreeElements.h8
-rw-r--r--Source/WebCore/rendering/svg/SVGTextChunkBuilder.cpp28
-rw-r--r--Source/WebCore/rendering/svg/SVGTextFragment.h62
-rw-r--r--Source/WebCore/rendering/svg/SVGTextLayoutAttributes.cpp53
-rw-r--r--Source/WebCore/rendering/svg/SVGTextLayoutAttributes.h41
-rw-r--r--Source/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.cpp227
-rw-r--r--Source/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.h39
-rw-r--r--Source/WebCore/rendering/svg/SVGTextLayoutEngine.cpp87
-rw-r--r--Source/WebCore/rendering/svg/SVGTextQuery.cpp53
33 files changed, 465 insertions, 324 deletions
diff --git a/Source/WebCore/rendering/svg/RenderSVGInline.cpp b/Source/WebCore/rendering/svg/RenderSVGInline.cpp
index 543d14b..02a85ce 100644
--- a/Source/WebCore/rendering/svg/RenderSVGInline.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGInline.cpp
@@ -33,6 +33,7 @@ namespace WebCore {
RenderSVGInline::RenderSVGInline(Node* n)
: RenderInline(n)
{
+ setAlwaysCreateLineBoxes();
}
InlineFlowBox* RenderSVGInline::createInlineFlowBox()
diff --git a/Source/WebCore/rendering/svg/RenderSVGInlineText.cpp b/Source/WebCore/rendering/svg/RenderSVGInlineText.cpp
index a8aa0c8..c8539c6 100644
--- a/Source/WebCore/rendering/svg/RenderSVGInlineText.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGInlineText.cpp
@@ -179,8 +179,11 @@ VisiblePosition RenderSVGInlineText::positionForPoint(const IntPoint& point)
const SVGTextFragment* closestDistanceFragment = 0;
SVGInlineTextBox* closestDistanceBox = 0;
+ AffineTransform fragmentTransform;
for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
- ASSERT(box->isSVGInlineTextBox());
+ if (!box->isSVGInlineTextBox())
+ continue;
+
SVGInlineTextBox* textBox = static_cast<SVGInlineTextBox*>(box);
Vector<SVGTextFragment>& fragments = textBox->textFragments();
@@ -188,8 +191,9 @@ VisiblePosition RenderSVGInlineText::positionForPoint(const IntPoint& point)
for (unsigned i = 0; i < textFragmentsSize; ++i) {
const SVGTextFragment& fragment = fragments.at(i);
FloatRect fragmentRect(fragment.x, fragment.y - baseline, fragment.width, fragment.height);
- if (!fragment.transform.isIdentity())
- fragmentRect = fragment.transform.mapRect(fragmentRect);
+ fragment.buildFragmentTransform(fragmentTransform);
+ if (!fragmentTransform.isIdentity())
+ fragmentRect = fragmentTransform.mapRect(fragmentRect);
float distance = powf(fragmentRect.x() - absolutePoint.x(), 2) +
powf(fragmentRect.y() + fragmentRect.height() / 2 - absolutePoint.y(), 2);
diff --git a/Source/WebCore/rendering/svg/RenderSVGPath.cpp b/Source/WebCore/rendering/svg/RenderSVGPath.cpp
index 1d9eca1..cc7c86e 100644
--- a/Source/WebCore/rendering/svg/RenderSVGPath.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGPath.cpp
@@ -128,8 +128,10 @@ void RenderSVGPath::layout()
updateCachedBoundariesInParents = true;
// Invalidate all resources of this client if our layout changed.
- if (m_everHadLayout && selfNeedsLayout())
+ if (m_everHadLayout && selfNeedsLayout()) {
SVGResourcesCache::clientLayoutChanged(this);
+ m_markerLayoutInfo.clear();
+ }
// At this point LayoutRepainter already grabbed the old bounds,
// recalculate them now so repaintAfterLayout() uses the new bounds.
diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp
index 96514af..09195f5 100644
--- a/Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp
@@ -278,7 +278,7 @@ void RenderSVGResourceFilter::postApplyResource(RenderObject* object, GraphicsCo
context = filterData->savedContext;
filterData->savedContext = 0;
-#if !PLATFORM(CG)
+#if !USE(CG)
if (filterData->sourceGraphicBuffer)
filterData->sourceGraphicBuffer->transformColorSpace(ColorSpaceDeviceRGB, ColorSpaceLinearRGB);
#endif
@@ -296,7 +296,7 @@ void RenderSVGResourceFilter::postApplyResource(RenderObject* object, GraphicsCo
// Always true if filterData is just built (filterData->builded is false).
if (!lastEffect->hasResult()) {
lastEffect->apply();
-#if !PLATFORM(CG)
+#if !USE(CG)
ImageBuffer* resultImage = lastEffect->asImageBuffer();
if (resultImage)
resultImage->transformColorSpace(ColorSpaceLinearRGB, ColorSpaceDeviceRGB);
diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.cpp
index 64df700..f077bfd 100644
--- a/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.cpp
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2010 University of Szeged
* Copyright (C) 2010 Zoltan Herczeg
+ * Copyright (C) 2011 Renata Hodovan (reni@webkit.org)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -32,9 +33,35 @@
#include "RenderSVGResource.h"
#include "SVGFEImage.h"
#include "SVGFilter.h"
+#include "SVGNames.h"
namespace WebCore {
+
+void RenderSVGResourceFilterPrimitive::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
+{
+ RenderSVGHiddenContainer::styleDidChange(diff, oldStyle);
+
+ RenderObject* filter = parent();
+ if (!filter)
+ return;
+ ASSERT(filter->isSVGResourceFilter());
+
+ if (diff == StyleDifferenceEqual || !oldStyle)
+ return;
+
+ const SVGRenderStyle* newStyle = this->style()->svgStyle();
+ if (node()->hasTagName(SVGNames::feFloodTag)) {
+ if (newStyle->floodColor() != oldStyle->svgStyle()->floodColor())
+ static_cast<RenderSVGResourceFilter*>(filter)->primitiveAttributeChanged(this, SVGNames::flood_colorAttr);
+ if (newStyle->floodOpacity() != oldStyle->svgStyle()->floodOpacity())
+ static_cast<RenderSVGResourceFilter*>(filter)->primitiveAttributeChanged(this, SVGNames::flood_opacityAttr);
+ } else if (node()->hasTagName(SVGNames::feDiffuseLightingTag) || node()->hasTagName(SVGNames::feSpecularLightingTag)) {
+ if (newStyle->lightingColor() != oldStyle->svgStyle()->lightingColor())
+ static_cast<RenderSVGResourceFilter*>(filter)->primitiveAttributeChanged(this, SVGNames::lighting_colorAttr);
+ }
+}
+
FloatRect RenderSVGResourceFilterPrimitive::determineFilterPrimitiveSubregion(FilterEffect* effect)
{
FloatRect uniteRect;
diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.h b/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.h
index 8176d29..e8e4efc 100644
--- a/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.h
+++ b/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.h
@@ -43,6 +43,8 @@ public:
{
}
+ virtual void styleDidChange(StyleDifference, const RenderStyle*);
+
virtual const char* renderName() const { return "RenderSVGResourceFilterPrimitive"; }
virtual bool isSVGResourceFilterPrimitive() const { return true; }
diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceGradient.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceGradient.cpp
index 9f2bb8d..a42a227 100644
--- a/Source/WebCore/rendering/svg/RenderSVGResourceGradient.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGResourceGradient.cpp
@@ -37,7 +37,7 @@ namespace WebCore {
RenderSVGResourceGradient::RenderSVGResourceGradient(SVGGradientElement* node)
: RenderSVGResourceContainer(node)
, m_shouldCollectGradientAttributes(true)
-#if PLATFORM(CG)
+#if USE(CG)
, m_savedContext(0)
#endif
{
@@ -73,7 +73,7 @@ void RenderSVGResourceGradient::removeClientFromCache(RenderObject* client, bool
markClientForInvalidation(client, markForInvalidation ? RepaintInvalidation : ParentOnlyInvalidation);
}
-#if PLATFORM(CG)
+#if USE(CG)
static inline bool createMaskAndSwapContextForTextGradient(GraphicsContext*& context,
GraphicsContext*& savedContext,
OwnPtr<ImageBuffer>& imageBuffer,
@@ -178,7 +178,7 @@ bool RenderSVGResourceGradient::applyResource(RenderObject* object, RenderStyle*
// CG platforms will handle the gradient space transform for text after applying the
// resource, so don't apply it here. For non-CG platforms, we want the text bounding
// box applied to the gradient space transform now, so the gradient shader can use it.
-#if PLATFORM(CG)
+#if USE(CG)
if (boundingBoxMode() && !objectBoundingBox.isEmpty() && !isPaintingText) {
#else
if (boundingBoxMode() && !objectBoundingBox.isEmpty()) {
@@ -201,7 +201,7 @@ bool RenderSVGResourceGradient::applyResource(RenderObject* object, RenderStyle*
context->save();
if (isPaintingText) {
-#if PLATFORM(CG)
+#if USE(CG)
if (!createMaskAndSwapContextForTextGradient(context, m_savedContext, m_imageBuffer, object)) {
context->restore();
return false;
@@ -235,7 +235,7 @@ void RenderSVGResourceGradient::postApplyResource(RenderObject* object, Graphics
ASSERT(resourceMode != ApplyToDefaultMode);
if (resourceMode & ApplyToTextMode) {
-#if PLATFORM(CG)
+#if USE(CG)
// CG requires special handling for gradient on text
if (m_savedContext && m_gradient.contains(object)) {
GradientData* gradientData = m_gradient.get(object);
diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceGradient.h b/Source/WebCore/rendering/svg/RenderSVGResourceGradient.h
index ad40b53..a71b6c5 100644
--- a/Source/WebCore/rendering/svg/RenderSVGResourceGradient.h
+++ b/Source/WebCore/rendering/svg/RenderSVGResourceGradient.h
@@ -65,7 +65,7 @@ private:
bool m_shouldCollectGradientAttributes : 1;
HashMap<RenderObject*, GradientData*> m_gradient;
-#if PLATFORM(CG)
+#if USE(CG)
GraphicsContext* m_savedContext;
OwnPtr<ImageBuffer> m_imageBuffer;
#endif
diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceMasker.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceMasker.cpp
index 7b24248..dc0df08 100644
--- a/Source/WebCore/rendering/svg/RenderSVGResourceMasker.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGResourceMasker.cpp
@@ -154,7 +154,7 @@ void RenderSVGResourceMasker::drawContentIntoMaskImage(MaskerData* maskerData, c
maskImageContext->restore();
-#if !PLATFORM(CG)
+#if !USE(CG)
maskerData->maskImage->transformColorSpace(ColorSpaceDeviceRGB, ColorSpaceLinearRGB);
#endif
diff --git a/Source/WebCore/rendering/svg/RenderSVGResourcePattern.cpp b/Source/WebCore/rendering/svg/RenderSVGResourcePattern.cpp
index b82be1b..fc26978 100644
--- a/Source/WebCore/rendering/svg/RenderSVGResourcePattern.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGResourcePattern.cpp
@@ -166,13 +166,13 @@ bool RenderSVGResourcePattern::applyResource(RenderObject* object, RenderStyle*
if (resourceMode & ApplyToFillMode) {
context->setTextDrawingMode(TextModeFill);
-#if PLATFORM(CG)
+#if USE(CG)
context->applyFillPattern();
#endif
} else if (resourceMode & ApplyToStrokeMode) {
context->setTextDrawingMode(TextModeStroke);
-#if PLATFORM(CG)
+#if USE(CG)
context->applyStrokePattern();
#endif
}
diff --git a/Source/WebCore/rendering/svg/RenderSVGShadowTreeRootContainer.cpp b/Source/WebCore/rendering/svg/RenderSVGShadowTreeRootContainer.cpp
index 5736333..d2a1103 100644
--- a/Source/WebCore/rendering/svg/RenderSVGShadowTreeRootContainer.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGShadowTreeRootContainer.cpp
@@ -38,7 +38,7 @@ RenderSVGShadowTreeRootContainer::~RenderSVGShadowTreeRootContainer()
{
if (m_shadowRoot && m_shadowRoot->attached()) {
m_shadowRoot->detach();
- m_shadowRoot->clearShadowHost();
+ m_shadowRoot->clearSVGShadowHost();
}
}
@@ -59,7 +59,7 @@ void RenderSVGShadowTreeRootContainer::updateFromElement()
useElement->buildPendingResource();
}
- ASSERT(m_shadowRoot->shadowHost() == useElement);
+ ASSERT(m_shadowRoot->svgShadowHost() == useElement);
bool shouldRecreateTree = m_recreateTree;
if (m_recreateTree) {
diff --git a/Source/WebCore/rendering/svg/RenderSVGText.cpp b/Source/WebCore/rendering/svg/RenderSVGText.cpp
index 8ca3d58..7af6cc6 100644
--- a/Source/WebCore/rendering/svg/RenderSVGText.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGText.cpp
@@ -57,6 +57,11 @@ RenderSVGText::RenderSVGText(SVGTextElement* node)
{
}
+bool RenderSVGText::isChildAllowed(RenderObject* child, RenderStyle*) const
+{
+ return child->isInline();
+}
+
RenderSVGText* RenderSVGText::locateRenderSVGTextAncestor(RenderObject* start)
{
ASSERT(start);
diff --git a/Source/WebCore/rendering/svg/RenderSVGText.h b/Source/WebCore/rendering/svg/RenderSVGText.h
index 93fc5f8..15ace2b 100644
--- a/Source/WebCore/rendering/svg/RenderSVGText.h
+++ b/Source/WebCore/rendering/svg/RenderSVGText.h
@@ -36,6 +36,8 @@ class RenderSVGText : public RenderSVGBlock {
public:
RenderSVGText(SVGTextElement*);
+ virtual bool isChildAllowed(RenderObject*, RenderStyle*) const;
+
void setNeedsPositioningValuesUpdate() { m_needsPositioningValuesUpdate = true; }
virtual void setNeedsTransformUpdate() { m_needsTransformUpdate = true; }
virtual FloatRect repaintRectInLocalCoordinates() const;
diff --git a/Source/WebCore/rendering/svg/SVGInlineFlowBox.cpp b/Source/WebCore/rendering/svg/SVGInlineFlowBox.cpp
index 10735f6..85707da 100644
--- a/Source/WebCore/rendering/svg/SVGInlineFlowBox.cpp
+++ b/Source/WebCore/rendering/svg/SVGInlineFlowBox.cpp
@@ -48,7 +48,7 @@ void SVGInlineFlowBox::paintSelectionBackground(PaintInfo& paintInfo)
}
}
-void SVGInlineFlowBox::paint(PaintInfo& paintInfo, int, int)
+void SVGInlineFlowBox::paint(PaintInfo& paintInfo, int, int, int, int)
{
ASSERT(paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection);
ASSERT(!paintInfo.context->paintingDisabled());
@@ -64,7 +64,7 @@ void SVGInlineFlowBox::paint(PaintInfo& paintInfo, int, int)
if (child->isSVGInlineTextBox())
computeTextMatchMarkerRectForRenderer(toRenderSVGInlineText(static_cast<SVGInlineTextBox*>(child)->textRenderer()));
- child->paint(childPaintInfo, 0, 0);
+ child->paint(childPaintInfo, 0, 0, 0, 0);
}
}
@@ -91,6 +91,7 @@ void SVGInlineFlowBox::computeTextMatchMarkerRectForRenderer(RenderSVGInlineText
RenderStyle* style = textRenderer->style();
ASSERT(style);
+ AffineTransform fragmentTransform;
Document* document = textRenderer->document();
Vector<DocumentMarker> markers = document->markers()->markersForNode(textRenderer->node());
@@ -104,7 +105,9 @@ void SVGInlineFlowBox::computeTextMatchMarkerRectForRenderer(RenderSVGInlineText
FloatRect markerRect;
for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
- ASSERT(box->isSVGInlineTextBox());
+ if (!box->isSVGInlineTextBox())
+ continue;
+
SVGInlineTextBox* textBox = static_cast<SVGInlineTextBox*>(box);
int markerStartPosition = max<int>(marker.startOffset - textBox->start(), 0);
@@ -127,8 +130,9 @@ void SVGInlineFlowBox::computeTextMatchMarkerRectForRenderer(RenderSVGInlineText
continue;
FloatRect fragmentRect = textBox->selectionRectForTextFragment(fragment, fragmentStartPosition, fragmentEndPosition, style);
- if (!fragment.transform.isIdentity())
- fragmentRect = fragment.transform.mapRect(fragmentRect);
+ fragment.buildFragmentTransform(fragmentTransform);
+ if (!fragmentTransform.isIdentity())
+ fragmentRect = fragmentTransform.mapRect(fragmentRect);
markerRect.unite(fragmentRect);
}
diff --git a/Source/WebCore/rendering/svg/SVGInlineFlowBox.h b/Source/WebCore/rendering/svg/SVGInlineFlowBox.h
index 0e56c9f..304c616 100644
--- a/Source/WebCore/rendering/svg/SVGInlineFlowBox.h
+++ b/Source/WebCore/rendering/svg/SVGInlineFlowBox.h
@@ -41,7 +41,7 @@ public:
void setLogicalHeight(int h) { m_logicalHeight = h; }
void paintSelectionBackground(PaintInfo&);
- virtual void paint(PaintInfo&, int tx, int ty);
+ virtual void paint(PaintInfo&, int tx, int ty, int lineTop, int lineBottom);
virtual IntRect calculateBoundaries() const;
diff --git a/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp b/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp
index 17bbfaa..bc550a6 100644
--- a/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp
+++ b/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp
@@ -70,8 +70,10 @@ int SVGInlineTextBox::offsetForPositionInFragment(const SVGTextFragment& fragmen
// Eventually handle lengthAdjust="spacingAndGlyphs".
// FIXME: Handle vertical text.
- if (!fragment.transform.isIdentity())
- textRun.setHorizontalGlyphStretch(narrowPrecisionToFloat(fragment.transform.xScale()));
+ AffineTransform fragmentTransform;
+ fragment.buildFragmentTransform(fragmentTransform);
+ if (!fragmentTransform.isIdentity())
+ textRun.setHorizontalGlyphStretch(narrowPrecisionToFloat(fragmentTransform.xScale()));
return fragment.characterOffset - start() + textRenderer->scaledFont().offsetForPosition(textRun, position * scalingFactor, includePartialGlyphs);
}
@@ -124,6 +126,7 @@ IntRect SVGInlineTextBox::selectionRect(int, int, int startPosition, int endPosi
RenderStyle* style = text->style();
ASSERT(style);
+ AffineTransform fragmentTransform;
FloatRect selectionRect;
int fragmentStartPosition = 0;
int fragmentEndPosition = 0;
@@ -138,8 +141,9 @@ IntRect SVGInlineTextBox::selectionRect(int, int, int startPosition, int endPosi
continue;
FloatRect fragmentRect = selectionRectForTextFragment(fragment, fragmentStartPosition, fragmentEndPosition, style);
- if (!fragment.transform.isIdentity())
- fragmentRect = fragment.transform.mapRect(fragmentRect);
+ fragment.buildFragmentTransform(fragmentTransform);
+ if (!fragmentTransform.isIdentity())
+ fragmentRect = fragmentTransform.mapRect(fragmentRect);
selectionRect.unite(fragmentRect);
}
@@ -211,6 +215,7 @@ void SVGInlineTextBox::paintSelectionBackground(PaintInfo& paintInfo)
int fragmentStartPosition = 0;
int fragmentEndPosition = 0;
+ AffineTransform fragmentTransform;
unsigned textFragmentsSize = m_textFragments.size();
for (unsigned i = 0; i < textFragmentsSize; ++i) {
SVGTextFragment& fragment = m_textFragments.at(i);
@@ -222,9 +227,9 @@ void SVGInlineTextBox::paintSelectionBackground(PaintInfo& paintInfo)
continue;
paintInfo.context->save();
-
- if (!fragment.transform.isIdentity())
- paintInfo.context->concatCTM(fragment.transform);
+ fragment.buildFragmentTransform(fragmentTransform);
+ if (!fragmentTransform.isIdentity())
+ paintInfo.context->concatCTM(fragmentTransform);
paintInfo.context->setFillColor(backgroundColor, style->colorSpace());
paintInfo.context->fillRect(selectionRectForTextFragment(fragment, fragmentStartPosition, fragmentEndPosition, style), backgroundColor, style->colorSpace());
@@ -236,7 +241,7 @@ void SVGInlineTextBox::paintSelectionBackground(PaintInfo& paintInfo)
ASSERT(!m_paintingResource);
}
-void SVGInlineTextBox::paint(PaintInfo& paintInfo, int, int)
+void SVGInlineTextBox::paint(PaintInfo& paintInfo, int, int, int, int)
{
ASSERT(paintInfo.shouldPaintWithinRoot(renderer()));
ASSERT(paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection);
@@ -285,15 +290,16 @@ void SVGInlineTextBox::paint(PaintInfo& paintInfo, int, int)
selectionStyle = style;
}
+ AffineTransform fragmentTransform;
unsigned textFragmentsSize = m_textFragments.size();
for (unsigned i = 0; i < textFragmentsSize; ++i) {
SVGTextFragment& fragment = m_textFragments.at(i);
ASSERT(!m_paintingResource);
paintInfo.context->save();
-
- if (!fragment.transform.isIdentity())
- paintInfo.context->concatCTM(fragment.transform);
+ fragment.buildFragmentTransform(fragmentTransform);
+ if (!fragmentTransform.isIdentity())
+ paintInfo.context->concatCTM(fragmentTransform);
// Spec: All text decorations except line-through should be drawn before the text is filled and stroked; thus, the text is rendered on top of these decorations.
int decorations = style->textDecorationsInEffect();
@@ -694,13 +700,14 @@ IntRect SVGInlineTextBox::calculateBoundaries() const
float baseline = textRenderer->scaledFont().fontMetrics().floatAscent() / scalingFactor;
+ AffineTransform fragmentTransform;
unsigned textFragmentsSize = m_textFragments.size();
for (unsigned i = 0; i < textFragmentsSize; ++i) {
const SVGTextFragment& fragment = m_textFragments.at(i);
FloatRect fragmentRect(fragment.x, fragment.y - baseline, fragment.width, fragment.height);
-
- if (!fragment.transform.isIdentity())
- fragmentRect = fragment.transform.mapRect(fragmentRect);
+ fragment.buildFragmentTransform(fragmentTransform);
+ if (!fragmentTransform.isIdentity())
+ fragmentRect = fragmentTransform.mapRect(fragmentRect);
textRect.unite(fragmentRect);
}
diff --git a/Source/WebCore/rendering/svg/SVGInlineTextBox.h b/Source/WebCore/rendering/svg/SVGInlineTextBox.h
index 79c836f..ce48019 100644
--- a/Source/WebCore/rendering/svg/SVGInlineTextBox.h
+++ b/Source/WebCore/rendering/svg/SVGInlineTextBox.h
@@ -46,7 +46,7 @@ public:
virtual float positionForOffset(int offset) const;
void paintSelectionBackground(PaintInfo&);
- virtual void paint(PaintInfo&, int tx, int ty);
+ virtual void paint(PaintInfo&, int tx, int ty, int lineTop, int lineBottom);
virtual IntRect selectionRect(int absx, int absy, int startPosition, int endPosition);
bool mapStartEndPositionsIntoFragmentCoordinates(const SVGTextFragment&, int& startPosition, int& endPosition) const;
diff --git a/Source/WebCore/rendering/svg/SVGMarkerLayoutInfo.cpp b/Source/WebCore/rendering/svg/SVGMarkerLayoutInfo.cpp
index dea5a0c..27b37f1 100644
--- a/Source/WebCore/rendering/svg/SVGMarkerLayoutInfo.cpp
+++ b/Source/WebCore/rendering/svg/SVGMarkerLayoutInfo.cpp
@@ -98,6 +98,15 @@ FloatRect SVGMarkerLayoutInfo::calculateBoundaries(RenderSVGResourceMarker* star
return bounds;
}
+void SVGMarkerLayoutInfo::clear()
+{
+ m_midMarker = 0;
+ m_elementIndex = 0;
+ m_strokeWidth = 0;
+ m_markerData.updateTypeAndMarker(SVGMarkerData::Unknown, 0);
+ m_layout.clear();
+}
+
void SVGMarkerLayoutInfo::drawMarkers(PaintInfo& paintInfo)
{
if (m_layout.isEmpty())
diff --git a/Source/WebCore/rendering/svg/SVGMarkerLayoutInfo.h b/Source/WebCore/rendering/svg/SVGMarkerLayoutInfo.h
index 32317b9..c2301cc 100644
--- a/Source/WebCore/rendering/svg/SVGMarkerLayoutInfo.h
+++ b/Source/WebCore/rendering/svg/SVGMarkerLayoutInfo.h
@@ -57,6 +57,7 @@ public:
RenderSVGResourceMarker* midMarker() const { return m_midMarker; }
int& elementIndex() { return m_elementIndex; }
void addLayoutedMarker(RenderSVGResourceMarker*, const FloatPoint& origin, float angle);
+ void clear();
private:
RenderSVGResourceMarker* m_midMarker;
diff --git a/Source/WebCore/rendering/svg/SVGRenderTreeAsText.cpp b/Source/WebCore/rendering/svg/SVGRenderTreeAsText.cpp
index a099f87..7d3f909 100644
--- a/Source/WebCore/rendering/svg/SVGRenderTreeAsText.cpp
+++ b/Source/WebCore/rendering/svg/SVGRenderTreeAsText.cpp
@@ -506,8 +506,12 @@ static inline void writeSVGInlineTextBox(TextStream& ts, SVGInlineTextBox* textB
static inline void writeSVGInlineTextBoxes(TextStream& ts, const RenderText& text, int indent)
{
- for (InlineTextBox* box = text.firstTextBox(); box; box = box->nextTextBox())
+ for (InlineTextBox* box = text.firstTextBox(); box; box = box->nextTextBox()) {
+ if (!box->isSVGInlineTextBox())
+ continue;
+
writeSVGInlineTextBox(ts, static_cast<SVGInlineTextBox*>(box), indent);
+ }
}
static void writeStandardPrefix(TextStream& ts, const RenderObject& object, int indent)
diff --git a/Source/WebCore/rendering/svg/SVGResourcesCache.cpp b/Source/WebCore/rendering/svg/SVGResourcesCache.cpp
index 886f76a..74d2950 100644
--- a/Source/WebCore/rendering/svg/SVGResourcesCache.cpp
+++ b/Source/WebCore/rendering/svg/SVGResourcesCache.cpp
@@ -126,6 +126,10 @@ void SVGResourcesCache::clientStyleChanged(RenderObject* renderer, StyleDifferen
if (diff == StyleDifferenceEqual)
return;
+ // In this case the proper SVGFE*Element will imply whether the modifided CSS properties implies a relayout or repaint.
+ if (renderer->isSVGResourceFilterPrimitive() && diff == StyleDifferenceRepaint)
+ return;
+
clientUpdatedFromElement(renderer, newStyle);
RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer, false);
}
diff --git a/Source/WebCore/rendering/svg/SVGRootInlineBox.cpp b/Source/WebCore/rendering/svg/SVGRootInlineBox.cpp
index ddbd3ea..cc6cb75 100644
--- a/Source/WebCore/rendering/svg/SVGRootInlineBox.cpp
+++ b/Source/WebCore/rendering/svg/SVGRootInlineBox.cpp
@@ -35,7 +35,7 @@
namespace WebCore {
-void SVGRootInlineBox::paint(PaintInfo& paintInfo, int, int)
+void SVGRootInlineBox::paint(PaintInfo& paintInfo, int, int, int, int)
{
ASSERT(paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection);
ASSERT(!paintInfo.context->paintingDisabled());
@@ -63,7 +63,7 @@ void SVGRootInlineBox::paint(PaintInfo& paintInfo, int, int)
if (child->isSVGInlineTextBox())
SVGInlineFlowBox::computeTextMatchMarkerRectForRenderer(toRenderSVGInlineText(static_cast<SVGInlineTextBox*>(child)->textRenderer()));
- child->paint(childPaintInfo, 0, 0);
+ child->paint(childPaintInfo, 0, 0, 0, 0);
}
}
@@ -103,13 +103,13 @@ void SVGRootInlineBox::layoutCharactersInTextBoxes(InlineFlowBox* start, SVGText
SVGInlineTextBox* textBox = static_cast<SVGInlineTextBox*>(child);
characterLayout.layoutInlineTextBox(textBox);
} else {
- ASSERT(child->isInlineFlowBox());
-
// Skip generated content.
Node* node = child->renderer()->node();
if (!node)
continue;
+ ASSERT(child->isInlineFlowBox());
+
SVGInlineFlowBox* flowBox = static_cast<SVGInlineFlowBox*>(child);
bool isTextPath = node->hasTagName(SVGNames::textPathTag);
if (isTextPath) {
@@ -146,12 +146,12 @@ void SVGRootInlineBox::layoutChildBoxes(InlineFlowBox* start)
textBox->setLogicalWidth(boxRect.width());
textBox->setLogicalHeight(boxRect.height());
} else {
- ASSERT(child->isInlineFlowBox());
-
// Skip generated content.
if (!child->renderer()->node())
continue;
+ ASSERT(child->isInlineFlowBox());
+
SVGInlineFlowBox* flowBox = static_cast<SVGInlineFlowBox*>(child);
layoutChildBoxes(flowBox);
@@ -214,6 +214,8 @@ InlineBox* SVGRootInlineBox::closestLeafChildForPosition(const IntPoint& point)
// FIXME: Check for vertical text!
InlineBox* closestLeaf = 0;
for (InlineBox* leaf = firstLeaf; leaf; leaf = leaf->nextLeafChild()) {
+ if (!leaf->isSVGInlineTextBox())
+ continue;
if (point.y() < leaf->m_y)
continue;
if (point.y() > leaf->m_y + leaf->virtualLogicalHeight())
@@ -274,8 +276,13 @@ static inline void reverseInlineBoxRangeAndValueListsIfNeeded(void* userData, Ve
if (first == last || first == --last)
return;
- ASSERT((*first)->isSVGInlineTextBox());
- ASSERT((*last)->isSVGInlineTextBox());
+ if (!(*last)->isSVGInlineTextBox() || !(*first)->isSVGInlineTextBox()) {
+ InlineBox* temp = *first;
+ *first = *last;
+ *last = temp;
+ ++first;
+ continue;
+ }
SVGInlineTextBox* firstTextBox = static_cast<SVGInlineTextBox*>(*first);
SVGInlineTextBox* lastTextBox = static_cast<SVGInlineTextBox*>(*last);
diff --git a/Source/WebCore/rendering/svg/SVGRootInlineBox.h b/Source/WebCore/rendering/svg/SVGRootInlineBox.h
index 39612e7..a83af64 100644
--- a/Source/WebCore/rendering/svg/SVGRootInlineBox.h
+++ b/Source/WebCore/rendering/svg/SVGRootInlineBox.h
@@ -45,7 +45,7 @@ public:
virtual int virtualLogicalHeight() const { return m_logicalHeight; }
void setLogicalHeight(int height) { m_logicalHeight = height; }
- virtual void paint(PaintInfo&, int tx, int ty);
+ virtual void paint(PaintInfo&, int tx, int ty, int lineTop, int lineBottom);
void computePerCharacterLayoutInformation();
diff --git a/Source/WebCore/rendering/svg/SVGShadowTreeElements.cpp b/Source/WebCore/rendering/svg/SVGShadowTreeElements.cpp
index 9ccdef0..ac4a63e 100644
--- a/Source/WebCore/rendering/svg/SVGShadowTreeElements.cpp
+++ b/Source/WebCore/rendering/svg/SVGShadowTreeElements.cpp
@@ -53,21 +53,21 @@ PassRefPtr<Element> SVGShadowTreeContainerElement::cloneElementWithoutAttributes
}
// SVGShadowTreeRootElement
-inline SVGShadowTreeRootElement::SVGShadowTreeRootElement(Document* document, SVGUseElement* shadowParent)
+inline SVGShadowTreeRootElement::SVGShadowTreeRootElement(Document* document, SVGUseElement* host)
: SVGShadowTreeContainerElement(document)
{
- setShadowHost(shadowParent);
+ setParent(host);
setInDocument();
}
-PassRefPtr<SVGShadowTreeRootElement> SVGShadowTreeRootElement::create(Document* document, SVGUseElement* shadowParent)
+PassRefPtr<SVGShadowTreeRootElement> SVGShadowTreeRootElement::create(Document* document, SVGUseElement* host)
{
- return adoptRef(new SVGShadowTreeRootElement(document, shadowParent));
+ return adoptRef(new SVGShadowTreeRootElement(document, host));
}
void SVGShadowTreeRootElement::attachElement(PassRefPtr<RenderStyle> style, RenderArena* arena)
{
- ASSERT(shadowHost());
+ ASSERT(svgShadowHost());
// Create the renderer with the specified style
RenderObject* renderer = createRenderer(arena, style.get());
@@ -81,12 +81,12 @@ void SVGShadowTreeRootElement::attachElement(PassRefPtr<RenderStyle> style, Rend
// Add the renderer to the render tree
if (renderer)
- shadowHost()->renderer()->addChild(renderer);
+ svgShadowHost()->renderer()->addChild(renderer);
}
-void SVGShadowTreeRootElement::clearShadowHost()
+void SVGShadowTreeRootElement::clearSVGShadowHost()
{
- setShadowHost(0);
+ setParent(0);
}
}
diff --git a/Source/WebCore/rendering/svg/SVGShadowTreeElements.h b/Source/WebCore/rendering/svg/SVGShadowTreeElements.h
index 2952e35..8cbd4b7 100644
--- a/Source/WebCore/rendering/svg/SVGShadowTreeElements.h
+++ b/Source/WebCore/rendering/svg/SVGShadowTreeElements.h
@@ -53,13 +53,15 @@ private:
class SVGShadowTreeRootElement : public SVGShadowTreeContainerElement {
public:
- static PassRefPtr<SVGShadowTreeRootElement> create(Document*, SVGUseElement* shadowParent);
+ static PassRefPtr<SVGShadowTreeRootElement> create(Document*, SVGUseElement* host);
void attachElement(PassRefPtr<RenderStyle>, RenderArena*);
- void clearShadowHost();
+ void clearSVGShadowHost();
+
+ virtual bool isSVGShadowRoot() const { return true; }
private:
- SVGShadowTreeRootElement(Document*, SVGUseElement* shadowParent);
+ SVGShadowTreeRootElement(Document*, SVGUseElement* host);
};
}
diff --git a/Source/WebCore/rendering/svg/SVGTextChunkBuilder.cpp b/Source/WebCore/rendering/svg/SVGTextChunkBuilder.cpp
index 47311bd..4391013 100644
--- a/Source/WebCore/rendering/svg/SVGTextChunkBuilder.cpp
+++ b/Source/WebCore/rendering/svg/SVGTextChunkBuilder.cpp
@@ -53,7 +53,7 @@ void SVGTextChunkBuilder::buildTextChunks(Vector<SVGInlineTextBox*>& lineLayoutB
unsigned boxPosition = 0;
unsigned boxCount = lineLayoutBoxes.size();
for (; boxPosition < boxCount; ++boxPosition) {
- SVGInlineTextBox* textBox = lineLayoutBoxes.at(boxPosition);
+ SVGInlineTextBox* textBox = lineLayoutBoxes[boxPosition];
if (!textBox->startsNewTextChunk())
continue;
@@ -82,14 +82,14 @@ void SVGTextChunkBuilder::layoutTextChunks(Vector<SVGInlineTextBox*>& lineLayout
unsigned chunkCount = m_textChunks.size();
for (unsigned i = 0; i < chunkCount; ++i)
- processTextChunk(m_textChunks.at(i));
+ processTextChunk(m_textChunks[i]);
m_textChunks.clear();
}
void SVGTextChunkBuilder::addTextChunk(Vector<SVGInlineTextBox*>& lineLayoutBoxes, unsigned boxStart, unsigned boxCount)
{
- SVGInlineTextBox* textBox = lineLayoutBoxes.at(boxStart);
+ SVGInlineTextBox* textBox = lineLayoutBoxes[boxStart];
ASSERT(textBox);
RenderSVGInlineText* textRenderer = toRenderSVGInlineText(textBox->textRenderer());
@@ -127,7 +127,7 @@ void SVGTextChunkBuilder::addTextChunk(Vector<SVGInlineTextBox*>& lineLayoutBoxe
// Handle 'lengthAdjust' property.
float desiredTextLength = 0;
if (SVGTextContentElement* textContentElement = SVGTextContentElement::elementFromRenderer(textRenderer->parent())) {
- desiredTextLength = textContentElement->textLength().value(textContentElement);
+ desiredTextLength = textContentElement->specifiedTextLength().value(textContentElement);
switch (static_cast<SVGTextContentElement::SVGLengthAdjustType>(textContentElement->lengthAdjust())) {
case SVGTextContentElement::LENGTHADJUST_UNKNOWN:
@@ -145,7 +145,7 @@ void SVGTextChunkBuilder::addTextChunk(Vector<SVGInlineTextBox*>& lineLayoutBoxe
Vector<SVGInlineTextBox*>& boxes = chunk.boxes();
for (unsigned i = boxStart; i < boxStart + boxCount; ++i)
- boxes.append(lineLayoutBoxes.at(i));
+ boxes.append(lineLayoutBoxes[i]);
m_textChunks.append(chunk);
}
@@ -173,26 +173,26 @@ void SVGTextChunkBuilder::processTextChunk(const SVGTextChunk& chunk)
float textLengthShift = (chunk.desiredTextLength() - chunkLength) / chunkCharacters;
unsigned atCharacter = 0;
for (unsigned boxPosition = 0; boxPosition < boxCount; ++boxPosition) {
- Vector<SVGTextFragment>& fragments = boxes.at(boxPosition)->textFragments();
+ Vector<SVGTextFragment>& fragments = boxes[boxPosition]->textFragments();
if (fragments.isEmpty())
- continue;
+ continue;
processTextLengthSpacingCorrection(isVerticalText, textLengthShift, fragments, atCharacter);
}
} else {
ASSERT(chunk.hasLengthAdjustSpacingAndGlyphs());
- float scale = chunk.desiredTextLength() / chunkLength;
+ float textLengthScale = chunk.desiredTextLength() / chunkLength;
AffineTransform spacingAndGlyphsTransform;
bool foundFirstFragment = false;
for (unsigned boxPosition = 0; boxPosition < boxCount; ++boxPosition) {
- SVGInlineTextBox* textBox = boxes.at(boxPosition);
+ SVGInlineTextBox* textBox = boxes[boxPosition];
Vector<SVGTextFragment>& fragments = textBox->textFragments();
if (fragments.isEmpty())
continue;
-
+
if (!foundFirstFragment) {
foundFirstFragment = true;
- buildSpacingAndGlyphsTransform(isVerticalText, scale, fragments.first(), spacingAndGlyphsTransform);
+ buildSpacingAndGlyphsTransform(isVerticalText, textLengthScale, fragments.first(), spacingAndGlyphsTransform);
}
m_textBoxTransformations.set(textBox, spacingAndGlyphsTransform);
@@ -212,7 +212,7 @@ void SVGTextChunkBuilder::processTextChunk(const SVGTextChunk& chunk)
float textAnchorShift = chunk.calculateTextAnchorShift(chunkLength);
for (unsigned boxPosition = 0; boxPosition < boxCount; ++boxPosition) {
- Vector<SVGTextFragment>& fragments = boxes.at(boxPosition)->textFragments();
+ Vector<SVGTextFragment>& fragments = boxes[boxPosition]->textFragments();
if (fragments.isEmpty())
continue;
processTextAnchorCorrection(isVerticalText, textAnchorShift, fragments);
@@ -223,7 +223,7 @@ void SVGTextChunkBuilder::processTextLengthSpacingCorrection(bool isVerticalText
{
unsigned fragmentCount = fragments.size();
for (unsigned i = 0; i < fragmentCount; ++i) {
- SVGTextFragment& fragment = fragments.at(i);
+ SVGTextFragment& fragment = fragments[i];
if (isVerticalText)
fragment.y += textLengthShift * atCharacter;
@@ -238,7 +238,7 @@ void SVGTextChunkBuilder::processTextAnchorCorrection(bool isVerticalText, float
{
unsigned fragmentCount = fragments.size();
for (unsigned i = 0; i < fragmentCount; ++i) {
- SVGTextFragment& fragment = fragments.at(i);
+ SVGTextFragment& fragment = fragments[i];
if (isVerticalText)
fragment.y += textAnchorShift;
diff --git a/Source/WebCore/rendering/svg/SVGTextFragment.h b/Source/WebCore/rendering/svg/SVGTextFragment.h
index b5b3c57..a44d0fa 100644
--- a/Source/WebCore/rendering/svg/SVGTextFragment.h
+++ b/Source/WebCore/rendering/svg/SVGTextFragment.h
@@ -31,6 +31,7 @@ struct SVGTextFragment {
: characterOffset(0)
, metricsListOffset(0)
, length(0)
+ , isTextOnPath(false)
, x(0)
, y(0)
, width(0)
@@ -38,19 +39,74 @@ struct SVGTextFragment {
{
}
+ enum TransformType {
+ TransformRespectingTextLength,
+ TransformIgnoringTextLength
+ };
+
+ void buildFragmentTransform(AffineTransform& result, TransformType type = TransformRespectingTextLength) const
+ {
+ if (type == TransformIgnoringTextLength) {
+ result = transform;
+ transformAroundOrigin(result);
+ return;
+ }
+
+ if (isTextOnPath)
+ buildTransformForTextOnPath(result);
+ else
+ buildTransformForTextOnLine(result);
+ }
+
// The first rendered character starts at RenderSVGInlineText::characters() + characterOffset.
unsigned characterOffset;
unsigned metricsListOffset;
- unsigned length;
+ unsigned length : 31;
+ bool isTextOnPath : 1;
float x;
float y;
float width;
float height;
- // Includes rotation/glyph-orientation-(horizontal|vertical) transforms, lengthAdjust="spacingAndGlyphs" (for textPath only),
- // as well as orientation related shifts (see SVGTextLayoutEngine, which builds this transformation).
+ // Includes rotation/glyph-orientation-(horizontal|vertical) transforms, as well as orientation related shifts
+ // (see SVGTextLayoutEngine, which builds this transformation).
AffineTransform transform;
+
+ // Contains lengthAdjust related transformations, which are not allowd to influence the SVGTextQuery code.
+ AffineTransform lengthAdjustTransform;
+
+private:
+ void transformAroundOrigin(AffineTransform& result) const
+ {
+ // Returns (translate(x, y) * result) * translate(-x, -y).
+ result.setE(result.e() + x);
+ result.setF(result.f() + y);
+ result.translate(-x, -y);
+ }
+
+ void buildTransformForTextOnPath(AffineTransform& result) const
+ {
+ // For text-on-path layout, multiply the transform with the lengthAdjustTransform before orienting the resulting transform.
+ result = lengthAdjustTransform.isIdentity() ? transform : transform * lengthAdjustTransform;
+ if (!result.isIdentity())
+ transformAroundOrigin(result);
+ }
+
+ void buildTransformForTextOnLine(AffineTransform& result) const
+ {
+ // For text-on-line layout, orient the transform first, then multiply the lengthAdjustTransform with the oriented transform.
+ if (transform.isIdentity()) {
+ result = lengthAdjustTransform;
+ return;
+ }
+
+ result = transform;
+ transformAroundOrigin(result);
+
+ if (!lengthAdjustTransform.isIdentity())
+ result = lengthAdjustTransform * result;
+ }
};
} // namespace WebCore
diff --git a/Source/WebCore/rendering/svg/SVGTextLayoutAttributes.cpp b/Source/WebCore/rendering/svg/SVGTextLayoutAttributes.cpp
index 4c227b4..df2cffe 100644
--- a/Source/WebCore/rendering/svg/SVGTextLayoutAttributes.cpp
+++ b/Source/WebCore/rendering/svg/SVGTextLayoutAttributes.cpp
@@ -34,11 +34,44 @@ SVGTextLayoutAttributes::SVGTextLayoutAttributes(RenderSVGInlineText* context)
void SVGTextLayoutAttributes::reserveCapacity(unsigned length)
{
- m_xValues.reserveCapacity(length);
- m_yValues.reserveCapacity(length);
- m_dxValues.reserveCapacity(length);
- m_dyValues.reserveCapacity(length);
- m_rotateValues.reserveCapacity(length);
+ m_positioningLists.xValues.reserveCapacity(length);
+ m_positioningLists.yValues.reserveCapacity(length);
+ m_positioningLists.dxValues.reserveCapacity(length);
+ m_positioningLists.dyValues.reserveCapacity(length);
+ m_positioningLists.rotateValues.reserveCapacity(length);
+ m_textMetricsValues.reserveCapacity(length);
+}
+
+void SVGTextLayoutAttributes::PositioningLists::fillWithEmptyValues(unsigned length)
+{
+ xValues.fill(SVGTextLayoutAttributes::emptyValue(), length);
+ yValues.fill(SVGTextLayoutAttributes::emptyValue(), length);
+ dxValues.fill(SVGTextLayoutAttributes::emptyValue(), length);
+ dyValues.fill(SVGTextLayoutAttributes::emptyValue(), length);
+ rotateValues.fill(SVGTextLayoutAttributes::emptyValue(), length);
+}
+
+void SVGTextLayoutAttributes::PositioningLists::appendEmptyValues()
+{
+ xValues.append(SVGTextLayoutAttributes::emptyValue());
+ yValues.append(SVGTextLayoutAttributes::emptyValue());
+ dxValues.append(SVGTextLayoutAttributes::emptyValue());
+ dyValues.append(SVGTextLayoutAttributes::emptyValue());
+ rotateValues.append(SVGTextLayoutAttributes::emptyValue());
+}
+
+static inline float safeValueAtPosition(const Vector<float>& values, unsigned position)
+{
+ return position < values.size() ? values[position] : SVGTextLayoutAttributes::emptyValue();
+}
+
+void SVGTextLayoutAttributes::PositioningLists::appendValuesFromPosition(const PositioningLists& source, unsigned position)
+{
+ xValues.append(safeValueAtPosition(source.xValues, position));
+ yValues.append(safeValueAtPosition(source.yValues, position));
+ dxValues.append(safeValueAtPosition(source.dxValues, position));
+ dyValues.append(safeValueAtPosition(source.dyValues, position));
+ rotateValues.append(safeValueAtPosition(source.rotateValues, position));
}
float SVGTextLayoutAttributes::emptyValue()
@@ -69,23 +102,23 @@ void SVGTextLayoutAttributes::dump() const
fprintf(stderr, "context: %p\n", m_context);
fprintf(stderr, "x values: ");
- dumpLayoutVector(m_xValues);
+ dumpLayoutVector(m_positioningLists.xValues);
fprintf(stderr, "\n");
fprintf(stderr, "y values: ");
- dumpLayoutVector(m_yValues);
+ dumpLayoutVector(m_positioningLists.yValues);
fprintf(stderr, "\n");
fprintf(stderr, "dx values: ");
- dumpLayoutVector(m_dxValues);
+ dumpLayoutVector(m_positioningLists.dxValues);
fprintf(stderr, "\n");
fprintf(stderr, "dy values: ");
- dumpLayoutVector(m_dyValues);
+ dumpLayoutVector(m_positioningLists.dyValues);
fprintf(stderr, "\n");
fprintf(stderr, "rotate values: ");
- dumpLayoutVector(m_rotateValues);
+ dumpLayoutVector(m_positioningLists.rotateValues);
fprintf(stderr, "\n");
fprintf(stderr, "character data values:\n");
diff --git a/Source/WebCore/rendering/svg/SVGTextLayoutAttributes.h b/Source/WebCore/rendering/svg/SVGTextLayoutAttributes.h
index fc6bd10..8b45d3d 100644
--- a/Source/WebCore/rendering/svg/SVGTextLayoutAttributes.h
+++ b/Source/WebCore/rendering/svg/SVGTextLayoutAttributes.h
@@ -31,6 +31,18 @@ class RenderSVGInlineText;
class SVGTextLayoutAttributes {
public:
+ struct PositioningLists {
+ void fillWithEmptyValues(unsigned length);
+ void appendEmptyValues();
+ void appendValuesFromPosition(const PositioningLists&, unsigned position);
+
+ Vector<float> xValues;
+ Vector<float> yValues;
+ Vector<float> dxValues;
+ Vector<float> dyValues;
+ Vector<float> rotateValues;
+ };
+
SVGTextLayoutAttributes(RenderSVGInlineText* context = 0);
void reserveCapacity(unsigned length);
@@ -40,31 +52,30 @@ public:
RenderSVGInlineText* context() const { return m_context; }
- Vector<float>& xValues() { return m_xValues; }
- const Vector<float>& xValues() const { return m_xValues; }
+ PositioningLists& positioningLists() { return m_positioningLists; }
+ const PositioningLists& positioningLists() const { return m_positioningLists; }
+
+ Vector<float>& xValues() { return m_positioningLists.xValues; }
+ const Vector<float>& xValues() const { return m_positioningLists.xValues; }
- Vector<float>& yValues() { return m_yValues; }
- const Vector<float>& yValues() const { return m_yValues; }
+ Vector<float>& yValues() { return m_positioningLists.yValues; }
+ const Vector<float>& yValues() const { return m_positioningLists.yValues; }
- Vector<float>& dxValues() { return m_dxValues; }
- const Vector<float>& dxValues() const { return m_dxValues; }
+ Vector<float>& dxValues() { return m_positioningLists.dxValues; }
+ const Vector<float>& dxValues() const { return m_positioningLists.dxValues; }
- Vector<float>& dyValues() { return m_dyValues; }
- const Vector<float>& dyValues() const { return m_dyValues; }
+ Vector<float>& dyValues() { return m_positioningLists.dyValues; }
+ const Vector<float>& dyValues() const { return m_positioningLists.dyValues; }
- Vector<float>& rotateValues() { return m_rotateValues; }
- const Vector<float>& rotateValues() const { return m_rotateValues; }
+ Vector<float>& rotateValues() { return m_positioningLists.rotateValues; }
+ const Vector<float>& rotateValues() const { return m_positioningLists.rotateValues; }
Vector<SVGTextMetrics>& textMetricsValues() { return m_textMetricsValues; }
const Vector<SVGTextMetrics>& textMetricsValues() const { return m_textMetricsValues; }
private:
RenderSVGInlineText* m_context;
- Vector<float> m_xValues;
- Vector<float> m_yValues;
- Vector<float> m_dxValues;
- Vector<float> m_dyValues;
- Vector<float> m_rotateValues;
+ PositioningLists m_positioningLists;
Vector<SVGTextMetrics> m_textMetricsValues;
};
diff --git a/Source/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.cpp b/Source/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.cpp
index 86be424..42eb8e8 100644
--- a/Source/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.cpp
+++ b/Source/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) Research In Motion Limited 2010. All rights reserved.
+ * Copyright (C) Research In Motion Limited 2010-2011. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -38,20 +38,19 @@ SVGTextLayoutAttributesBuilder::SVGTextLayoutAttributesBuilder()
void SVGTextLayoutAttributesBuilder::buildLayoutAttributesForTextSubtree(RenderSVGText* textRoot)
{
ASSERT(textRoot);
- m_scopes.clear();
// Build list of x/y/dx/dy/rotate values for each subtree element that may define these values (tspan/textPath etc).
unsigned atCharacter = 0;
UChar lastCharacter = '\0';
- buildLayoutScopes(textRoot, atCharacter, lastCharacter);
+ collectTextPositioningElements(textRoot, atCharacter, lastCharacter);
if (!atCharacter)
return;
- // Build list of x/y/dx/dy/rotate values for the outermost <text> element.
- buildOutermostLayoutScope(textRoot, atCharacter);
+ // Collect x/y/dx/dy/rotate values for each character, stored in the m_positioningLists.xValues()/etc. lists.
+ buildLayoutAttributesForAllCharacters(textRoot, atCharacter);
- // Propagate layout attributes to each RenderSVGInlineText object.
+ // Propagate layout attributes to each RenderSVGInlineText object, and the whole list to the RenderSVGText root.
Vector<SVGTextLayoutAttributes>& allAttributes = textRoot->layoutAttributes();
allAttributes.clear();
atCharacter = 0;
@@ -85,40 +84,6 @@ static inline void extractFloatValuesFromSVGNumberList(const SVGNumberList& list
floatValues.append(list.at(i));
}
-void SVGTextLayoutAttributesBuilder::buildLayoutScope(LayoutScope& scope, RenderObject* renderer, unsigned textContentStart, unsigned textContentLength) const
-{
- ASSERT(renderer);
- ASSERT(renderer->style());
-
- scope.textContentStart = textContentStart;
- scope.textContentLength = textContentLength;
-
- SVGTextPositioningElement* element = SVGTextPositioningElement::elementFromRenderer(renderer);
- if (!element)
- return;
-
- SVGTextLayoutAttributes& attributes = scope.attributes;
- extractFloatValuesFromSVGLengthList(element, element->x(), attributes.xValues(), textContentLength);
- extractFloatValuesFromSVGLengthList(element, element->y(), attributes.yValues(), textContentLength);
- extractFloatValuesFromSVGLengthList(element, element->dx(), attributes.dxValues(), textContentLength);
- extractFloatValuesFromSVGLengthList(element, element->dy(), attributes.dyValues(), textContentLength);
- extractFloatValuesFromSVGNumberList(element->rotate(), attributes.rotateValues(), textContentLength);
-
- // The last rotation value spans the whole scope.
- Vector<float>& rotateValues = attributes.rotateValues();
- if (rotateValues.isEmpty())
- return;
-
- unsigned rotateValuesSize = rotateValues.size();
- if (rotateValuesSize == textContentLength)
- return;
-
- float lastRotation = rotateValues.last();
-
- rotateValues.resize(textContentLength);
- for (unsigned i = rotateValuesSize; i < textContentLength; ++i)
- rotateValues.at(i) = lastRotation;
-}
static inline bool characterIsSpace(const UChar& character)
{
@@ -136,56 +101,84 @@ static inline bool shouldPreserveAllWhiteSpace(RenderStyle* style)
return style->whiteSpace() == PRE;
}
-void SVGTextLayoutAttributesBuilder::buildLayoutScopes(RenderObject* start, unsigned& atCharacter, UChar& lastCharacter)
+static inline void processRenderSVGInlineText(RenderSVGInlineText* text, unsigned& atCharacter, UChar& lastCharacter)
{
- for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) {
- if (child->isSVGInlineText()) {
- RenderSVGInlineText* text = toRenderSVGInlineText(child);
+ if (shouldPreserveAllWhiteSpace(text->style())) {
+ atCharacter += text->textLength();
+ return;
+ }
- if (!shouldPreserveAllWhiteSpace(text->style())) {
- const UChar* characters = text->characters();
- unsigned textLength = text->textLength();
- for (unsigned textPosition = 0; textPosition < textLength; ++textPosition) {
- const UChar& currentCharacter = characters[textPosition];
- if (characterIsSpace(currentCharacter) && characterIsSpaceOrNull(lastCharacter))
- continue;
+ const UChar* characters = text->characters();
+ unsigned textLength = text->textLength();
+ for (unsigned textPosition = 0; textPosition < textLength; ++textPosition) {
+ const UChar& currentCharacter = characters[textPosition];
+ if (characterIsSpace(currentCharacter) && characterIsSpaceOrNull(lastCharacter))
+ continue;
- lastCharacter = currentCharacter;
- ++atCharacter;
- }
- } else
- atCharacter += text->textLength();
+ lastCharacter = currentCharacter;
+ ++atCharacter;
+ }
+}
+
+void SVGTextLayoutAttributesBuilder::collectTextPositioningElements(RenderObject* start, unsigned& atCharacter, UChar& lastCharacter)
+{
+ ASSERT(!start->isSVGText() || m_textPositions.isEmpty());
+ for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) {
+ if (child->isSVGInlineText()) {
+ processRenderSVGInlineText(toRenderSVGInlineText(child), atCharacter, lastCharacter);
continue;
}
if (!child->isSVGInline())
continue;
- unsigned textContentStart = atCharacter;
- buildLayoutScopes(child, atCharacter, lastCharacter);
+ SVGTextPositioningElement* element = SVGTextPositioningElement::elementFromRenderer(child);
+ unsigned atPosition = m_textPositions.size();
+ if (element)
+ m_textPositions.append(TextPosition(element, atCharacter));
+
+ collectTextPositioningElements(child, atCharacter, lastCharacter);
+
+ if (!element)
+ continue;
- LayoutScope scope;
- buildLayoutScope(scope, child, textContentStart, atCharacter - textContentStart);
- m_scopes.append(scope);
+ // Update text position, after we're back from recursion.
+ TextPosition& position = m_textPositions[atPosition];
+ ASSERT(!position.length);
+ position.length = atCharacter - position.start;
}
}
-void SVGTextLayoutAttributesBuilder::buildOutermostLayoutScope(RenderSVGText* textRoot, unsigned textLength)
+void SVGTextLayoutAttributesBuilder::buildLayoutAttributesForAllCharacters(RenderSVGText* textRoot, unsigned textLength)
{
- LayoutScope scope;
- buildLayoutScope(scope, textRoot, 0, textLength);
+ ASSERT(textLength);
- // Handle <text> x/y default attributes.
- Vector<float>& xValues = scope.attributes.xValues();
- if (xValues.isEmpty())
- xValues.append(0);
+ SVGTextPositioningElement* outermostTextElement = SVGTextPositioningElement::elementFromRenderer(textRoot);
+ ASSERT(outermostTextElement);
- Vector<float>& yValues = scope.attributes.yValues();
- if (yValues.isEmpty())
- yValues.append(0);
+ // Fill the lists with the special emptyValue marker.
+ m_positioningLists.fillWithEmptyValues(textLength);
- m_scopes.prepend(scope);
+ // Grab outermost <text> element value lists and insert them in the m_positioningLists.
+ TextPosition wholeTextPosition(outermostTextElement, 0, textLength);
+ fillAttributesAtPosition(wholeTextPosition);
+
+ // Handle x/y default attributes.
+ float& xFirst = m_positioningLists.xValues.first();
+ if (xFirst == SVGTextLayoutAttributes::emptyValue())
+ xFirst = 0;
+
+ float& yFirst = m_positioningLists.yValues.first();
+ if (yFirst == SVGTextLayoutAttributes::emptyValue())
+ yFirst = 0;
+
+ // Fill m_positioningLists using child text positioning elements in top-down order.
+ unsigned size = m_textPositions.size();
+ for (unsigned i = 0; i < size; ++i)
+ fillAttributesAtPosition(m_textPositions[i]);
+
+ // Now m_positioningLists.contains a x/y/dx/dy/rotate value for each character in the <text> subtree.
}
void SVGTextLayoutAttributesBuilder::propagateLayoutAttributes(RenderObject* start, Vector<SVGTextLayoutAttributes>& allAttributes, unsigned& atCharacter, UChar& lastCharacter) const
@@ -222,16 +215,19 @@ void SVGTextLayoutAttributesBuilder::propagateLayoutAttributes(RenderObject* sta
metricsLength = currentMetrics.length();
if (!preserveWhiteSpace && characterIsSpace(currentCharacter) && characterIsSpaceOrNull(lastCharacter)) {
- assignEmptyLayoutAttributesForCharacter(attributes);
+ attributes.positioningLists().appendEmptyValues();
attributes.textMetricsValues().append(SVGTextMetrics::emptyMetrics());
continue;
}
- assignLayoutAttributesForCharacter(attributes, currentMetrics, valueListPosition);
+ SVGTextLayoutAttributes::PositioningLists& positioningLists = attributes.positioningLists();
+ positioningLists.appendValuesFromPosition(m_positioningLists, valueListPosition);
+ attributes.textMetricsValues().append(currentMetrics);
+ // Pad x/y/dx/dy/rotate value lists with empty values, if the metrics span more than one character.
if (metricsLength > 1) {
for (unsigned i = 0; i < metricsLength - 1; ++i)
- assignEmptyLayoutAttributesForCharacter(attributes);
+ positioningLists.appendEmptyValues();
}
lastCharacter = currentCharacter;
@@ -257,67 +253,42 @@ void SVGTextLayoutAttributesBuilder::propagateLayoutAttributes(RenderObject* sta
}
}
-float SVGTextLayoutAttributesBuilder::nextLayoutValue(LayoutValueType type, unsigned atCharacter) const
+static inline void fillListAtPosition(Vector<float>& allValues, Vector<float>& values, unsigned start)
{
- for (int i = m_scopes.size() - 1; i >= 0; --i) {
- const LayoutScope& scope = m_scopes.at(i);
- if (scope.textContentStart > atCharacter || scope.textContentStart + scope.textContentLength < atCharacter)
- continue;
+ unsigned valuesSize = values.size();
+ for (unsigned i = 0; i < valuesSize; ++i)
+ allValues[start + i] = values[i];
+}
- const Vector<float>* valuesPointer = 0;
- switch (type) {
- case XValueAttribute:
- valuesPointer = &scope.attributes.xValues();
- break;
- case YValueAttribute:
- valuesPointer = &scope.attributes.yValues();
- break;
- case DxValueAttribute:
- valuesPointer = &scope.attributes.dxValues();
- break;
- case DyValueAttribute:
- valuesPointer = &scope.attributes.dyValues();
- break;
- case RotateValueAttribute:
- valuesPointer = &scope.attributes.rotateValues();
- break;
- default:
- ASSERT_NOT_REACHED();
- }
+void SVGTextLayoutAttributesBuilder::fillAttributesAtPosition(const TextPosition& position)
+{
+ Vector<float> values;
+ extractFloatValuesFromSVGLengthList(position.element, position.element->x(), values, position.length);
+ fillListAtPosition(m_positioningLists.xValues, values, position.start);
- ASSERT(valuesPointer);
- const Vector<float>& values = *valuesPointer;
- if (values.isEmpty())
- continue;
+ values.clear();
+ extractFloatValuesFromSVGLengthList(position.element, position.element->y(), values, position.length);
+ fillListAtPosition(m_positioningLists.yValues, values, position.start);
- unsigned position = atCharacter - scope.textContentStart;
- if (position >= values.size())
- continue;
+ values.clear();
+ extractFloatValuesFromSVGLengthList(position.element, position.element->dx(), values, position.length);
+ fillListAtPosition(m_positioningLists.dxValues, values, position.start);
- return values.at(position);
- }
+ values.clear();
+ extractFloatValuesFromSVGLengthList(position.element, position.element->dy(), values, position.length);
+ fillListAtPosition(m_positioningLists.dyValues, values, position.start);
- return SVGTextLayoutAttributes::emptyValue();
-}
+ values.clear();
+ extractFloatValuesFromSVGNumberList(position.element->rotate(), values, position.length);
+ fillListAtPosition(m_positioningLists.rotateValues, values, position.start);
-void SVGTextLayoutAttributesBuilder::assignLayoutAttributesForCharacter(SVGTextLayoutAttributes& attributes, SVGTextMetrics& metrics, unsigned valueListPosition) const
-{
- attributes.xValues().append(nextLayoutValue(XValueAttribute, valueListPosition));
- attributes.yValues().append(nextLayoutValue(YValueAttribute, valueListPosition));
- attributes.dxValues().append(nextLayoutValue(DxValueAttribute, valueListPosition));
- attributes.dyValues().append(nextLayoutValue(DyValueAttribute, valueListPosition));
- attributes.rotateValues().append(nextLayoutValue(RotateValueAttribute, valueListPosition));
- attributes.textMetricsValues().append(metrics);
-}
+ // The last rotation value always spans the whole scope.
+ if (values.isEmpty())
+ return;
-void SVGTextLayoutAttributesBuilder::assignEmptyLayoutAttributesForCharacter(SVGTextLayoutAttributes& attributes) const
-{
- attributes.xValues().append(SVGTextLayoutAttributes::emptyValue());
- attributes.yValues().append(SVGTextLayoutAttributes::emptyValue());
- attributes.dxValues().append(SVGTextLayoutAttributes::emptyValue());
- attributes.dyValues().append(SVGTextLayoutAttributes::emptyValue());
- attributes.rotateValues().append(SVGTextLayoutAttributes::emptyValue());
- // This doesn't add an empty value to textMetricsValues() on purpose!
+ float lastValue = values.last();
+ for (unsigned i = values.size(); i < position.length; ++i)
+ m_positioningLists.rotateValues[position.start + i] = lastValue;
}
}
diff --git a/Source/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.h b/Source/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.h
index b368c51..a5995c0 100644
--- a/Source/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.h
+++ b/Source/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) Research In Motion Limited 2010. All rights reserved.
+ * Copyright (C) Research In Motion Limited 2010-2011. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -28,6 +28,7 @@ namespace WebCore {
class RenderObject;
class RenderSVGText;
+class SVGTextPositioningElement;
// SVGTextLayoutAttributesBuilder performs the first layout phase for SVG text.
//
@@ -45,37 +46,27 @@ public:
void buildLayoutAttributesForTextSubtree(RenderSVGText*);
private:
- struct LayoutScope {
- LayoutScope()
- : textContentStart(0)
- , textContentLength(0)
+ struct TextPosition {
+ TextPosition(SVGTextPositioningElement* newElement = 0, unsigned newStart = 0, unsigned newLength = 0)
+ : element(newElement)
+ , start(newStart)
+ , length(newLength)
{
}
- unsigned textContentStart;
- unsigned textContentLength;
- SVGTextLayoutAttributes attributes;
+ SVGTextPositioningElement* element;
+ unsigned start;
+ unsigned length;
};
- void buildLayoutScope(LayoutScope&, RenderObject*, unsigned textContentStart, unsigned textContentLength) const;
- void buildLayoutScopes(RenderObject*, unsigned& atCharacter, UChar& lastCharacter);
- void buildOutermostLayoutScope(RenderSVGText*, unsigned textLength);
+ void collectTextPositioningElements(RenderObject*, unsigned& atCharacter, UChar& lastCharacter);
+ void buildLayoutAttributesForAllCharacters(RenderSVGText*, unsigned textLength);
void propagateLayoutAttributes(RenderObject*, Vector<SVGTextLayoutAttributes>& allAttributes, unsigned& atCharacter, UChar& lastCharacter) const;
-
- enum LayoutValueType {
- XValueAttribute,
- YValueAttribute,
- DxValueAttribute,
- DyValueAttribute,
- RotateValueAttribute
- };
-
- float nextLayoutValue(LayoutValueType, unsigned atCharacter) const;
- void assignLayoutAttributesForCharacter(SVGTextLayoutAttributes&, SVGTextMetrics&, unsigned valueListPosition) const;
- void assignEmptyLayoutAttributesForCharacter(SVGTextLayoutAttributes&) const;
+ void fillAttributesAtPosition(const TextPosition&);
private:
- Vector<LayoutScope> m_scopes;
+ Vector<TextPosition> m_textPositions;
+ SVGTextLayoutAttributes::PositioningLists m_positioningLists;
};
} // namespace WebCore
diff --git a/Source/WebCore/rendering/svg/SVGTextLayoutEngine.cpp b/Source/WebCore/rendering/svg/SVGTextLayoutEngine.cpp
index 71db2ea..2bc7e32 100644
--- a/Source/WebCore/rendering/svg/SVGTextLayoutEngine.cpp
+++ b/Source/WebCore/rendering/svg/SVGTextLayoutEngine.cpp
@@ -157,7 +157,7 @@ bool SVGTextLayoutEngine::parentDefinesTextLength(RenderObject* parent) const
SVGTextContentElement* textContentElement = SVGTextContentElement::elementFromRenderer(currentParent);
if (textContentElement) {
SVGTextContentElement::SVGLengthAdjustType lengthAdjust = static_cast<SVGTextContentElement::SVGLengthAdjustType>(textContentElement->lengthAdjust());
- if (lengthAdjust == SVGTextContentElement::LENGTHADJUST_SPACING && textContentElement->textLength().value(textContentElement) > 0)
+ if (lengthAdjust == SVGTextContentElement::LENGTHADJUST_SPACING && textContentElement->specifiedTextLength().value(textContentElement) > 0)
return true;
}
@@ -213,7 +213,7 @@ void SVGTextLayoutEngine::beginTextPathLayout(RenderObject* object, SVGTextLayou
if (SVGTextContentElement* textContentElement = SVGTextContentElement::elementFromRenderer(textPath)) {
lengthAdjust = static_cast<SVGTextContentElement::SVGLengthAdjustType>(textContentElement->lengthAdjust());
- desiredTextLength = textContentElement->textLength().value(textContentElement);
+ desiredTextLength = textContentElement->specifiedTextLength().value(textContentElement);
}
if (!desiredTextLength)
@@ -261,34 +261,10 @@ void SVGTextLayoutEngine::layoutInlineTextBox(SVGInlineTextBox* textBox)
m_lineLayoutBoxes.append(textBox);
}
-void SVGTextLayoutEngine::finishLayout()
-{
- // After all text fragments are stored in their correpsonding SVGInlineTextBoxes, we can layout individual text chunks.
- // Chunk layouting is only performed for line layout boxes, not for path layout, where it has already been done.
- m_chunkLayoutBuilder.layoutTextChunks(m_lineLayoutBoxes);
-
- // Finalize transform matrices, after the chunk layout corrections have been applied, and all fragment x/y positions are finalized.
- if (!m_lineLayoutBoxes.isEmpty()) {
-#if DUMP_TEXT_FRAGMENTS > 0
- fprintf(stderr, "Line layout: ");
-#endif
-
- finalizeTransformMatrices(m_lineLayoutBoxes);
- }
-
- if (!m_pathLayoutBoxes.isEmpty()) {
#if DUMP_TEXT_FRAGMENTS > 0
- fprintf(stderr, "Path layout: ");
-#endif
- finalizeTransformMatrices(m_pathLayoutBoxes);
- }
-}
-
-void SVGTextLayoutEngine::finalizeTransformMatrices(Vector<SVGInlineTextBox*>& boxes)
+static inline void dumpTextBoxes(Vector<SVGInlineTextBox*>& boxes)
{
unsigned boxCount = boxes.size();
-
-#if DUMP_TEXT_FRAGMENTS > 0
fprintf(stderr, "Dumping all text fragments in text sub tree, %i boxes\n", boxCount);
for (unsigned boxPosition = 0; boxPosition < boxCount; ++boxPosition) {
@@ -308,9 +284,12 @@ void SVGTextLayoutEngine::finalizeTransformMatrices(Vector<SVGInlineTextBox*>& b
, i, fragment.x, fragment.y, fragment.width, fragment.height, fragment.characterOffset, fragment.length, fragmentString.utf8().data());
}
}
+}
#endif
-
+void SVGTextLayoutEngine::finalizeTransformMatrices(Vector<SVGInlineTextBox*>& boxes)
+{
+ unsigned boxCount = boxes.size();
if (!boxCount)
return;
@@ -321,29 +300,48 @@ void SVGTextLayoutEngine::finalizeTransformMatrices(Vector<SVGInlineTextBox*>& b
unsigned fragmentCount = fragments.size();
for (unsigned i = 0; i < fragmentCount; ++i) {
- SVGTextFragment& fragment = fragments.at(i);
- AffineTransform& transform = fragment.transform;
- if (!transform.isIdentity()) {
- transform = AffineTransform::translation(fragment.x, fragment.y) * transform;
- transform.translate(-fragment.x, -fragment.y);
- }
-
m_chunkLayoutBuilder.transformationForTextBox(textBox, textBoxTransformation);
if (textBoxTransformation.isIdentity())
continue;
-
- if (transform.isIdentity())
- transform = textBoxTransformation;
- else
- transform = textBoxTransformation * transform;
+ ASSERT(fragments[i].lengthAdjustTransform.isIdentity());
+ fragments[i].lengthAdjustTransform = textBoxTransformation;
}
}
boxes.clear();
}
+void SVGTextLayoutEngine::finishLayout()
+{
+ // After all text fragments are stored in their correpsonding SVGInlineTextBoxes, we can layout individual text chunks.
+ // Chunk layouting is only performed for line layout boxes, not for path layout, where it has already been done.
+ m_chunkLayoutBuilder.layoutTextChunks(m_lineLayoutBoxes);
+
+ // Finalize transform matrices, after the chunk layout corrections have been applied, and all fragment x/y positions are finalized.
+ if (!m_lineLayoutBoxes.isEmpty()) {
+#if DUMP_TEXT_FRAGMENTS > 0
+ fprintf(stderr, "Line layout: ");
+ dumpTextBoxes(m_lineLayoutBoxes);
+#endif
+
+ finalizeTransformMatrices(m_lineLayoutBoxes);
+ }
+
+ if (!m_pathLayoutBoxes.isEmpty()) {
+#if DUMP_TEXT_FRAGMENTS > 0
+ fprintf(stderr, "Path layout: ");
+ dumpTextBoxes(m_pathLayoutBoxes);
+#endif
+
+ finalizeTransformMatrices(m_pathLayoutBoxes);
+ }
+}
+
bool SVGTextLayoutEngine::currentLogicalCharacterAttributes(SVGTextLayoutAttributes& logicalAttributes)
{
+ if (m_layoutAttributes.isEmpty())
+ return false;
+
logicalAttributes = m_layoutAttributes.first();
if (m_logicalCharacterOffset != logicalAttributes.xValues().size())
return true;
@@ -374,6 +372,8 @@ bool SVGTextLayoutEngine::currentLogicalCharacterMetrics(SVGTextLayoutAttributes
continue;
}
+ ASSERT(textMetricsSize);
+ ASSERT(m_logicalMetricsListOffset < textMetricsSize);
logicalMetrics = textMetricsValues.at(m_logicalMetricsListOffset);
if (logicalMetrics == SVGTextMetrics::emptyMetrics() || (!logicalMetrics.width() && !logicalMetrics.height())) {
advanceToNextLogicalCharacter(logicalMetrics);
@@ -634,11 +634,12 @@ void SVGTextLayoutEngine::layoutTextOnLineOrPath(SVGInlineTextBox* textBox, Rend
if (orientationAngle)
m_currentTextFragment.transform.rotate(orientationAngle);
- if (m_inPathLayout && m_textPathScaling != 1) {
+ m_currentTextFragment.isTextOnPath = m_inPathLayout && m_textPathScaling != 1;
+ if (m_currentTextFragment.isTextOnPath) {
if (m_isVerticalText)
- m_currentTextFragment.transform.scaleNonUniform(1, m_textPathScaling);
+ m_currentTextFragment.lengthAdjustTransform.scaleNonUniform(1, m_textPathScaling);
else
- m_currentTextFragment.transform.scaleNonUniform(m_textPathScaling, 1);
+ m_currentTextFragment.lengthAdjustTransform.scaleNonUniform(m_textPathScaling, 1);
}
}
diff --git a/Source/WebCore/rendering/svg/SVGTextQuery.cpp b/Source/WebCore/rendering/svg/SVGTextQuery.cpp
index 5f3523e..c141c11 100644
--- a/Source/WebCore/rendering/svg/SVGTextQuery.cpp
+++ b/Source/WebCore/rendering/svg/SVGTextQuery.cpp
@@ -80,17 +80,6 @@ static inline InlineFlowBox* flowBoxForRenderer(RenderObject* renderer)
return 0;
}
-static inline float mapLengthThroughFragmentTransformation(const SVGTextFragment& fragment, bool isVerticalText, float length)
-{
- if (fragment.transform.isIdentity())
- return length;
-
- if (isVerticalText)
- return narrowPrecisionToFloat(static_cast<double>(length) * fragment.transform.yScale());
-
- return narrowPrecisionToFloat(static_cast<double>(length) * fragment.transform.xScale());
-}
-
SVGTextQuery::SVGTextQuery(RenderObject* renderer)
{
collectTextBoxesInFlowBox(flowBoxForRenderer(renderer));
@@ -111,8 +100,8 @@ void SVGTextQuery::collectTextBoxesInFlowBox(InlineFlowBox* flowBox)
continue;
}
- ASSERT(child->isSVGInlineTextBox());
- m_textBoxes.append(static_cast<SVGInlineTextBox*>(child));
+ if (child->isSVGInlineTextBox())
+ m_textBoxes.append(static_cast<SVGInlineTextBox*>(child));
}
}
@@ -273,9 +262,7 @@ struct TextLengthData : SVGTextQuery::Data {
bool SVGTextQuery::textLengthCallback(Data* queryData, const SVGTextFragment& fragment) const
{
TextLengthData* data = static_cast<TextLengthData*>(queryData);
-
- float fragmentLength = queryData->isVerticalText ? fragment.height : fragment.width;
- data->textLength += mapLengthThroughFragmentTransformation(fragment, queryData->isVerticalText, fragmentLength);
+ data->textLength += queryData->isVerticalText ? fragment.height : fragment.width;
return false;
}
@@ -314,9 +301,7 @@ bool SVGTextQuery::subStringLengthCallback(Data* queryData, const SVGTextFragmen
return false;
SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(queryData->textRenderer, fragment.characterOffset + startPosition, endPosition - startPosition);
- float fragmentLength = queryData->isVerticalText ? metrics.height() : metrics.width();
-
- data->subStringLength += mapLengthThroughFragmentTransformation(fragment, queryData->isVerticalText, fragmentLength);
+ data->subStringLength += queryData->isVerticalText ? metrics.height() : metrics.width();
return false;
}
@@ -360,10 +345,12 @@ bool SVGTextQuery::startPositionOfCharacterCallback(Data* queryData, const SVGTe
data->startPosition.move(metrics.width(), 0);
}
- if (fragment.transform.isIdentity())
+ AffineTransform fragmentTransform;
+ fragment.buildFragmentTransform(fragmentTransform, SVGTextFragment::TransformIgnoringTextLength);
+ if (fragmentTransform.isIdentity())
return true;
- data->startPosition = fragment.transform.mapPoint(data->startPosition);
+ data->startPosition = fragmentTransform.mapPoint(data->startPosition);
return true;
}
@@ -405,10 +392,12 @@ bool SVGTextQuery::endPositionOfCharacterCallback(Data* queryData, const SVGText
else
data->endPosition.move(metrics.width(), 0);
- if (fragment.transform.isIdentity())
+ AffineTransform fragmentTransform;
+ fragment.buildFragmentTransform(fragmentTransform, SVGTextFragment::TransformIgnoringTextLength);
+ if (fragmentTransform.isIdentity())
return true;
- data->endPosition = fragment.transform.mapPoint(data->endPosition);
+ data->endPosition = fragmentTransform.mapPoint(data->endPosition);
return true;
}
@@ -443,9 +432,15 @@ bool SVGTextQuery::rotationOfCharacterCallback(Data* queryData, const SVGTextFra
if (!mapStartEndPositionsIntoFragmentCoordinates(queryData, fragment, startPosition, endPosition))
return false;
- AffineTransform newTransform(fragment.transform);
- newTransform.scale(1 / fragment.transform.xScale(), 1 / fragment.transform.yScale());
- data->rotation = narrowPrecisionToFloat(rad2deg(atan2(newTransform.b(), newTransform.a())));
+ AffineTransform fragmentTransform;
+ fragment.buildFragmentTransform(fragmentTransform, SVGTextFragment::TransformIgnoringTextLength);
+ if (fragmentTransform.isIdentity())
+ data->rotation = 0;
+ else {
+ fragmentTransform.scale(1 / fragmentTransform.xScale(), 1 / fragmentTransform.yScale());
+ data->rotation = narrowPrecisionToFloat(rad2deg(atan2(fragmentTransform.b(), fragmentTransform.a())));
+ }
+
return true;
}
@@ -488,10 +483,12 @@ static inline void calculateGlyphBoundaries(SVGTextQuery::Data* queryData, const
SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(queryData->textRenderer, fragment.characterOffset + startPosition, 1);
extent.setSize(FloatSize(metrics.width(), metrics.height()));
- if (fragment.transform.isIdentity())
+ AffineTransform fragmentTransform;
+ fragment.buildFragmentTransform(fragmentTransform, SVGTextFragment::TransformIgnoringTextLength);
+ if (fragmentTransform.isIdentity())
return;
- extent = fragment.transform.mapRect(extent);
+ extent = fragmentTransform.mapRect(extent);
}
bool SVGTextQuery::extentOfCharacterCallback(Data* queryData, const SVGTextFragment& fragment) const