diff options
author | Ben Murdoch <benm@google.com> | 2011-06-02 12:07:03 +0100 |
---|---|---|
committer | Ben Murdoch <benm@google.com> | 2011-06-10 10:47:21 +0100 |
commit | 2daae5fd11344eaa88a0d92b0f6d65f8d2255c00 (patch) | |
tree | e4964fbd1cb70599f7718ff03e50ea1dab33890b /Source/WebCore/rendering/svg | |
parent | 87bdf0060a247bfbe668342b87e0874182e0ffa9 (diff) | |
download | external_webkit-2daae5fd11344eaa88a0d92b0f6d65f8d2255c00.zip external_webkit-2daae5fd11344eaa88a0d92b0f6d65f8d2255c00.tar.gz external_webkit-2daae5fd11344eaa88a0d92b0f6d65f8d2255c00.tar.bz2 |
Merge WebKit at r84325: Initial merge by git.
Change-Id: Ic1a909300ecc0a13ddc6b4e784371d2ac6e3d59b
Diffstat (limited to 'Source/WebCore/rendering/svg')
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 |