diff options
author | Jocelyn Turcotte <jocelyn.turcotte@digia.com> | 2014-08-08 14:30:41 +0200 |
---|---|---|
committer | Jocelyn Turcotte <jocelyn.turcotte@digia.com> | 2014-08-12 13:49:54 +0200 |
commit | ab0a50979b9eb4dfa3320eff7e187e41efedf7a9 (patch) | |
tree | 498dfb8a97ff3361a9f7486863a52bb4e26bb898 /chromium/third_party/WebKit/Source/core/rendering/svg | |
parent | 4ce69f7403811819800e7c5ae1318b2647e778d1 (diff) |
Update Chromium to beta version 37.0.2062.68
Change-Id: I188e3b5aff1bec75566014291b654eb19f5bc8ca
Reviewed-by: Andras Becsi <andras.becsi@digia.com>
Diffstat (limited to 'chromium/third_party/WebKit/Source/core/rendering/svg')
95 files changed, 2171 insertions, 2025 deletions
diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/ReferenceFilterBuilder.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/ReferenceFilterBuilder.cpp index 8c0a5c517a4..a53a3dcf118 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/ReferenceFilterBuilder.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/ReferenceFilterBuilder.cpp @@ -29,9 +29,9 @@ #include "core/rendering/svg/ReferenceFilterBuilder.h" -#include "SVGNames.h" #include "core/css/CSSPrimitiveValue.h" #include "core/css/CSSPrimitiveValueMappings.h" +#include "core/css/StylePropertySet.h" #include "core/dom/Element.h" #include "core/fetch/DocumentResource.h" #include "core/rendering/svg/RenderSVGResourceFilter.h" @@ -80,10 +80,11 @@ static bool getSVGElementColorSpace(SVGElement* svgElement, ColorSpace& cs) if (svgStyle) { // If a layout has been performed, then we can use the fast path to get this attribute eColorInterpolation = svgStyle->colorInterpolationFilters(); + } else if (!svgElement->presentationAttributeStyle()) { + return false; } else { // Otherwise, use the slow path by using string comparison (used by external svg files) - RefPtr<CSSValue> cssValue = svgElement->getPresentationAttribute( - SVGNames::color_interpolation_filtersAttr.toString()); + RefPtrWillBeRawPtr<CSSValue> cssValue = svgElement->presentationAttributeStyle()->getPropertyCSSValue(CSSPropertyColorInterpolationFilters); if (cssValue.get() && cssValue->isPrimitiveValue()) { const CSSPrimitiveValue& primitiveValue = *((CSSPrimitiveValue*)cssValue.get()); eColorInterpolation = (EColorInterpolation)primitiveValue; @@ -110,9 +111,9 @@ static bool getSVGElementColorSpace(SVGElement* svgElement, ColorSpace& cs) PassRefPtr<FilterEffect> ReferenceFilterBuilder::build(Filter* parentFilter, RenderObject* renderer, FilterEffect* previousEffect, const ReferenceFilterOperation* filterOperation) { if (!renderer) - return 0; + return nullptr; - Document* document = &renderer->document(); + TreeScope* treeScope = &renderer->node()->treeScope(); if (DocumentResourceReference* documentResourceRef = documentResourceReference(filterOperation)) { DocumentResource* cachedSVGDocument = documentResourceRef->document(); @@ -120,25 +121,25 @@ PassRefPtr<FilterEffect> ReferenceFilterBuilder::build(Filter* parentFilter, Ren // If we have an SVG document, this is an external reference. Otherwise // we look up the referenced node in the current document. if (cachedSVGDocument) - document = cachedSVGDocument->document(); + treeScope = cachedSVGDocument->document(); } - if (!document) - return 0; + if (!treeScope) + return nullptr; - Element* filter = document->getElementById(filterOperation->fragment()); + Element* filter = treeScope->getElementById(filterOperation->fragment()); if (!filter) { // Although we did not find the referenced filter, it might exist later - // in the document - document->accessSVGExtensions()->addPendingResource(filterOperation->fragment(), toElement(renderer->node())); - return 0; + // in the document. + treeScope->document().accessSVGExtensions().addPendingResource(filterOperation->fragment(), toElement(renderer->node())); + return nullptr; } - if (!filter->isSVGElement() || !filter->hasTagName(SVGNames::filterTag)) - return 0; + if (!isSVGFilterElement(*filter)) + return nullptr; - SVGFilterElement* filterElement = toSVGFilterElement(toSVGElement(filter)); + SVGFilterElement& filterElement = toSVGFilterElement(*filter); // FIXME: Figure out what to do with SourceAlpha. Right now, we're // using the alpha of the original input layer, which is obviously @@ -148,13 +149,9 @@ PassRefPtr<FilterEffect> ReferenceFilterBuilder::build(Filter* parentFilter, Ren RefPtr<SVGFilterBuilder> builder = SVGFilterBuilder::create(previousEffect, SourceAlpha::create(parentFilter)); ColorSpace filterColorSpace = ColorSpaceDeviceRGB; - bool useFilterColorSpace = getSVGElementColorSpace(filterElement, filterColorSpace); - - for (Node* node = filterElement->firstChild(); node; node = node->nextSibling()) { - if (!node->isSVGElement()) - continue; + bool useFilterColorSpace = getSVGElementColorSpace(&filterElement, filterColorSpace); - SVGElement* element = toSVGElement(node); + for (SVGElement* element = Traversal<SVGElement>::firstChild(filterElement); element; element = Traversal<SVGElement>::nextSibling(*element)) { if (!element->isFilterEffect()) continue; @@ -165,11 +162,11 @@ PassRefPtr<FilterEffect> ReferenceFilterBuilder::build(Filter* parentFilter, Ren continue; effectElement->setStandardAttributes(effect.get()); - effect->setEffectBoundaries(SVGLengthContext::resolveRectangle<SVGFilterPrimitiveStandardAttributes>(effectElement, filterElement->primitiveUnitsCurrentValue(), parentFilter->sourceImageRect())); + effect->setEffectBoundaries(SVGLengthContext::resolveRectangle<SVGFilterPrimitiveStandardAttributes>(effectElement, filterElement.primitiveUnits()->currentValue()->enumValue(), parentFilter->sourceImageRect())); ColorSpace colorSpace = filterColorSpace; if (useFilterColorSpace || getSVGElementColorSpace(effectElement, colorSpace)) effect->setOperatingColorSpace(colorSpace); - builder->add(effectElement->resultCurrentValue(), effect); + builder->add(AtomicString(effectElement->result()->currentValue()->value()), effect); } return builder->lastEffect(); } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGBlock.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGBlock.cpp index ab40394a4b3..8eddc1f1e6f 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGBlock.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGBlock.cpp @@ -23,7 +23,9 @@ #include "core/rendering/svg/RenderSVGBlock.h" +#include "core/rendering/RenderView.h" #include "core/rendering/style/ShadowList.h" +#include "core/rendering/svg/SVGRenderSupport.h" #include "core/rendering/svg/SVGResourcesCache.h" #include "core/svg/SVGElement.h" @@ -50,7 +52,7 @@ void RenderSVGBlock::updateFromStyle() // RenderSVGlock, used by Render(SVGText|ForeignObject), is not allowed to call setHasOverflowClip(true). // RenderBlock assumes a layer to be present when the overflow clip functionality is requested. Both - // Render(SVGText|ForeignObject) return 'false' on 'requiresLayer'. Fine for RenderSVGText. + // Render(SVGText|ForeignObject) return 'NoLayer' on 'layerTypeRequired'. Fine for RenderSVGText. // // If we want to support overflow rules for <foreignObject> we can choose between two solutions: // a) make RenderSVGForeignObject require layers and SVG layer aware @@ -77,11 +79,46 @@ void RenderSVGBlock::willBeDestroyed() void RenderSVGBlock::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { - if (diff == StyleDifferenceLayout) + if (diff.needsFullLayout()) setNeedsBoundariesUpdate(); RenderBlock::styleDidChange(diff, oldStyle); SVGResourcesCache::clientStyleChanged(this, diff, style()); } +void RenderSVGBlock::mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState& transformState, MapCoordinatesFlags, bool* wasFixed) const +{ + SVGRenderSupport::mapLocalToContainer(this, repaintContainer, transformState, wasFixed); +} + +const RenderObject* RenderSVGBlock::pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap& geometryMap) const +{ + return SVGRenderSupport::pushMappingToContainer(this, ancestorToStopAt, geometryMap); +} + +LayoutRect RenderSVGBlock::clippedOverflowRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer) const +{ + return SVGRenderSupport::clippedOverflowRectForRepaint(this, paintInvalidationContainer); +} + +void RenderSVGBlock::computeFloatRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer, FloatRect& paintInvalidationRect, bool fixed) const +{ + SVGRenderSupport::computeFloatRectForRepaint(this, paintInvalidationContainer, paintInvalidationRect, fixed); +} + +bool RenderSVGBlock::nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation&, const LayoutPoint&, HitTestAction) +{ + ASSERT_NOT_REACHED(); + return false; +} + +void RenderSVGBlock::invalidateTreeAfterLayout(const RenderLayerModelObject& paintInvalidationContainer) +{ + if (!shouldCheckForPaintInvalidationAfterLayout()) + return; + + ForceHorriblySlowRectMapping slowRectMapping(*this); + RenderBlockFlow::invalidateTreeAfterLayout(paintInvalidationContainer); +} + } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGBlock.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGBlock.h index 6f08eb1f72f..1e21c7c639a 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGBlock.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGBlock.h @@ -32,19 +32,33 @@ public: virtual LayoutRect visualOverflowRect() const OVERRIDE FINAL; + virtual LayoutRect clippedOverflowRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer) const OVERRIDE FINAL; + virtual void computeFloatRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer, FloatRect&, bool fixed = false) const OVERRIDE FINAL; + + virtual void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = 0) const OVERRIDE FINAL; + virtual const RenderObject* pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap&) const OVERRIDE FINAL; + + virtual AffineTransform localTransform() const OVERRIDE FINAL { return m_localTransform; } + + virtual LayerType layerTypeRequired() const OVERRIDE FINAL { return NoLayer; } + + virtual void invalidateTreeAfterLayout(const RenderLayerModelObject&) OVERRIDE; + protected: virtual void willBeDestroyed() OVERRIDE; + AffineTransform m_localTransform; + private: virtual void updateFromStyle() OVERRIDE FINAL; - virtual bool isRenderSVGBlock() const OVERRIDE FINAL { return true; }; - - virtual bool supportsPartialLayout() const OVERRIDE { return false; } + virtual bool isSVG() const OVERRIDE FINAL { return true; } virtual void absoluteRects(Vector<IntRect>&, const LayoutPoint& accumulatedOffset) const OVERRIDE FINAL; virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) OVERRIDE FINAL; + + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; }; } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGContainer.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGContainer.cpp index 04f28cae872..5767807922e 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGContainer.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGContainer.cpp @@ -25,13 +25,15 @@ #include "core/rendering/svg/RenderSVGContainer.h" +#include "core/frame/Settings.h" #include "core/rendering/GraphicsContextAnnotator.h" -#include "core/rendering/LayoutRectRecorder.h" #include "core/rendering/LayoutRepainter.h" #include "core/rendering/RenderView.h" +#include "core/rendering/svg/SVGRenderSupport.h" #include "core/rendering/svg/SVGRenderingContext.h" #include "core/rendering/svg/SVGResources.h" #include "core/rendering/svg/SVGResourcesCache.h" +#include "platform/graphics/GraphicsContextCullSaver.h" #include "platform/graphics/GraphicsContextStateSaver.h" namespace WebCore { @@ -52,9 +54,8 @@ void RenderSVGContainer::layout() ASSERT(needsLayout()); // RenderSVGRoot disables layoutState for the SVG rendering tree. - ASSERT(!view()->layoutStateEnabled()); + ASSERT(!view()->layoutStateCachedOffsetsEnabled()); - LayoutRectRecorder recorder(*this); LayoutRepainter repainter(*this, SVGRenderSupport::checkForSVGRepaintDuringLayout(this) || selfWillPaint()); // Allow RenderSVGViewportContainer to update its viewport. @@ -116,7 +117,7 @@ void RenderSVGContainer::paint(PaintInfo& paintInfo, const LayoutPoint&) if (!firstChild() && !selfWillPaint()) return; - FloatRect repaintRect = repaintRectInLocalCoordinates(); + FloatRect repaintRect = paintInvalidationRectInLocalCoordinates(); if (!SVGRenderSupport::paintInfoIntersectsRepaintRect(repaintRect, localToParentTransform(), paintInfo)) return; @@ -130,10 +131,14 @@ void RenderSVGContainer::paint(PaintInfo& paintInfo, const LayoutPoint&) childPaintInfo.applyTransform(localToParentTransform()); SVGRenderingContext renderingContext; + GraphicsContextCullSaver cullSaver(*childPaintInfo.context); bool continueRendering = true; if (childPaintInfo.phase == PaintPhaseForeground) { renderingContext.prepareToRenderSVGContent(this, childPaintInfo); continueRendering = renderingContext.isRenderingPrepared(); + + if (continueRendering && document().settings()->containerCullingEnabled()) + cullSaver.cull(paintInvalidationRectInLocalCoordinates()); } if (continueRendering) { @@ -144,11 +149,11 @@ void RenderSVGContainer::paint(PaintInfo& paintInfo, const LayoutPoint&) } // FIXME: This really should be drawn from local coordinates, but currently we hack it - // to avoid our clip killing our outline rect. Thus we translate our + // to avoid our clip killing our outline rect. Thus we translate our // outline rect into parent coords before drawing. // FIXME: This means our focus ring won't share our rotation like it should. // We should instead disable our clip during PaintPhaseOutline - if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && style()->outlineWidth() && style()->visibility() == VISIBLE) { + if (paintInfo.phase == PaintPhaseForeground && style()->outlineWidth() && style()->visibility() == VISIBLE) { IntRect paintRectInParent = enclosingIntRect(localToParentTransform().mapRect(repaintRect)); paintOutline(paintInfo, paintRectInParent); } @@ -157,7 +162,7 @@ void RenderSVGContainer::paint(PaintInfo& paintInfo, const LayoutPoint&) // addFocusRingRects is called from paintOutline and needs to be in the same coordinates as the paintOuline call void RenderSVGContainer::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint&, const RenderLayerModelObject*) { - IntRect paintRectInParent = enclosingIntRect(localToParentTransform().mapRect(repaintRectInLocalCoordinates())); + IntRect paintRectInParent = enclosingIntRect(localToParentTransform().mapRect(paintInvalidationRectInLocalCoordinates())); if (!paintRectInParent.isEmpty()) rects.append(paintRectInParent); } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGContainer.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGContainer.h index fd4e74db96b..b7235fbaded 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGContainer.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGContainer.h @@ -37,12 +37,15 @@ public: RenderObject* firstChild() const { ASSERT(children() == virtualChildren()); return children()->firstChild(); } RenderObject* lastChild() const { ASSERT(children() == virtualChildren()); return children()->lastChild(); } + // If you have a RenderSVGContainer, use firstChild or lastChild instead. + void slowFirstChild() const WTF_DELETED_FUNCTION; + void slowLastChild() const WTF_DELETED_FUNCTION; + const RenderObjectChildList* children() const { return &m_children; } RenderObjectChildList* children() { return &m_children; } - virtual void paint(PaintInfo&, const LayoutPoint&); + virtual void paint(PaintInfo&, const LayoutPoint&) OVERRIDE; virtual void setNeedsBoundariesUpdate() OVERRIDE FINAL { m_needsBoundariesUpdate = true; } - virtual bool needsBoundariesUpdate() OVERRIDE FINAL { return m_needsBoundariesUpdate; } virtual bool didTransformToRootUpdate() { return false; } bool isObjectBoundingBoxValid() const { return m_objectBoundingBoxValid; } @@ -51,9 +54,9 @@ protected: virtual const RenderObjectChildList* virtualChildren() const OVERRIDE FINAL { return children(); } virtual bool isSVGContainer() const OVERRIDE FINAL { return true; } - virtual const char* renderName() const { return "RenderSVGContainer"; } + virtual const char* renderName() const OVERRIDE { return "RenderSVGContainer"; } - virtual void layout(); + virtual void layout() OVERRIDE; virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0) OVERRIDE FINAL; virtual void removeChild(RenderObject*) OVERRIDE FINAL; @@ -61,9 +64,9 @@ protected: virtual FloatRect objectBoundingBox() const OVERRIDE FINAL { return m_objectBoundingBox; } virtual FloatRect strokeBoundingBox() const OVERRIDE FINAL { return m_strokeBoundingBox; } - virtual FloatRect repaintRectInLocalCoordinates() const OVERRIDE FINAL { return m_repaintBoundingBox; } + virtual FloatRect paintInvalidationRectInLocalCoordinates() const OVERRIDE FINAL { return m_repaintBoundingBox; } - virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction); + virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction) OVERRIDE; // Allow RenderSVGTransformableContainer to hook in at the right time in layout() virtual bool calculateLocalTransform() { return false; } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGEllipse.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGEllipse.cpp index ac5c6491fc3..b9a75029ae0 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGEllipse.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGEllipse.cpp @@ -28,9 +28,9 @@ #include "core/rendering/svg/RenderSVGEllipse.h" -#include "SVGNames.h" #include "core/svg/SVGCircleElement.h" #include "core/svg/SVGEllipseElement.h" +#include "platform/graphics/GraphicsContext.h" namespace WebCore { @@ -53,20 +53,22 @@ void RenderSVGEllipse::updateShapeFromElement() m_center = FloatPoint(); m_radii = FloatSize(); - // Fallback to RenderSVGShape if shape has a non-scaling stroke. - if (hasNonScalingStroke()) { - RenderSVGShape::updateShapeFromElement(); - m_usePathFallback = true; - return; - } else - m_usePathFallback = false; - calculateRadiiAndCenter(); - // Spec: "A value of zero disables rendering of the element." - if (m_radii.width() <= 0 || m_radii.height() <= 0) + // Spec: "A negative value is an error. A value of zero disables rendering of the element." + if (m_radii.width() < 0 || m_radii.height() < 0) return; + if (!m_radii.isEmpty()) { + // Fallback to RenderSVGShape if shape has a non-scaling stroke. + if (hasNonScalingStroke()) { + RenderSVGShape::updateShapeFromElement(); + m_usePathFallback = true; + return; + } + m_usePathFallback = false; + } + m_fillBoundingBox = FloatRect(m_center.x() - m_radii.width(), m_center.y() - m_radii.height(), 2 * m_radii.width(), 2 * m_radii.height()); m_strokeBoundingBox = m_fillBoundingBox; if (style()->svgStyle()->hasStroke()) @@ -76,21 +78,21 @@ void RenderSVGEllipse::updateShapeFromElement() void RenderSVGEllipse::calculateRadiiAndCenter() { ASSERT(element()); - if (element()->hasTagName(SVGNames::circleTag)) { - SVGCircleElement* circle = toSVGCircleElement(element()); + if (isSVGCircleElement(*element())) { + SVGCircleElement& circle = toSVGCircleElement(*element()); - SVGLengthContext lengthContext(circle); - float radius = circle->rCurrentValue().value(lengthContext); + SVGLengthContext lengthContext(&circle); + float radius = circle.r()->currentValue()->value(lengthContext); m_radii = FloatSize(radius, radius); - m_center = FloatPoint(circle->cxCurrentValue().value(lengthContext), circle->cyCurrentValue().value(lengthContext)); + m_center = FloatPoint(circle.cx()->currentValue()->value(lengthContext), circle.cy()->currentValue()->value(lengthContext)); return; } - SVGEllipseElement* ellipse = toSVGEllipseElement(element()); + SVGEllipseElement& ellipse = toSVGEllipseElement(*element()); - SVGLengthContext lengthContext(ellipse); - m_radii = FloatSize(ellipse->rxCurrentValue().value(lengthContext), ellipse->ryCurrentValue().value(lengthContext)); - m_center = FloatPoint(ellipse->cxCurrentValue().value(lengthContext), ellipse->cyCurrentValue().value(lengthContext)); + SVGLengthContext lengthContext(&ellipse); + m_radii = FloatSize(ellipse.rx()->currentValue()->value(lengthContext), ellipse.ry()->currentValue()->value(lengthContext)); + m_center = FloatPoint(ellipse.cx()->currentValue()->value(lengthContext), ellipse.cy()->currentValue()->value(lengthContext)); } void RenderSVGEllipse::fillShape(GraphicsContext* context) const diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGEllipse.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGEllipse.h index f06e5c16cf0..b73b5526853 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGEllipse.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGEllipse.h @@ -37,14 +37,14 @@ public: virtual ~RenderSVGEllipse(); private: - virtual const char* renderName() const { return "RenderSVGEllipse"; } - - virtual void updateShapeFromElement(); - virtual bool isEmpty() const { return m_usePathFallback ? RenderSVGShape::isEmpty() : m_fillBoundingBox.isEmpty(); }; - virtual void fillShape(GraphicsContext*) const; - virtual void strokeShape(GraphicsContext*) const; - virtual bool shapeDependentStrokeContains(const FloatPoint&); - virtual bool shapeDependentFillContains(const FloatPoint&, const WindRule) const; + virtual const char* renderName() const OVERRIDE { return "RenderSVGEllipse"; } + + virtual void updateShapeFromElement() OVERRIDE; + virtual bool isShapeEmpty() const OVERRIDE { return m_usePathFallback ? RenderSVGShape::isShapeEmpty() : m_fillBoundingBox.isEmpty(); } + virtual void fillShape(GraphicsContext*) const OVERRIDE; + virtual void strokeShape(GraphicsContext*) const OVERRIDE; + virtual bool shapeDependentStrokeContains(const FloatPoint&) OVERRIDE; + virtual bool shapeDependentFillContains(const FloatPoint&, const WindRule) const OVERRIDE; void calculateRadiiAndCenter(); private: diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGForeignObject.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGForeignObject.cpp index e27e037926f..9a9459836e1 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGForeignObject.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGForeignObject.cpp @@ -24,7 +24,6 @@ #include "core/rendering/svg/RenderSVGForeignObject.h" #include "core/rendering/HitTestResult.h" -#include "core/rendering/LayoutRectRecorder.h" #include "core/rendering/LayoutRepainter.h" #include "core/rendering/RenderView.h" #include "core/rendering/svg/SVGRenderSupport.h" @@ -45,6 +44,12 @@ RenderSVGForeignObject::~RenderSVGForeignObject() { } +bool RenderSVGForeignObject::isChildAllowed(RenderObject* child, RenderStyle* style) const +{ + // Disallow arbitary SVG content. Only allow proper <svg xmlns="svgNS"> subdocuments. + return !child->isSVG() || child->isSVGRoot(); +} + void RenderSVGForeignObject::paint(PaintInfo& paintInfo, const LayoutPoint&) { if (paintInfo.context->paintingDisabled() @@ -85,16 +90,6 @@ void RenderSVGForeignObject::paint(PaintInfo& paintInfo, const LayoutPoint&) } } -LayoutRect RenderSVGForeignObject::clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const -{ - return SVGRenderSupport::clippedOverflowRectForRepaint(this, repaintContainer); -} - -void RenderSVGForeignObject::computeFloatRectForRepaint(const RenderLayerModelObject* repaintContainer, FloatRect& repaintRect, bool fixed) const -{ - SVGRenderSupport::computeFloatRectForRepaint(this, repaintContainer, repaintRect, fixed); -} - const AffineTransform& RenderSVGForeignObject::localToParentTransform() const { m_localToParentTransform = localTransform(); @@ -121,9 +116,8 @@ void RenderSVGForeignObject::computeLogicalHeight(LayoutUnit, LayoutUnit logical void RenderSVGForeignObject::layout() { ASSERT(needsLayout()); - ASSERT(!view()->layoutStateEnabled()); // RenderSVGRoot disables layoutState for the SVG rendering tree. + ASSERT(!view()->layoutStateCachedOffsetsEnabled()); // RenderSVGRoot disables layoutState for the SVG rendering tree. - LayoutRectRecorder recorder(*this); LayoutRepainter repainter(*this, SVGRenderSupport::checkForSVGRepaintDuringLayout(this)); SVGForeignObjectElement* foreign = toSVGForeignObjectElement(node()); @@ -138,8 +132,8 @@ void RenderSVGForeignObject::layout() // Cache viewport boundaries SVGLengthContext lengthContext(foreign); - FloatPoint viewportLocation(foreign->xCurrentValue().value(lengthContext), foreign->yCurrentValue().value(lengthContext)); - m_viewport = FloatRect(viewportLocation, FloatSize(foreign->widthCurrentValue().value(lengthContext), foreign->heightCurrentValue().value(lengthContext))); + FloatPoint viewportLocation(foreign->x()->currentValue()->value(lengthContext), foreign->y()->currentValue()->value(lengthContext)); + m_viewport = FloatRect(viewportLocation, FloatSize(foreign->width()->currentValue()->value(lengthContext), foreign->height()->currentValue()->value(lengthContext))); if (!updateCachedBoundariesInParents) updateCachedBoundariesInParents = oldViewport != m_viewport; @@ -165,6 +159,14 @@ void RenderSVGForeignObject::layout() repainter.repaintAfterLayout(); } +void RenderSVGForeignObject::mapRectToPaintInvalidationBacking(const RenderLayerModelObject* paintInvalidationContainer, + LayoutRect& rect, bool fixed) const +{ + FloatRect r(rect); + SVGRenderSupport::computeFloatRectForRepaint(this, paintInvalidationContainer, r, fixed); + rect = enclosingLayoutRect(r); +} + bool RenderSVGForeignObject::nodeAtFloatPoint(const HitTestRequest& request, HitTestResult& result, const FloatPoint& pointInParent, HitTestAction hitTestAction) { // Embedded content is drawn in the foreground phase. @@ -184,20 +186,4 @@ bool RenderSVGForeignObject::nodeAtFloatPoint(const HitTestRequest& request, Hit || RenderBlock::nodeAtPoint(request, result, hitTestLocation, LayoutPoint(), HitTestChildBlockBackgrounds); } -bool RenderSVGForeignObject::nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation&, const LayoutPoint&, HitTestAction) -{ - ASSERT_NOT_REACHED(); - return false; -} - -void RenderSVGForeignObject::mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState& transformState, MapCoordinatesFlags, bool* wasFixed) const -{ - SVGRenderSupport::mapLocalToContainer(this, repaintContainer, transformState, wasFixed); -} - -const RenderObject* RenderSVGForeignObject::pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap& geometryMap) const -{ - return SVGRenderSupport::pushMappingToContainer(this, ancestorToStopAt, geometryMap); -} - } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGForeignObject.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGForeignObject.h index 63cdac1d35b..d57b723aa18 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGForeignObject.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGForeignObject.h @@ -32,38 +32,32 @@ public: explicit RenderSVGForeignObject(SVGForeignObjectElement*); virtual ~RenderSVGForeignObject(); - virtual const char* renderName() const { return "RenderSVGForeignObject"; } + virtual const char* renderName() const OVERRIDE { return "RenderSVGForeignObject"; } - virtual void paint(PaintInfo&, const LayoutPoint&); + virtual bool isChildAllowed(RenderObject*, RenderStyle*) const OVERRIDE; - virtual LayoutRect clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const OVERRIDE; - virtual void computeFloatRectForRepaint(const RenderLayerModelObject* repaintContainer, FloatRect&, bool fixed = false) const OVERRIDE; + virtual void paint(PaintInfo&, const LayoutPoint&) OVERRIDE; - virtual bool requiresLayer() const { return false; } - virtual void layout(); + virtual void layout() OVERRIDE; - virtual FloatRect objectBoundingBox() const { return FloatRect(FloatPoint(), m_viewport.size()); } - virtual FloatRect strokeBoundingBox() const { return FloatRect(FloatPoint(), m_viewport.size()); } - virtual FloatRect repaintRectInLocalCoordinates() const { return FloatRect(FloatPoint(), m_viewport.size()); } + virtual FloatRect objectBoundingBox() const OVERRIDE { return FloatRect(FloatPoint(), m_viewport.size()); } + virtual FloatRect strokeBoundingBox() const OVERRIDE { return FloatRect(FloatPoint(), m_viewport.size()); } + virtual FloatRect paintInvalidationRectInLocalCoordinates() const OVERRIDE { return FloatRect(FloatPoint(), m_viewport.size()); } - virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction); - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; - virtual bool isSVGForeignObject() const { return true; } + virtual void mapRectToPaintInvalidationBacking(const RenderLayerModelObject* paintInvalidationContainer, LayoutRect&, bool fixed = false) const OVERRIDE; + virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction) OVERRIDE; + virtual bool isSVGForeignObject() const OVERRIDE { return true; } - virtual void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = 0) const OVERRIDE; - virtual const RenderObject* pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap&) const OVERRIDE; - virtual void setNeedsTransformUpdate() { m_needsTransformUpdate = true; } + virtual void setNeedsTransformUpdate() OVERRIDE { m_needsTransformUpdate = true; } private: virtual void updateLogicalWidth() OVERRIDE; virtual void computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues&) const OVERRIDE; - virtual const AffineTransform& localToParentTransform() const; - virtual AffineTransform localTransform() const { return m_localTransform; } + virtual const AffineTransform& localToParentTransform() const OVERRIDE; bool m_needsTransformUpdate : 1; FloatRect m_viewport; - AffineTransform m_localTransform; mutable AffineTransform m_localToParentTransform; }; diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGGradientStop.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGGradientStop.cpp index ca5f315a7bc..d9ce3bf7015 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGGradientStop.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGGradientStop.cpp @@ -21,15 +21,12 @@ #include "core/rendering/svg/RenderSVGGradientStop.h" -#include "SVGNames.h" #include "core/rendering/svg/RenderSVGResourceContainer.h" #include "core/svg/SVGGradientElement.h" #include "core/svg/SVGStopElement.h" namespace WebCore { -using namespace SVGNames; - RenderSVGGradientStop::RenderSVGGradientStop(SVGStopElement* element) : RenderObject(element) { @@ -42,7 +39,7 @@ RenderSVGGradientStop::~RenderSVGGradientStop() void RenderSVGGradientStop::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { RenderObject::styleDidChange(diff, oldStyle); - if (diff == StyleDifferenceEqual) + if (diff.hasNoChange()) return; // <stop> elements should only be allowed to make renderers under gradient elements @@ -67,9 +64,8 @@ void RenderSVGGradientStop::layout() SVGGradientElement* RenderSVGGradientStop::gradientElement() const { ContainerNode* parentNode = node()->parentNode(); - if (parentNode->hasTagName(linearGradientTag) || parentNode->hasTagName(radialGradientTag)) - return toSVGGradientElement(parentNode); - return 0; + ASSERT(parentNode); + return isSVGGradientElement(*parentNode) ? toSVGGradientElement(parentNode) : 0; } } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGGradientStop.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGGradientStop.h index e56274e3ffc..4d6fee11121 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGGradientStop.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGGradientStop.h @@ -34,21 +34,22 @@ public: explicit RenderSVGGradientStop(SVGStopElement*); virtual ~RenderSVGGradientStop(); - virtual bool isSVGGradientStop() const { return true; } - virtual const char* renderName() const { return "RenderSVGGradientStop"; } + virtual const char* renderName() const OVERRIDE { return "RenderSVGGradientStop"; } + virtual bool isSVGGradientStop() const OVERRIDE { return true; } + virtual bool isSVG() const OVERRIDE { return true; } - virtual void layout(); + virtual void layout() OVERRIDE; // This overrides are needed to prevent ASSERTs on <svg><stop /></svg> // RenderObject's default implementations ASSERT_NOT_REACHED() // https://bugs.webkit.org/show_bug.cgi?id=20400 - virtual LayoutRect clippedOverflowRectForRepaint(const RenderLayerModelObject*) const OVERRIDE { return LayoutRect(); } - virtual FloatRect objectBoundingBox() const { return FloatRect(); } - virtual FloatRect strokeBoundingBox() const { return FloatRect(); } - virtual FloatRect repaintRectInLocalCoordinates() const { return FloatRect(); } + virtual LayoutRect clippedOverflowRectForPaintInvalidation(const RenderLayerModelObject*) const OVERRIDE { return LayoutRect(); } + virtual FloatRect objectBoundingBox() const OVERRIDE { return FloatRect(); } + virtual FloatRect strokeBoundingBox() const OVERRIDE { return FloatRect(); } + virtual FloatRect paintInvalidationRectInLocalCoordinates() const OVERRIDE { return FloatRect(); } protected: - virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) OVERRIDE; private: SVGGradientElement* gradientElement() const; diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGHiddenContainer.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGHiddenContainer.cpp index 0f1578935a5..0e5af52bb57 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGHiddenContainer.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGHiddenContainer.cpp @@ -20,8 +20,7 @@ #include "config.h" #include "core/rendering/svg/RenderSVGHiddenContainer.h" - -#include "core/rendering/LayoutRectRecorder.h" +#include "core/rendering/svg/SVGRenderSupport.h" namespace WebCore { @@ -33,7 +32,6 @@ RenderSVGHiddenContainer::RenderSVGHiddenContainer(SVGElement* element) void RenderSVGHiddenContainer::layout() { ASSERT(needsLayout()); - LayoutRectRecorder recorder(*this); SVGRenderSupport::layoutChildren(this, selfNeedsLayout()); updateCachedBoundaries(); clearNeedsLayout(); diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGHiddenContainer.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGHiddenContainer.h index f8e57d33f1d..0616b76b719 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGHiddenContainer.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGHiddenContainer.h @@ -32,17 +32,17 @@ class RenderSVGHiddenContainer : public RenderSVGContainer { public: explicit RenderSVGHiddenContainer(SVGElement*); - virtual const char* renderName() const { return "RenderSVGHiddenContainer"; } + virtual const char* renderName() const OVERRIDE { return "RenderSVGHiddenContainer"; } protected: - virtual void layout(); + virtual void layout() OVERRIDE; private: virtual bool isSVGHiddenContainer() const OVERRIDE FINAL { return true; } virtual void paint(PaintInfo&, const LayoutPoint&) OVERRIDE FINAL; - virtual LayoutRect clippedOverflowRectForRepaint(const RenderLayerModelObject*) const OVERRIDE FINAL { return LayoutRect(); } + virtual LayoutRect clippedOverflowRectForPaintInvalidation(const RenderLayerModelObject*) const OVERRIDE FINAL { return LayoutRect(); } virtual void absoluteQuads(Vector<FloatQuad>&, bool* wasFixed) const OVERRIDE FINAL; virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction) OVERRIDE FINAL; diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGImage.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGImage.cpp index 9e2e4cd9414..b483670d4f2 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGImage.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGImage.cpp @@ -29,11 +29,11 @@ #include "core/rendering/GraphicsContextAnnotator.h" #include "core/rendering/ImageQualityController.h" -#include "core/rendering/LayoutRectRecorder.h" #include "core/rendering/LayoutRepainter.h" #include "core/rendering/PointerEventsHitRules.h" #include "core/rendering/RenderImageResource.h" #include "core/rendering/svg/RenderSVGResource.h" +#include "core/rendering/svg/SVGRenderSupport.h" #include "core/rendering/svg/SVGRenderingContext.h" #include "core/rendering/svg/SVGResources.h" #include "core/rendering/svg/SVGResourcesCache.h" @@ -64,12 +64,12 @@ bool RenderSVGImage::updateImageViewport() bool updatedViewport = false; SVGLengthContext lengthContext(image); - m_objectBoundingBox = FloatRect(image->xCurrentValue().value(lengthContext), image->yCurrentValue().value(lengthContext), image->widthCurrentValue().value(lengthContext), image->heightCurrentValue().value(lengthContext)); + m_objectBoundingBox = FloatRect(image->x()->currentValue()->value(lengthContext), image->y()->currentValue()->value(lengthContext), image->width()->currentValue()->value(lengthContext), image->height()->currentValue()->value(lengthContext)); // Images with preserveAspectRatio=none should force non-uniform scaling. This can be achieved // by setting the image's container size to its intrinsic size. // See: http://www.w3.org/TR/SVG/single-page.html, 7.8 The ‘preserveAspectRatio’ attribute. - if (image->preserveAspectRatioCurrentValue().align() == SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_NONE) { + if (image->preserveAspectRatio()->currentValue()->align() == SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_NONE) { if (ImageResource* cachedImage = m_imageResource->cachedImage()) { LayoutSize intrinsicSize = cachedImage->imageSizeForRenderer(0, style()->effectiveZoom()); if (intrinsicSize != m_imageResource->imageSize(style()->effectiveZoom())) { @@ -93,7 +93,6 @@ void RenderSVGImage::layout() { ASSERT(needsLayout()); - LayoutRectRecorder recorder(*this); LayoutRepainter repainter(*this, SVGRenderSupport::checkForSVGRepaintDuringLayout(this) && selfNeedsLayout()); updateImageViewport(); @@ -126,33 +125,38 @@ void RenderSVGImage::paint(PaintInfo& paintInfo, const LayoutPoint&) { ANNOTATE_GRAPHICS_CONTEXT(paintInfo, this); - if (paintInfo.context->paintingDisabled() || style()->visibility() == HIDDEN || !m_imageResource->hasImage()) + if (paintInfo.context->paintingDisabled() + || paintInfo.phase != PaintPhaseForeground + || style()->visibility() == HIDDEN + || !m_imageResource->hasImage()) return; - FloatRect boundingBox = repaintRectInLocalCoordinates(); + FloatRect boundingBox = paintInvalidationRectInLocalCoordinates(); if (!SVGRenderSupport::paintInfoIntersectsRepaintRect(boundingBox, m_localTransform, paintInfo)) return; PaintInfo childPaintInfo(paintInfo); - bool drawsOutline = style()->outlineWidth() && (childPaintInfo.phase == PaintPhaseOutline || childPaintInfo.phase == PaintPhaseSelfOutline); - if (drawsOutline || childPaintInfo.phase == PaintPhaseForeground) { - GraphicsContextStateSaver stateSaver(*childPaintInfo.context); - childPaintInfo.applyTransform(m_localTransform); + GraphicsContextStateSaver stateSaver(*childPaintInfo.context, false); - if (childPaintInfo.phase == PaintPhaseForeground && !m_objectBoundingBox.isEmpty()) { - SVGRenderingContext renderingContext(this, childPaintInfo); + if (!m_localTransform.isIdentity()) { + stateSaver.save(); + childPaintInfo.applyTransform(m_localTransform, false); + } + if (!m_objectBoundingBox.isEmpty()) { + // SVGRenderingContext may taint the state - make sure we're always saving. + SVGRenderingContext renderingContext(this, childPaintInfo, stateSaver.saved() ? + SVGRenderingContext::DontSaveGraphicsContext : SVGRenderingContext::SaveGraphicsContext); - if (renderingContext.isRenderingPrepared()) { - if (style()->svgStyle()->bufferedRendering() == BR_STATIC && renderingContext.bufferForeground(m_bufferedForeground)) - return; + if (renderingContext.isRenderingPrepared()) { + if (style()->svgStyle()->bufferedRendering() == BR_STATIC && renderingContext.bufferForeground(m_bufferedForeground)) + return; - paintForeground(childPaintInfo); - } + paintForeground(childPaintInfo); } - - if (drawsOutline) - paintOutline(childPaintInfo, IntRect(boundingBox)); } + + if (style()->outlineWidth()) + paintOutline(childPaintInfo, IntRect(boundingBox)); } void RenderSVGImage::paintForeground(PaintInfo& paintInfo) @@ -162,13 +166,16 @@ void RenderSVGImage::paintForeground(PaintInfo& paintInfo) FloatRect srcRect(0, 0, image->width(), image->height()); SVGImageElement* imageElement = toSVGImageElement(element()); - imageElement->preserveAspectRatioCurrentValue().transformRect(destRect, srcRect); + imageElement->preserveAspectRatio()->currentValue()->transformRect(destRect, srcRect); - bool useLowQualityScaling = false; + InterpolationQuality interpolationQuality = InterpolationDefault; if (style()->svgStyle()->bufferedRendering() != BR_STATIC) - useLowQualityScaling = ImageQualityController::imageQualityController()->shouldPaintAtLowQuality(paintInfo.context, this, image.get(), image.get(), LayoutSize(destRect.size())); + interpolationQuality = ImageQualityController::imageQualityController()->chooseInterpolationQuality(paintInfo.context, this, image.get(), image.get(), LayoutSize(destRect.size())); - paintInfo.context->drawImage(image.get(), destRect, srcRect, CompositeSourceOver, DoNotRespectImageOrientation, useLowQualityScaling); + InterpolationQuality previousInterpolationQuality = paintInfo.context->imageInterpolationQuality(); + paintInfo.context->setImageInterpolationQuality(interpolationQuality); + paintInfo.context->drawImage(image.get(), destRect, srcRect, CompositeSourceOver); + paintInfo.context->setImageInterpolationQuality(previousInterpolationQuality); } void RenderSVGImage::invalidateBufferedForeground() @@ -218,13 +225,13 @@ void RenderSVGImage::imageChanged(WrappedImagePtr, const IntRect*) invalidateBufferedForeground(); - repaint(); + paintInvalidationForWholeRenderer(); } void RenderSVGImage::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint&, const RenderLayerModelObject*) { // this is called from paint() after the localTransform has already been applied - IntRect contentRect = enclosingIntRect(repaintRectInLocalCoordinates()); + IntRect contentRect = enclosingIntRect(paintInvalidationRectInLocalCoordinates()); if (!contentRect.isEmpty()) rects.append(contentRect); } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGImage.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGImage.h index e87392e04fa..644bdd15027 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGImage.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGImage.h @@ -37,9 +37,8 @@ public: virtual ~RenderSVGImage(); bool updateImageViewport(); - virtual void setNeedsBoundariesUpdate() { m_needsBoundariesUpdate = true; } - virtual bool needsBoundariesUpdate() OVERRIDE { return m_needsBoundariesUpdate; } - virtual void setNeedsTransformUpdate() { m_needsTransformUpdate = true; } + virtual void setNeedsBoundariesUpdate() OVERRIDE { m_needsBoundariesUpdate = true; } + virtual void setNeedsTransformUpdate() OVERRIDE { m_needsTransformUpdate = true; } RenderImageResource* imageResource() { return m_imageResource.get(); } @@ -47,27 +46,27 @@ public: void paintForeground(PaintInfo&); private: - virtual const char* renderName() const { return "RenderSVGImage"; } + virtual const char* renderName() const OVERRIDE { return "RenderSVGImage"; } virtual bool isSVGImage() const OVERRIDE { return true; } - virtual const AffineTransform& localToParentTransform() const { return m_localTransform; } + virtual const AffineTransform& localToParentTransform() const OVERRIDE { return m_localTransform; } - virtual FloatRect objectBoundingBox() const { return m_objectBoundingBox; } - virtual FloatRect strokeBoundingBox() const { return m_objectBoundingBox; } - virtual FloatRect repaintRectInLocalCoordinates() const { return m_repaintBoundingBox; } + virtual FloatRect objectBoundingBox() const OVERRIDE { return m_objectBoundingBox; } + virtual FloatRect strokeBoundingBox() const OVERRIDE { return m_objectBoundingBox; } + virtual FloatRect paintInvalidationRectInLocalCoordinates() const OVERRIDE { return m_repaintBoundingBox; } virtual void addFocusRingRects(Vector<IntRect>&, const LayoutPoint& additionalOffset, const RenderLayerModelObject* paintContainer = 0) OVERRIDE; - virtual void imageChanged(WrappedImagePtr, const IntRect* = 0); + virtual void imageChanged(WrappedImagePtr, const IntRect* = 0) OVERRIDE; - virtual void layout(); - virtual void paint(PaintInfo&, const LayoutPoint&); + virtual void layout() OVERRIDE; + virtual void paint(PaintInfo&, const LayoutPoint&) OVERRIDE; void invalidateBufferedForeground(); - virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction); + virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction) OVERRIDE; - virtual AffineTransform localTransform() const { return m_localTransform; } + virtual AffineTransform localTransform() const OVERRIDE { return m_localTransform; } bool m_needsBoundariesUpdate : 1; bool m_needsTransformUpdate : 1; diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGInline.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGInline.cpp index 68b1a4029cd..07c0a58c4d9 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGInline.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGInline.cpp @@ -27,12 +27,22 @@ #include "core/rendering/svg/SVGInlineFlowBox.h" #include "core/rendering/svg/SVGRenderSupport.h" #include "core/rendering/svg/SVGResourcesCache.h" +#include "core/svg/SVGAElement.h" namespace WebCore { bool RenderSVGInline::isChildAllowed(RenderObject* child, RenderStyle* style) const { - if (SVGRenderSupport::isEmptySVGInlineText(child)) + if (child->isText()) + return SVGRenderSupport::isRenderableTextNode(child); + + if (isSVGAElement(*node())) { + // Disallow direct descendant 'a'. + if (isSVGAElement(*child->node())) + return false; + } + + if (!child->isSVGInline() && !child->isSVGInlineText()) return false; return RenderInline::isChildAllowed(child, style); @@ -46,7 +56,7 @@ RenderSVGInline::RenderSVGInline(Element* element) InlineFlowBox* RenderSVGInline::createInlineFlowBox() { - InlineFlowBox* box = new SVGInlineFlowBox(this); + InlineFlowBox* box = new SVGInlineFlowBox(*this); box->setHasVirtualLogicalHeight(); return box; } @@ -67,22 +77,22 @@ FloatRect RenderSVGInline::strokeBoundingBox() const return FloatRect(); } -FloatRect RenderSVGInline::repaintRectInLocalCoordinates() const +FloatRect RenderSVGInline::paintInvalidationRectInLocalCoordinates() const { if (const RenderObject* object = RenderSVGText::locateRenderSVGTextAncestor(this)) - return object->repaintRectInLocalCoordinates(); + return object->paintInvalidationRectInLocalCoordinates(); return FloatRect(); } -LayoutRect RenderSVGInline::clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const +LayoutRect RenderSVGInline::clippedOverflowRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer) const { - return SVGRenderSupport::clippedOverflowRectForRepaint(this, repaintContainer); + return SVGRenderSupport::clippedOverflowRectForRepaint(this, paintInvalidationContainer); } -void RenderSVGInline::computeFloatRectForRepaint(const RenderLayerModelObject* repaintContainer, FloatRect& repaintRect, bool fixed) const +void RenderSVGInline::computeFloatRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer, FloatRect& paintInvalidationRect, bool fixed) const { - SVGRenderSupport::computeFloatRectForRepaint(this, repaintContainer, repaintRect, fixed); + SVGRenderSupport::computeFloatRectForRepaint(this, paintInvalidationContainer, paintInvalidationRect, fixed); } void RenderSVGInline::mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState& transformState, MapCoordinatesFlags, bool* wasFixed) const @@ -114,7 +124,7 @@ void RenderSVGInline::willBeDestroyed() void RenderSVGInline::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { - if (diff == StyleDifferenceLayout) + if (diff.needsFullLayout()) setNeedsBoundariesUpdate(); RenderInline::styleDidChange(diff, oldStyle); diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGInline.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGInline.h index 43634a39c22..1c09c5666f6 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGInline.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGInline.h @@ -29,9 +29,10 @@ class RenderSVGInline : public RenderInline { public: explicit RenderSVGInline(Element*); - virtual const char* renderName() const { return "RenderSVGInline"; } - virtual bool requiresLayer() const OVERRIDE FINAL { return false; } + virtual const char* renderName() const OVERRIDE { return "RenderSVGInline"; } + virtual LayerType layerTypeRequired() const OVERRIDE FINAL { return NoLayer; } virtual bool isSVGInline() const OVERRIDE FINAL { return true; } + virtual bool isSVG() const OVERRIDE FINAL { return true; } virtual bool isChildAllowed(RenderObject*, RenderStyle*) const OVERRIDE; @@ -42,10 +43,10 @@ public: // this element, since we need it for filters. virtual FloatRect objectBoundingBox() const OVERRIDE FINAL; virtual FloatRect strokeBoundingBox() const OVERRIDE FINAL; - virtual FloatRect repaintRectInLocalCoordinates() const OVERRIDE FINAL; + virtual FloatRect paintInvalidationRectInLocalCoordinates() const OVERRIDE FINAL; - virtual LayoutRect clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const OVERRIDE FINAL; - virtual void computeFloatRectForRepaint(const RenderLayerModelObject* repaintContainer, FloatRect&, bool fixed = false) const OVERRIDE FINAL; + virtual LayoutRect clippedOverflowRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer) const OVERRIDE FINAL; + virtual void computeFloatRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer, FloatRect&, bool fixed = false) const OVERRIDE FINAL; virtual void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = 0) const OVERRIDE FINAL; virtual const RenderObject* pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap&) const OVERRIDE FINAL; virtual void absoluteQuads(Vector<FloatQuad>&, bool* wasFixed) const OVERRIDE FINAL; @@ -60,6 +61,8 @@ private: virtual void removeChild(RenderObject*) OVERRIDE FINAL; }; +DEFINE_RENDER_OBJECT_TYPE_CASTS(RenderSVGInline, isSVGInline()); + } #endif // !RenderSVGTSpan_H diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGInlineText.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGInlineText.cpp index e8041f8c1c2..d19fed0516d 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGInlineText.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGInlineText.cpp @@ -89,17 +89,17 @@ void RenderSVGInlineText::styleDidChange(StyleDifference diff, const RenderStyle return; } - if (diff != StyleDifferenceLayout) + if (!diff.needsFullLayout()) return; // The text metrics may be influenced by style changes. if (RenderSVGText* textRenderer = RenderSVGText::locateRenderSVGTextAncestor(this)) - textRenderer->subtreeStyleDidChange(this); + textRenderer->setNeedsLayoutAndFullPaintInvalidation(); } InlineTextBox* RenderSVGInlineText::createTextBox() { - InlineTextBox* box = new SVGInlineTextBox(this); + InlineTextBox* box = new SVGInlineTextBox(*this); box->setHasVirtualLogicalHeight(); return box; } @@ -186,8 +186,7 @@ PositionWithAffinity RenderSVGInlineText::positionForPoint(const LayoutPoint& po const SVGTextFragment& fragment = fragments.at(i); FloatRect fragmentRect(fragment.x, fragment.y - baseline, fragment.width, fragment.height); fragment.buildFragmentTransform(fragmentTransform); - if (!fragmentTransform.isIdentity()) - fragmentRect = fragmentTransform.mapRect(fragmentRect); + fragmentRect = fragmentTransform.mapRect(fragmentRect); float distance = powf(fragmentRect.x() - absolutePoint.x(), 2) + powf(fragmentRect.y() + fragmentRect.height() / 2 - absolutePoint.y(), 2); @@ -226,7 +225,7 @@ void RenderSVGInlineText::computeNewScaledFontForStyle(RenderObject* renderer, c return; } - if (style->fontDescription().textRenderingMode() == GeometricPrecision) + if (style->fontDescription().textRendering() == GeometricPrecision) scalingFactor = 1; FontDescription fontDescription(style->fontDescription()); @@ -235,7 +234,7 @@ void RenderSVGInlineText::computeNewScaledFontForStyle(RenderObject* renderer, c // FIXME: We need to better handle the case when we compute very small fonts below (below 1pt). fontDescription.setComputedSize(FontSize::getComputedSizeFromSpecifiedSize(&document, scalingFactor, fontDescription.isAbsoluteSize(), fontDescription.specifiedSize(), DoNotUseSmartMinimumForFontSize)); - scaledFont = Font(fontDescription, 0, 0); + scaledFont = Font(fontDescription); scaledFont.update(document.styleEngine()->fontSelector()); } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGInlineText.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGInlineText.h index 8c7f711a68f..b7fc9add99b 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGInlineText.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGInlineText.h @@ -27,8 +27,6 @@ namespace WebCore { -class SVGInlineTextBox; - class RenderSVGInlineText FINAL : public RenderText { public: RenderSVGInlineText(Node*, PassRefPtr<StringImpl>); @@ -45,19 +43,20 @@ public: FloatRect floatLinesBoundingBox() const; private: - virtual const char* renderName() const { return "RenderSVGInlineText"; } + virtual const char* renderName() const OVERRIDE { return "RenderSVGInlineText"; } - virtual void setTextInternal(PassRefPtr<StringImpl>); - virtual void styleDidChange(StyleDifference, const RenderStyle*); + virtual void setTextInternal(PassRefPtr<StringImpl>) OVERRIDE; + virtual void styleDidChange(StyleDifference, const RenderStyle*) OVERRIDE; - virtual FloatRect objectBoundingBox() const { return floatLinesBoundingBox(); } + virtual FloatRect objectBoundingBox() const OVERRIDE { return floatLinesBoundingBox(); } - virtual bool isSVGInlineText() const { return true; } + virtual bool isSVGInlineText() const OVERRIDE { return true; } + virtual bool isSVG() const OVERRIDE { return true; } - virtual PositionWithAffinity positionForPoint(const LayoutPoint&) OVERRIDE FINAL; - virtual LayoutRect localCaretRect(InlineBox*, int caretOffset, LayoutUnit* extraWidthToEndOfLine = 0); - virtual IntRect linesBoundingBox() const; - virtual InlineTextBox* createTextBox(); + virtual PositionWithAffinity positionForPoint(const LayoutPoint&) OVERRIDE; + virtual LayoutRect localCaretRect(InlineBox*, int caretOffset, LayoutUnit* extraWidthToEndOfLine = 0) OVERRIDE; + virtual IntRect linesBoundingBox() const OVERRIDE; + virtual InlineTextBox* createTextBox() OVERRIDE; float m_scalingFactor; Font m_scaledFont; diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGModelObject.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGModelObject.cpp index 12da706b521..a6918a93535 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGModelObject.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGModelObject.cpp @@ -29,11 +29,12 @@ */ #include "config.h" - #include "core/rendering/svg/RenderSVGModelObject.h" -#include "SVGNames.h" +#include "core/rendering/RenderLayer.h" +#include "core/rendering/RenderView.h" #include "core/rendering/svg/RenderSVGRoot.h" +#include "core/rendering/svg/SVGRenderSupport.h" #include "core/rendering/svg/SVGResourcesCache.h" #include "core/svg/SVGGraphicsElement.h" @@ -44,14 +45,19 @@ RenderSVGModelObject::RenderSVGModelObject(SVGElement* node) { } -LayoutRect RenderSVGModelObject::clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const +bool RenderSVGModelObject::isChildAllowed(RenderObject* child, RenderStyle*) const +{ + return child->isSVG() && !(child->isSVGInline() || child->isSVGInlineText()); +} + +LayoutRect RenderSVGModelObject::clippedOverflowRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer) const { - return SVGRenderSupport::clippedOverflowRectForRepaint(this, repaintContainer); + return SVGRenderSupport::clippedOverflowRectForRepaint(this, paintInvalidationContainer); } -void RenderSVGModelObject::computeFloatRectForRepaint(const RenderLayerModelObject* repaintContainer, FloatRect& repaintRect, bool fixed) const +void RenderSVGModelObject::computeFloatRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer, FloatRect& paintInvalidationRect, bool fixed) const { - SVGRenderSupport::computeFloatRectForRepaint(this, repaintContainer, repaintRect, fixed); + SVGRenderSupport::computeFloatRectForRepaint(this, paintInvalidationContainer, paintInvalidationRect, fixed); } void RenderSVGModelObject::mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState& transformState, MapCoordinatesFlags, bool* wasFixed) const @@ -64,18 +70,6 @@ const RenderObject* RenderSVGModelObject::pushMappingToContainer(const RenderLay return SVGRenderSupport::pushMappingToContainer(this, ancestorToStopAt, geometryMap); } -// Copied from RenderBox, this method likely requires further refactoring to work easily for both SVG and CSS Box Model content. -// FIXME: This may also need to move into SVGRenderSupport as the RenderBox version depends -// on borderBoundingBox() which SVG RenderBox subclases (like SVGRenderBlock) do not implement. -LayoutRect RenderSVGModelObject::outlineBoundsForRepaint(const RenderLayerModelObject* repaintContainer, const RenderGeometryMap*) const -{ - LayoutRect box = enclosingLayoutRect(repaintRectInLocalCoordinates()); - adjustRectForOutlineAndShadow(box); - - FloatQuad containerRelativeQuad = localToContainerQuad(FloatRect(box), repaintContainer); - return containerRelativeQuad.enclosingBoundingBox(); -} - void RenderSVGModelObject::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset) const { IntRect rect = enclosingIntRect(strokeBoundingBox()); @@ -107,7 +101,7 @@ void RenderSVGModelObject::addLayerHitTestRects(LayerHitTestRects&, const Render void RenderSVGModelObject::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { - if (diff == StyleDifferenceLayout) { + if (diff.needsFullLayout()) { setNeedsBoundariesUpdate(); if (style()->hasTransform()) setNeedsTransformUpdate(); @@ -123,82 +117,53 @@ bool RenderSVGModelObject::nodeAtPoint(const HitTestRequest&, HitTestResult&, co return false; } -static void getElementCTM(SVGGraphicsElement* element, AffineTransform& transform) +// The SVG addFocusRingRects() method adds rects in local coordinates so the default absoluteFocusRingQuads +// returns incorrect values for SVG objects. Overriding this method provides access to the absolute bounds. +void RenderSVGModelObject::absoluteFocusRingQuads(Vector<FloatQuad>& quads) { - ASSERT(element); - element->document().updateLayoutIgnorePendingStylesheets(); - - SVGElement* stopAtElement = element->nearestViewportElement(); - ASSERT(stopAtElement); + quads.append(localToAbsoluteQuad(FloatQuad(paintInvalidationRectInLocalCoordinates()))); +} - AffineTransform localTransform; - Node* current = element; +void RenderSVGModelObject::invalidateTreeAfterLayout(const RenderLayerModelObject& paintInvalidationContainer) +{ + // Note: This is a reduced version of RenderBox::invalidateTreeAfterLayout(). + // FIXME: Should share code with RenderBox::invalidateTreeAfterLayout(). + ASSERT(RuntimeEnabledFeatures::repaintAfterLayoutEnabled()); + ASSERT(!needsLayout()); - while (current && current->isSVGElement()) { - SVGElement* currentElement = toSVGElement(current); - localTransform = currentElement->renderer()->localToParentTransform(); - transform = localTransform.multiply(transform); - // For getCTM() computation, stop at the nearest viewport element - if (currentElement == stopAtElement) - break; + if (!shouldCheckForPaintInvalidationAfterLayout()) + return; - current = current->parentOrShadowHostNode(); - } -} + ForceHorriblySlowRectMapping slowRectMapping(*this); -// FloatRect::intersects does not consider horizontal or vertical lines (because of isEmpty()). -// So special-case handling of such lines. -static bool intersectsAllowingEmpty(const FloatRect& r, const FloatRect& other) -{ - if (r.isEmpty() && other.isEmpty()) - return false; - if (r.isEmpty() && !other.isEmpty()) { - return (other.contains(r.x(), r.y()) && !other.contains(r.maxX(), r.maxY())) - || (!other.contains(r.x(), r.y()) && other.contains(r.maxX(), r.maxY())); - } - if (other.isEmpty() && !r.isEmpty()) - return intersectsAllowingEmpty(other, r); - return r.intersects(other); -} + const LayoutRect oldPaintInvalidationRect = previousPaintInvalidationRect(); + const LayoutPoint oldPositionFromPaintInvalidationContainer = previousPositionFromPaintInvalidationContainer(); + const RenderLayerModelObject& newPaintInvalidationContainer = *containerForPaintInvalidation(); + setPreviousPaintInvalidationRect(clippedOverflowRectForPaintInvalidation(&newPaintInvalidationContainer)); + setPreviousPositionFromPaintInvalidationContainer(RenderLayer::positionFromPaintInvalidationContainer(this, &newPaintInvalidationContainer)); -// One of the element types that can cause graphics to be drawn onto the target canvas. Specifically: circle, ellipse, -// image, line, path, polygon, polyline, rect, text and use. -static bool isGraphicsElement(RenderObject* renderer) -{ - return renderer->isSVGShape() || renderer->isSVGText() || renderer->isSVGImage() || renderer->node()->hasTagName(SVGNames::useTag); -} + // If an ancestor container had its transform changed, then we just + // need to update the RenderSVGModelObject's repaint rect above. The invalidation + // will be handled by the container where the transform changed. This essentially + // means that we prune the entire branch for performance. + if (!SVGRenderSupport::parentTransformDidChange(this)) + return; -// The SVG addFocusRingRects() method adds rects in local coordinates so the default absoluteFocusRingQuads -// returns incorrect values for SVG objects. Overriding this method provides access to the absolute bounds. -void RenderSVGModelObject::absoluteFocusRingQuads(Vector<FloatQuad>& quads) -{ - quads.append(localToAbsoluteQuad(FloatQuad(repaintRectInLocalCoordinates()))); -} + // If we are set to do a full paint invalidation that means the RenderView will be + // issue paint invalidations. We can then skip issuing of paint invalidations for the child + // renderers as they'll be covered by the RenderView. + if (view()->doingFullRepaint()) { + RenderObject::invalidateTreeAfterLayout(newPaintInvalidationContainer); + return; + } -bool RenderSVGModelObject::checkIntersection(RenderObject* renderer, const SVGRect& rect) -{ - if (!renderer || renderer->style()->pointerEvents() == PE_NONE) - return false; - if (!isGraphicsElement(renderer)) - return false; - AffineTransform ctm; - SVGGraphicsElement* svgElement = toSVGGraphicsElement(renderer->node()); - getElementCTM(svgElement, ctm); - ASSERT(svgElement->renderer()); - return intersectsAllowingEmpty(rect, ctm.mapRect(svgElement->renderer()->repaintRectInLocalCoordinates())); -} + const LayoutRect& newPaintInvalidationRect = previousPaintInvalidationRect(); + const LayoutPoint& newPositionFromPaintInvalidationContainer = previousPositionFromPaintInvalidationContainer(); + invalidatePaintAfterLayoutIfNeeded(containerForPaintInvalidation(), + shouldDoFullPaintInvalidationAfterLayout(), oldPaintInvalidationRect, oldPositionFromPaintInvalidationContainer, + &newPaintInvalidationRect, &newPositionFromPaintInvalidationContainer); -bool RenderSVGModelObject::checkEnclosure(RenderObject* renderer, const SVGRect& rect) -{ - if (!renderer || renderer->style()->pointerEvents() == PE_NONE) - return false; - if (!isGraphicsElement(renderer)) - return false; - AffineTransform ctm; - SVGGraphicsElement* svgElement = toSVGGraphicsElement(renderer->node()); - getElementCTM(svgElement, ctm); - ASSERT(svgElement->renderer()); - return rect.contains(ctm.mapRect(svgElement->renderer()->repaintRectInLocalCoordinates())); + RenderObject::invalidateTreeAfterLayout(newPaintInvalidationContainer); } } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGModelObject.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGModelObject.h index c8df10aca7d..41bc62ae412 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGModelObject.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGModelObject.h @@ -32,9 +32,8 @@ #define RenderSVGModelObject_h #include "core/rendering/RenderObject.h" -#include "core/rendering/svg/SVGRenderSupport.h" #include "core/svg/SVGElement.h" -#include "core/svg/SVGRect.h" +#include "platform/geometry/FloatRect.h" namespace WebCore { @@ -49,34 +48,37 @@ class RenderSVGModelObject : public RenderObject { public: explicit RenderSVGModelObject(SVGElement*); - virtual LayoutRect clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const OVERRIDE; - virtual void computeFloatRectForRepaint(const RenderLayerModelObject* repaintContainer, FloatRect&, bool fixed = false) const OVERRIDE FINAL; - virtual LayoutRect outlineBoundsForRepaint(const RenderLayerModelObject* repaintContainer, const RenderGeometryMap*) const OVERRIDE FINAL; + virtual bool isChildAllowed(RenderObject*, RenderStyle*) const OVERRIDE; + virtual bool canHaveWhitespaceChildren() const OVERRIDE { return false; } + + virtual LayoutRect clippedOverflowRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer) const OVERRIDE; + virtual void computeFloatRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer, FloatRect&, bool fixed = false) const OVERRIDE FINAL; virtual void absoluteRects(Vector<IntRect>&, const LayoutPoint& accumulatedOffset) const OVERRIDE FINAL; - virtual void absoluteQuads(Vector<FloatQuad>&, bool* wasFixed) const; + virtual void absoluteQuads(Vector<FloatQuad>&, bool* wasFixed) const OVERRIDE; virtual void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = 0) const OVERRIDE FINAL; virtual const RenderObject* pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap&) const OVERRIDE FINAL; - virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); - - static bool checkIntersection(RenderObject*, const SVGRect&); - static bool checkEnclosure(RenderObject*, const SVGRect&); + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) OVERRIDE; - virtual void computeLayerHitTestRects(LayerHitTestRects&) const OVERRIDE; + virtual void computeLayerHitTestRects(LayerHitTestRects&) const OVERRIDE FINAL; SVGElement* element() const { return toSVGElement(RenderObject::node()); } + virtual bool isSVG() const OVERRIDE FINAL { return true; } + + virtual void invalidateTreeAfterLayout(const RenderLayerModelObject&) OVERRIDE; + protected: - virtual void addLayerHitTestRects(LayerHitTestRects&, const RenderLayer* currentCompositedLayer, const LayoutPoint& layerOffset, const LayoutRect& containerRect) const OVERRIDE; - virtual void willBeDestroyed(); + virtual void addLayerHitTestRects(LayerHitTestRects&, const RenderLayer* currentCompositedLayer, const LayoutPoint& layerOffset, const LayoutRect& containerRect) const OVERRIDE FINAL; + virtual void willBeDestroyed() OVERRIDE; private: // RenderSVGModelObject subclasses should use element() instead. void node() const WTF_DELETED_FUNCTION; // This method should never be called, SVG uses a different nodeAtPoint method - bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE FINAL; virtual void absoluteFocusRingQuads(Vector<FloatQuad>&) OVERRIDE FINAL; }; diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGPath.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGPath.h index 8cec15c4c92..48b36762e04 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGPath.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGPath.h @@ -37,7 +37,7 @@ public: private: virtual bool isSVGPath() const OVERRIDE { return true; } - virtual const char* renderName() const { return "RenderSVGPath"; } + virtual const char* renderName() const OVERRIDE { return "RenderSVGPath"; } virtual void updateShapeFromElement() OVERRIDE; FloatRect calculateUpdatedStrokeBoundingBox() const; diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGRect.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGRect.cpp index dfe447156f6..5fd79e7f626 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGRect.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGRect.cpp @@ -28,8 +28,7 @@ #include "config.h" #include "core/rendering/svg/RenderSVGRect.h" - -#include "SVGNames.h" +#include "platform/graphics/GraphicsContext.h" namespace WebCore { @@ -54,19 +53,24 @@ void RenderSVGRect::updateShapeFromElement() ASSERT(rect); SVGLengthContext lengthContext(rect); - // Fallback to RenderSVGShape if rect has rounded corners or a non-scaling stroke. - if (rect->rxCurrentValue().value(lengthContext) > 0 || rect->ryCurrentValue().value(lengthContext) > 0 || hasNonScalingStroke()) { - RenderSVGShape::updateShapeFromElement(); - m_usePathFallback = true; - return; - } + FloatSize boundingBoxSize(rect->width()->currentValue()->value(lengthContext), rect->height()->currentValue()->value(lengthContext)); - m_usePathFallback = false; - FloatSize boundingBoxSize(rect->widthCurrentValue().value(lengthContext), rect->heightCurrentValue().value(lengthContext)); - if (boundingBoxSize.isEmpty()) + // Spec: "A negative value is an error." + if (boundingBoxSize.width() < 0 || boundingBoxSize.height() < 0) return; - m_fillBoundingBox = FloatRect(FloatPoint(rect->xCurrentValue().value(lengthContext), rect->yCurrentValue().value(lengthContext)), boundingBoxSize); + // Spec: "A value of zero disables rendering of the element." + if (!boundingBoxSize.isEmpty()) { + // Fallback to RenderSVGShape if rect has rounded corners or a non-scaling stroke. + if (rect->rx()->currentValue()->value(lengthContext) > 0 || rect->ry()->currentValue()->value(lengthContext) > 0 || hasNonScalingStroke()) { + RenderSVGShape::updateShapeFromElement(); + m_usePathFallback = true; + return; + } + m_usePathFallback = false; + } + + m_fillBoundingBox = FloatRect(FloatPoint(rect->x()->currentValue()->value(lengthContext), rect->y()->currentValue()->value(lengthContext)), boundingBoxSize); // To decide if the stroke contains a point we create two rects which represent the inner and // the outer stroke borders. A stroke contains the point, if the point is between them. diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGRect.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGRect.h index 1a5d6e091e4..7ae39625755 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGRect.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGRect.h @@ -39,14 +39,14 @@ public: virtual ~RenderSVGRect(); private: - virtual const char* renderName() const { return "RenderSVGRect"; } - - virtual void updateShapeFromElement(); - virtual bool isEmpty() const { return m_usePathFallback ? RenderSVGShape::isEmpty() : m_fillBoundingBox.isEmpty(); }; - virtual void fillShape(GraphicsContext*) const; - virtual void strokeShape(GraphicsContext*) const; - virtual bool shapeDependentStrokeContains(const FloatPoint&); - virtual bool shapeDependentFillContains(const FloatPoint&, const WindRule) const; + virtual const char* renderName() const OVERRIDE { return "RenderSVGRect"; } + + virtual void updateShapeFromElement() OVERRIDE; + virtual bool isShapeEmpty() const OVERRIDE { return m_usePathFallback ? RenderSVGShape::isShapeEmpty() : m_fillBoundingBox.isEmpty(); } + virtual void fillShape(GraphicsContext*) const OVERRIDE; + virtual void strokeShape(GraphicsContext*) const OVERRIDE; + virtual bool shapeDependentStrokeContains(const FloatPoint&) OVERRIDE; + virtual bool shapeDependentFillContains(const FloatPoint&, const WindRule) const OVERRIDE; private: FloatRect m_innerStrokeRect; diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResource.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResource.cpp index 4dd3ae01c90..0c67bc8d070 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResource.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResource.cpp @@ -24,8 +24,8 @@ #include "core/rendering/svg/RenderSVGResource.h" -#include "core/frame/Frame.h" #include "core/frame/FrameView.h" +#include "core/frame/LocalFrame.h" #include "core/rendering/svg/RenderSVGResourceClipper.h" #include "core/rendering/svg/RenderSVGResourceFilter.h" #include "core/rendering/svg/RenderSVGResourceMasker.h" @@ -35,22 +35,25 @@ namespace WebCore { -static inline bool inheritColorFromParentStyleIfNeeded(RenderObject* object, bool applyToFill, Color& color) +static inline bool inheritColorFromParentStyle(RenderObject* object, bool applyToFill, Color& color) { - if (color.isValid()) - return true; if (!object->parent() || !object->parent()->style()) return false; const SVGRenderStyle* parentSVGStyle = object->parent()->style()->svgStyle(); + SVGPaint::SVGPaintType paintType = applyToFill ? parentSVGStyle->fillPaintType() : parentSVGStyle->strokePaintType(); + if (paintType != SVGPaint::SVG_PAINTTYPE_RGBCOLOR && paintType != SVGPaint::SVG_PAINTTYPE_RGBCOLOR_ICCCOLOR) + return false; color = applyToFill ? parentSVGStyle->fillPaintColor() : parentSVGStyle->strokePaintColor(); return true; } -static inline RenderSVGResource* requestPaintingResource(RenderSVGResourceMode mode, RenderObject* object, const RenderStyle* style, Color& fallbackColor) +static inline RenderSVGResource* requestPaintingResource(RenderSVGResourceMode mode, RenderObject* object, const RenderStyle* style, bool& hasFallback) { ASSERT(object); ASSERT(style); + hasFallback = false; + // If we have no style at all, ignore it. const SVGRenderStyle* svgStyle = style->svgStyle(); if (!svgStyle) @@ -78,10 +81,10 @@ static inline RenderSVGResource* requestPaintingResource(RenderSVGResourceMode m bool applyToFill = mode == ApplyToFillMode; SVGPaint::SVGPaintType paintType = applyToFill ? svgStyle->fillPaintType() : svgStyle->strokePaintType(); - if (paintType == SVGPaint::SVG_PAINTTYPE_NONE) - return 0; + ASSERT(paintType != SVGPaint::SVG_PAINTTYPE_NONE); Color color; + bool hasColor = false; switch (paintType) { case SVGPaint::SVG_PAINTTYPE_CURRENTCOLOR: case SVGPaint::SVG_PAINTTYPE_RGBCOLOR: @@ -90,6 +93,7 @@ static inline RenderSVGResource* requestPaintingResource(RenderSVGResourceMode m case SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR: case SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR_ICCCOLOR: color = applyToFill ? svgStyle->fillPaintColor() : svgStyle->strokePaintColor(); + hasColor = true; default: break; } @@ -101,15 +105,15 @@ static inline RenderSVGResource* requestPaintingResource(RenderSVGResourceMode m // For SVG_PAINTTYPE_CURRENTCOLOR, 'color' already contains the 'visitedColor'. if (visitedPaintType < SVGPaint::SVG_PAINTTYPE_URI_NONE && visitedPaintType != SVGPaint::SVG_PAINTTYPE_CURRENTCOLOR) { const Color& visitedColor = applyToFill ? svgStyle->visitedLinkFillPaintColor() : svgStyle->visitedLinkStrokePaintColor(); - if (visitedColor.isValid()) - color = Color(visitedColor.red(), visitedColor.green(), visitedColor.blue(), color.alpha()); + color = Color(visitedColor.red(), visitedColor.green(), visitedColor.blue(), color.alpha()); + hasColor = true; } } // If the primary resource is just a color, return immediately. RenderSVGResourceSolidColor* colorResource = RenderSVGResource::sharedSolidPaintingResource(); if (paintType < SVGPaint::SVG_PAINTTYPE_URI_NONE) { - if (!inheritColorFromParentStyleIfNeeded(object, applyToFill, color)) + if (!hasColor && !inheritColorFromParentStyle(object, applyToFill, color)) return 0; colorResource->setColor(color); @@ -119,7 +123,7 @@ static inline RenderSVGResource* requestPaintingResource(RenderSVGResourceMode m // If no resources are associated with the given renderer, return the color resource. SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(object); if (!resources) { - if (paintType == SVGPaint::SVG_PAINTTYPE_URI_NONE || !inheritColorFromParentStyleIfNeeded(object, applyToFill, color)) + if (paintType == SVGPaint::SVG_PAINTTYPE_URI_NONE || (!hasColor && !inheritColorFromParentStyle(object, applyToFill, color))) return 0; colorResource->setColor(color); @@ -129,7 +133,7 @@ static inline RenderSVGResource* requestPaintingResource(RenderSVGResourceMode m // If the requested resource is not available, return the color resource. RenderSVGResource* uriResource = mode == ApplyToFillMode ? resources->fill() : resources->stroke(); if (!uriResource) { - if (!inheritColorFromParentStyleIfNeeded(object, applyToFill, color)) + if (!hasColor && !inheritColorFromParentStyle(object, applyToFill, color)) return 0; colorResource->setColor(color); @@ -137,19 +141,22 @@ static inline RenderSVGResource* requestPaintingResource(RenderSVGResourceMode m } // The paint server resource exists, though it may be invalid (pattern with width/height=0). Pass the fallback color to our caller - // so it can use the solid color painting resource, if applyResource() on the URI resource failed. - fallbackColor = color; + // via sharedSolidPaintingResource so it can use the solid color painting resource, if applyResource() on the URI resource failed. + if (hasColor) { + colorResource->setColor(color); + hasFallback = true; + } return uriResource; } -RenderSVGResource* RenderSVGResource::fillPaintingResource(RenderObject* object, const RenderStyle* style, Color& fallbackColor) +RenderSVGResource* RenderSVGResource::fillPaintingResource(RenderObject* object, const RenderStyle* style, bool& hasFallback) { - return requestPaintingResource(ApplyToFillMode, object, style, fallbackColor); + return requestPaintingResource(ApplyToFillMode, object, style, hasFallback); } -RenderSVGResource* RenderSVGResource::strokePaintingResource(RenderObject* object, const RenderStyle* style, Color& fallbackColor) +RenderSVGResource* RenderSVGResource::strokePaintingResource(RenderObject* object, const RenderStyle* style, bool& hasFallback) { - return requestPaintingResource(ApplyToStrokeMode, object, style, fallbackColor); + return requestPaintingResource(ApplyToStrokeMode, object, style, hasFallback); } RenderSVGResourceSolidColor* RenderSVGResource::sharedSolidPaintingResource() @@ -176,13 +183,28 @@ static inline void removeFromCacheAndInvalidateDependencies(RenderObject* object if (!object->node() || !object->node()->isSVGElement()) return; - HashSet<SVGElement*>* dependencies = object->document().accessSVGExtensions()->setOfElementsReferencingTarget(toSVGElement(object->node())); + SVGElementSet* dependencies = object->document().accessSVGExtensions().setOfElementsReferencingTarget(toSVGElement(object->node())); if (!dependencies) return; - HashSet<SVGElement*>::iterator end = dependencies->end(); - for (HashSet<SVGElement*>::iterator it = dependencies->begin(); it != end; ++it) { - if (RenderObject* renderer = (*it)->renderer()) + + // We allow cycles in SVGDocumentExtensions reference sets in order to avoid expensive + // reference graph adjustments on changes, so we need to break possible cycles here. + // This strong reference is safe, as it is guaranteed that this set will be emptied + // at the end of recursion. + typedef WillBeHeapHashSet<RawPtrWillBeMember<SVGElement> > SVGElementSet; + DEFINE_STATIC_LOCAL(OwnPtrWillBePersistent<SVGElementSet>, invalidatingDependencies, (adoptPtrWillBeNoop(new SVGElementSet))); + + SVGElementSet::iterator end = dependencies->end(); + for (SVGElementSet::iterator it = dependencies->begin(); it != end; ++it) { + if (RenderObject* renderer = (*it)->renderer()) { + if (UNLIKELY(!invalidatingDependencies->add(*it).isNewEntry)) { + // Reference cycle: we are in process of invalidating this dependant. + continue; + } + RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer, needsLayout); + invalidatingDependencies->remove(*it); + } } } @@ -192,7 +214,7 @@ void RenderSVGResource::markForLayoutAndParentResourceInvalidation(RenderObject* ASSERT(object->node()); if (needsLayout && !object->documentBeingDestroyed()) - object->setNeedsLayout(); + object->setNeedsLayoutAndFullPaintInvalidation(); removeFromCacheAndInvalidateDependencies(object, needsLayout); diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResource.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResource.h index 676562dd01c..d1d3a89926b 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResource.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResource.h @@ -43,9 +43,8 @@ enum RenderSVGResourceMode { ApplyToStrokeMode = 1 << 2, ApplyToTextMode = 1 << 3 // used in combination with ApplyTo{Fill|Stroke}Mode }; +typedef unsigned RenderSVGResourceModeFlags; -class Color; -class FloatRect; class GraphicsContext; class Path; class RenderObject; @@ -75,8 +74,9 @@ public: } // Helper utilities used in the render tree to access resources used for painting shapes/text (gradients & patterns & solid colors only) - static RenderSVGResource* fillPaintingResource(RenderObject*, const RenderStyle*, Color& fallbackColor); - static RenderSVGResource* strokePaintingResource(RenderObject*, const RenderStyle*, Color& fallbackColor); + // If hasFallback gets set to true, the sharedSolidPaintingResource is set to a fallback color. + static RenderSVGResource* fillPaintingResource(RenderObject*, const RenderStyle*, bool& hasFallback); + static RenderSVGResource* strokePaintingResource(RenderObject*, const RenderStyle*, bool& hasFallback); static RenderSVGResourceSolidColor* sharedSolidPaintingResource(); static void markForLayoutAndParentResourceInvalidation(RenderObject*, bool needsLayout = true); diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceClipper.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceClipper.cpp index b98db0f7c86..62db92f8c1a 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceClipper.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceClipper.cpp @@ -24,15 +24,16 @@ #include "core/rendering/svg/RenderSVGResourceClipper.h" -#include "RuntimeEnabledFeatures.h" -#include "SVGNames.h" -#include "core/frame/Frame.h" +#include "core/SVGNames.h" #include "core/frame/FrameView.h" +#include "core/frame/LocalFrame.h" #include "core/rendering/HitTestResult.h" +#include "core/rendering/svg/SVGRenderSupport.h" #include "core/rendering/svg/SVGRenderingContext.h" #include "core/rendering/svg/SVGResources.h" #include "core/rendering/svg/SVGResourcesCache.h" #include "core/svg/SVGUseElement.h" +#include "platform/RuntimeEnabledFeatures.h" #include "platform/graphics/DisplayList.h" #include "platform/graphics/GraphicsContextStateSaver.h" #include "wtf/TemporaryChange.h" @@ -78,7 +79,7 @@ bool RenderSVGResourceClipper::applyStatefulResource(RenderObject* object, Graph clearInvalidationMask(); - return applyClippingToContext(object, object->objectBoundingBox(), object->repaintRectInLocalCoordinates(), context, clipperContext); + return applyClippingToContext(object, object->objectBoundingBox(), object->paintInvalidationRectInLocalCoordinates(), context, clipperContext); } bool RenderSVGResourceClipper::tryPathOnlyClipping(GraphicsContext* context, @@ -89,16 +90,16 @@ bool RenderSVGResourceClipper::tryPathOnlyClipping(GraphicsContext* context, WindRule clipRule = RULE_NONZERO; Path clipPath = Path(); - for (Node* childNode = element()->firstChild(); childNode; childNode = childNode->nextSibling()) { - RenderObject* renderer = childNode->renderer(); + for (Element* childElement = ElementTraversal::firstWithin(*element()); childElement; childElement = ElementTraversal::nextSibling(*childElement)) { + RenderObject* renderer = childElement->renderer(); if (!renderer) continue; // Only shapes or paths are supported for direct clipping. We need to fallback to masking for texts. if (renderer->isSVGText()) return false; - if (!childNode->isSVGElement() || !toSVGElement(childNode)->isSVGGraphicsElement()) + if (!childElement->isSVGElement() || !toSVGElement(childElement)->isSVGGraphicsElement()) continue; - SVGGraphicsElement* styled = toSVGGraphicsElement(childNode); + SVGGraphicsElement* styled = toSVGGraphicsElement(childElement); RenderStyle* style = renderer->style(); if (!style || style->display() == NONE || style->visibility() != VISIBLE) continue; @@ -127,7 +128,7 @@ bool RenderSVGResourceClipper::tryPathOnlyClipping(GraphicsContext* context, } } // Only one visible shape/path was found. Directly continue clipping and transform the content to userspace if necessary. - if (toSVGClipPathElement(element())->clipPathUnitsCurrentValue() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { + if (toSVGClipPathElement(element())->clipPathUnits()->currentValue()->enumValue() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { AffineTransform transform; transform.translate(objectBoundingBox.x(), objectBoundingBox.y()); transform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height()); @@ -148,7 +149,6 @@ bool RenderSVGResourceClipper::applyClippingToContext(RenderObject* target, cons const FloatRect& repaintRect, GraphicsContext* context, ClipperContext& clipperContext) { ASSERT(target); - ASSERT(target->node()); ASSERT(context); ASSERT(clipperContext.state == ClipperContext::NotAppliedState); ASSERT_WITH_SECURITY_IMPLICATION(!needsLayout()); @@ -161,8 +161,8 @@ bool RenderSVGResourceClipper::applyClippingToContext(RenderObject* target, cons // When drawing a clip for non-SVG elements, the CTM does not include the zoom factor. // In this case, we need to apply the zoom scale explicitly - but only for clips with // userSpaceOnUse units (the zoom is accounted for objectBoundingBox-resolved lengths). - if (!target->node()->isSVGElement() - && toSVGClipPathElement(element())->clipPathUnitsCurrentValue() == SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE) { + if (!target->isSVG() + && toSVGClipPathElement(element())->clipPathUnits()->currentValue()->enumValue() == SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE) { ASSERT(style()); animatedLocalTransform.scale(style()->effectiveZoom()); } @@ -238,7 +238,7 @@ void RenderSVGResourceClipper::drawClipMaskContent(GraphicsContext* context, con ASSERT(context); AffineTransform contentTransformation; - SVGUnitTypes::SVGUnitType contentUnits = toSVGClipPathElement(element())->clipPathUnitsCurrentValue(); + SVGUnitTypes::SVGUnitType contentUnits = toSVGClipPathElement(element())->clipPathUnits()->currentValue()->enumValue(); if (contentUnits == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { contentTransformation.translate(targetBoundingBox.x(), targetBoundingBox.y()); contentTransformation.scaleNonUniform(targetBoundingBox.width(), targetBoundingBox.height()); @@ -258,7 +258,10 @@ PassRefPtr<DisplayList> RenderSVGResourceClipper::asDisplayList(GraphicsContext* ASSERT(context); ASSERT(frame()); - context->beginRecording(repaintRectInLocalCoordinates()); + // Using strokeBoundingBox (instead of paintInvalidationRectInLocalCoordinates) to avoid the intersection + // with local clips/mask, which may yield incorrect results when mixing objectBoundingBox and + // userSpaceOnUse units (http://crbug.com/294900). + context->beginRecording(strokeBoundingBox()); // Switch to a paint behavior where all children of this <clipPath> will be rendered using special constraints: // - fill-opacity/stroke-opacity/opacity set to 1 @@ -268,9 +271,9 @@ PassRefPtr<DisplayList> RenderSVGResourceClipper::asDisplayList(GraphicsContext* PaintBehavior oldBehavior = frame()->view()->paintBehavior(); frame()->view()->setPaintBehavior(oldBehavior | PaintBehaviorRenderingSVGMask); - for (Node* childNode = element()->firstChild(); childNode; childNode = childNode->nextSibling()) { - RenderObject* renderer = childNode->renderer(); - if (!childNode->isSVGElement() || !renderer) + for (SVGElement* childElement = Traversal<SVGElement>::firstChild(*element()); childElement; childElement = Traversal<SVGElement>::nextSibling(*childElement)) { + RenderObject* renderer = childElement->renderer(); + if (!renderer) continue; RenderStyle* style = renderer->style(); @@ -278,13 +281,13 @@ PassRefPtr<DisplayList> RenderSVGResourceClipper::asDisplayList(GraphicsContext* continue; WindRule newClipRule = style->svgStyle()->clipRule(); - bool isUseElement = childNode->hasTagName(SVGNames::useTag); + bool isUseElement = isSVGUseElement(*childElement); if (isUseElement) { - SVGUseElement* useElement = toSVGUseElement(childNode); - renderer = useElement->rendererClipChild(); + SVGUseElement& useElement = toSVGUseElement(*childElement); + renderer = useElement.rendererClipChild(); if (!renderer) continue; - if (!useElement->hasAttribute(SVGNames::clip_ruleAttr)) + if (!useElement.hasAttribute(SVGNames::clip_ruleAttr)) newClipRule = renderer->style()->svgStyle()->clipRule(); } @@ -295,7 +298,7 @@ PassRefPtr<DisplayList> RenderSVGResourceClipper::asDisplayList(GraphicsContext* context->setFillRule(newClipRule); if (isUseElement) - renderer = childNode->renderer(); + renderer = childElement->renderer(); SVGRenderingContext::renderSubtree(context, renderer, contentTransformation); } @@ -308,16 +311,16 @@ PassRefPtr<DisplayList> RenderSVGResourceClipper::asDisplayList(GraphicsContext* void RenderSVGResourceClipper::calculateClipContentRepaintRect() { // This is a rough heuristic to appraise the clip size and doesn't consider clip on clip. - for (Node* childNode = element()->firstChild(); childNode; childNode = childNode->nextSibling()) { - RenderObject* renderer = childNode->renderer(); - if (!childNode->isSVGElement() || !renderer) + for (SVGElement* childElement = Traversal<SVGElement>::firstChild(*element()); childElement; childElement = Traversal<SVGElement>::nextSibling(*childElement)) { + RenderObject* renderer = childElement->renderer(); + if (!renderer) continue; - if (!renderer->isSVGShape() && !renderer->isSVGText() && !childNode->hasTagName(SVGNames::useTag)) + if (!renderer->isSVGShape() && !renderer->isSVGText() && !isSVGUseElement(*childElement)) continue; RenderStyle* style = renderer->style(); if (!style || style->display() == NONE || style->visibility() != VISIBLE) continue; - m_clipBoundaries.unite(renderer->localToParentTransform().mapRect(renderer->repaintRectInLocalCoordinates())); + m_clipBoundaries.unite(renderer->localToParentTransform().mapRect(renderer->paintInvalidationRectInLocalCoordinates())); } m_clipBoundaries = toSVGClipPathElement(element())->animatedLocalTransform().mapRect(m_clipBoundaries); } @@ -329,7 +332,7 @@ bool RenderSVGResourceClipper::hitTestClipContent(const FloatRect& objectBoundin return false; SVGClipPathElement* clipPathElement = toSVGClipPathElement(element()); - if (clipPathElement->clipPathUnitsCurrentValue() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { + if (clipPathElement->clipPathUnits()->currentValue()->enumValue() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { AffineTransform transform; transform.translate(objectBoundingBox.x(), objectBoundingBox.y()); transform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height()); @@ -338,11 +341,11 @@ bool RenderSVGResourceClipper::hitTestClipContent(const FloatRect& objectBoundin point = clipPathElement->animatedLocalTransform().inverse().mapPoint(point); - for (Node* childNode = element()->firstChild(); childNode; childNode = childNode->nextSibling()) { - RenderObject* renderer = childNode->renderer(); - if (!childNode->isSVGElement() || !renderer) + for (SVGElement* childElement = Traversal<SVGElement>::firstChild(*element()); childElement; childElement = Traversal<SVGElement>::nextSibling(*childElement)) { + RenderObject* renderer = childElement->renderer(); + if (!renderer) continue; - if (!renderer->isSVGShape() && !renderer->isSVGText() && !childNode->hasTagName(SVGNames::useTag)) + if (!renderer->isSVGShape() && !renderer->isSVGText() && !isSVGUseElement(*childElement)) continue; IntPoint hitPoint; HitTestResult result(hitPoint); @@ -353,7 +356,7 @@ bool RenderSVGResourceClipper::hitTestClipContent(const FloatRect& objectBoundin return false; } -FloatRect RenderSVGResourceClipper::resourceBoundingBox(RenderObject* object) +FloatRect RenderSVGResourceClipper::resourceBoundingBox(const RenderObject* object) { // Resource was not layouted yet. Give back the boundingBox of the object. if (selfNeedsLayout()) @@ -362,7 +365,7 @@ FloatRect RenderSVGResourceClipper::resourceBoundingBox(RenderObject* object) if (m_clipBoundaries.isEmpty()) calculateClipContentRepaintRect(); - if (toSVGClipPathElement(element())->clipPathUnitsCurrentValue() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { + if (toSVGClipPathElement(element())->clipPathUnits()->currentValue()->enumValue() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { FloatRect objectBoundingBox = object->objectBoundingBox(); AffineTransform transform; transform.translate(objectBoundingBox.x(), objectBoundingBox.y()); diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceClipper.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceClipper.h index ae89b1e3df5..75a805859ff 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceClipper.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceClipper.h @@ -45,13 +45,13 @@ public: explicit RenderSVGResourceClipper(SVGClipPathElement*); virtual ~RenderSVGResourceClipper(); - virtual const char* renderName() const { return "RenderSVGResourceClipper"; } + virtual const char* renderName() const OVERRIDE { return "RenderSVGResourceClipper"; } - virtual void removeAllClientsFromCache(bool markForInvalidation = true); - virtual void removeClientFromCache(RenderObject*, bool markForInvalidation = true); + virtual void removeAllClientsFromCache(bool markForInvalidation = true) OVERRIDE; + virtual void removeClientFromCache(RenderObject*, bool markForInvalidation = true) OVERRIDE; - virtual bool applyResource(RenderObject*, RenderStyle*, GraphicsContext*&, unsigned short resourceMode) OVERRIDE FINAL; - virtual void postApplyResource(RenderObject*, GraphicsContext*&, unsigned short, const Path*, const RenderSVGShape*) OVERRIDE FINAL; + virtual bool applyResource(RenderObject*, RenderStyle*, GraphicsContext*&, unsigned short resourceMode) OVERRIDE; + virtual void postApplyResource(RenderObject*, GraphicsContext*&, unsigned short, const Path*, const RenderSVGShape*) OVERRIDE; // FIXME: Filters are also stateful resources that could benefit from having their state managed // on the caller stack instead of the current hashmap. We should look at refactoring these @@ -64,13 +64,13 @@ public: // FIXME: We made applyClippingToContext public because we cannot call applyResource on HTML elements (it asserts on RenderObject::objectBoundingBox) bool applyClippingToContext(RenderObject*, const FloatRect&, const FloatRect&, GraphicsContext*, ClipperContext&); - FloatRect resourceBoundingBox(RenderObject*); + FloatRect resourceBoundingBox(const RenderObject*); - virtual RenderSVGResourceType resourceType() const { return s_resourceType; } + virtual RenderSVGResourceType resourceType() const OVERRIDE { return s_resourceType; } bool hitTestClipContent(const FloatRect&, const FloatPoint&); - SVGUnitTypes::SVGUnitType clipPathUnits() const { return toSVGClipPathElement(element())->clipPathUnitsCurrentValue(); } + SVGUnitTypes::SVGUnitType clipPathUnits() const { return toSVGClipPathElement(element())->clipPathUnits()->currentValue()->enumValue(); } static const RenderSVGResourceType s_resourceType; private: diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceContainer.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceContainer.cpp index 55405a77a08..8434f4fe4ee 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceContainer.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceContainer.cpp @@ -21,7 +21,6 @@ #include "core/rendering/svg/RenderSVGResourceContainer.h" -#include "core/rendering/LayoutRectRecorder.h" #include "core/rendering/RenderLayer.h" #include "core/rendering/RenderView.h" #include "core/rendering/svg/SVGRenderingContext.h" @@ -32,7 +31,7 @@ namespace WebCore { -static inline SVGDocumentExtensions* svgExtensionsFromElement(SVGElement* element) +static inline SVGDocumentExtensions& svgExtensionsFromElement(SVGElement* element) { ASSERT(element); return element->document().accessSVGExtensions(); @@ -51,7 +50,7 @@ RenderSVGResourceContainer::RenderSVGResourceContainer(SVGElement* node) RenderSVGResourceContainer::~RenderSVGResourceContainer() { if (m_registered) - svgExtensionsFromElement(element())->removeResource(m_id); + svgExtensionsFromElement(element()).removeResource(m_id); } void RenderSVGResourceContainer::layout() @@ -62,7 +61,6 @@ void RenderSVGResourceContainer::layout() if (m_isInLayout) return; - LayoutRectRecorder recorder(*this); TemporaryChange<bool> inLayoutChange(m_isInLayout, true); RenderSVGHiddenContainer::layout(); @@ -92,8 +90,8 @@ void RenderSVGResourceContainer::idChanged() removeAllClientsFromCache(); // Remove old id, that is guaranteed to be present in cache. - SVGDocumentExtensions* extensions = svgExtensionsFromElement(element()); - extensions->removeResource(m_id); + SVGDocumentExtensions& extensions = svgExtensionsFromElement(element()); + extensions.removeResource(m_id); m_id = element()->getIdAttribute(); registerResource(); @@ -150,10 +148,10 @@ void RenderSVGResourceContainer::markClientForInvalidation(RenderObject* client, break; case RepaintInvalidation: if (client->view()) { - if (RuntimeEnabledFeatures::repaintAfterLayoutEnabled() && frameView()->isInLayout()) - client->setShouldDoFullRepaintAfterLayout(true); + if (RuntimeEnabledFeatures::repaintAfterLayoutEnabled() && frameView()->isInPerformLayout()) + client->setShouldDoFullPaintInvalidationAfterLayout(true); else - client->repaint(); + client->paintInvalidationForWholeRenderer(); } break; case ParentOnlyInvalidation: @@ -202,7 +200,7 @@ void RenderSVGResourceContainer::invalidateCacheAndMarkForLayout(SubtreeLayoutSc if (selfNeedsLayout()) return; - setNeedsLayout(MarkContainingBlockChain, layoutScope); + setNeedsLayoutAndFullPaintInvalidation(MarkContainingBlockChain, layoutScope); if (everHadLayout()) removeAllClientsFromCache(); @@ -210,33 +208,36 @@ void RenderSVGResourceContainer::invalidateCacheAndMarkForLayout(SubtreeLayoutSc void RenderSVGResourceContainer::registerResource() { - SVGDocumentExtensions* extensions = svgExtensionsFromElement(element()); - if (!extensions->hasPendingResource(m_id)) { - extensions->addResource(m_id, this); + SVGDocumentExtensions& extensions = svgExtensionsFromElement(element()); + if (!extensions.hasPendingResource(m_id)) { + extensions.addResource(m_id, this); return; } - OwnPtr<SVGDocumentExtensions::SVGPendingElements> clients(extensions->removePendingResource(m_id)); + OwnPtr<SVGDocumentExtensions::SVGPendingElements> clients(extensions.removePendingResource(m_id)); // Cache us with the new id. - extensions->addResource(m_id, this); + extensions.addResource(m_id, this); // Update cached resources of pending clients. const SVGDocumentExtensions::SVGPendingElements::const_iterator end = clients->end(); for (SVGDocumentExtensions::SVGPendingElements::const_iterator it = clients->begin(); it != end; ++it) { ASSERT((*it)->hasPendingResources()); - extensions->clearHasPendingResourcesIfPossible(*it); + extensions.clearHasPendingResourcesIfPossible(*it); RenderObject* renderer = (*it)->renderer(); if (!renderer) continue; - SVGResourcesCache::clientStyleChanged(renderer, StyleDifferenceLayout, renderer->style()); - renderer->setNeedsLayout(); + + StyleDifference diff; + diff.setNeedsFullLayout(); + SVGResourcesCache::clientStyleChanged(renderer, diff, renderer->style()); + renderer->setNeedsLayoutAndFullPaintInvalidation(); } } -bool RenderSVGResourceContainer::shouldTransformOnTextPainting(RenderObject* object, AffineTransform& resourceTransform) +static bool shouldTransformOnTextPainting(RenderObject* object, AffineTransform& resourceTransform) { - ASSERT_UNUSED(object, object); + ASSERT(object); // This method should only be called for RenderObjects that deal with text rendering. Cmp. RenderObject.h's is*() methods. ASSERT(object->isSVGText() || object->isSVGTextPath() || object->isSVGInline()); @@ -251,6 +252,26 @@ bool RenderSVGResourceContainer::shouldTransformOnTextPainting(RenderObject* obj return true; } +AffineTransform RenderSVGResourceContainer::computeResourceSpaceTransform(RenderObject* object, const AffineTransform& baseTransform, const SVGRenderStyle* svgStyle, unsigned short resourceMode) +{ + AffineTransform computedSpaceTransform = baseTransform; + if (resourceMode & ApplyToTextMode) { + // Depending on the font scaling factor, we may need to apply an + // additional transform (scale-factor) the paintserver, since text + // painting removes the scale factor from the context. (See + // SVGInlineTextBox::paintTextWithShadows.) + AffineTransform additionalTextTransformation; + if (shouldTransformOnTextPainting(object, additionalTextTransformation)) + computedSpaceTransform = additionalTextTransformation * computedSpaceTransform; + } + if (resourceMode & ApplyToStrokeMode) { + // Non-scaling stroke needs to reset the transform back to the host transform. + if (svgStyle->vectorEffect() == VE_NON_SCALING_STROKE) + computedSpaceTransform = transformOnNonScalingStroke(object, computedSpaceTransform); + } + return computedSpaceTransform; +} + // FIXME: This does not belong here. AffineTransform RenderSVGResourceContainer::transformOnNonScalingStroke(RenderObject* object, const AffineTransform& resourceTransform) { diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceContainer.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceContainer.h index 71d3c6f0cf1..52b50c394a3 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceContainer.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceContainer.h @@ -33,12 +33,11 @@ public: explicit RenderSVGResourceContainer(SVGElement*); virtual ~RenderSVGResourceContainer(); - virtual void layout(); + virtual void layout() OVERRIDE; virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) OVERRIDE FINAL; virtual bool isSVGResourceContainer() const OVERRIDE FINAL { return true; } - static bool shouldTransformOnTextPainting(RenderObject*, AffineTransform&); static AffineTransform transformOnNonScalingStroke(RenderObject*, const AffineTransform& resourceTransform); void idChanged(); @@ -64,6 +63,8 @@ protected: void clearInvalidationMask() { m_invalidationMask = 0; } + static AffineTransform computeResourceSpaceTransform(RenderObject*, const AffineTransform& baseTransform, const SVGRenderStyle*, unsigned short resourceMode); + bool m_isInLayout; private: @@ -86,21 +87,21 @@ private: HashSet<RenderLayer*> m_clientLayers; }; -inline RenderSVGResourceContainer* getRenderSVGResourceContainerById(Document& document, const AtomicString& id) +inline RenderSVGResourceContainer* getRenderSVGResourceContainerById(TreeScope& treeScope, const AtomicString& id) { if (id.isEmpty()) return 0; - if (RenderSVGResourceContainer* renderResource = document.accessSVGExtensions()->resourceById(id)) + if (RenderSVGResourceContainer* renderResource = treeScope.document().accessSVGExtensions().resourceById(id)) return renderResource; return 0; } template<typename Renderer> -Renderer* getRenderSVGResourceById(Document& document, const AtomicString& id) +Renderer* getRenderSVGResourceById(TreeScope& treeScope, const AtomicString& id) { - if (RenderSVGResourceContainer* container = getRenderSVGResourceContainerById(document, id)) + if (RenderSVGResourceContainer* container = getRenderSVGResourceContainerById(treeScope, id)) return container->cast<Renderer>(); return 0; diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceFilter.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceFilter.cpp index 840c563c4c2..80f0a30a0c2 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceFilter.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceFilter.cpp @@ -30,9 +30,9 @@ #include "core/rendering/svg/SVGRenderingContext.h" #include "core/svg/SVGFilterPrimitiveStandardAttributes.h" #include "platform/graphics/UnacceleratedImageBufferSurface.h" +#include "platform/graphics/filters/SkiaImageFilterBuilder.h" #include "platform/graphics/filters/SourceAlpha.h" #include "platform/graphics/filters/SourceGraphic.h" -#include "platform/graphics/gpu/AcceleratedImageBufferSurface.h" using namespace std; @@ -50,6 +50,11 @@ RenderSVGResourceFilter::~RenderSVGResourceFilter() m_filter.clear(); } +bool RenderSVGResourceFilter::isChildAllowed(RenderObject* child, RenderStyle*) const +{ + return child->isSVGResourceFilterPrimitive(); +} + void RenderSVGResourceFilter::removeAllClientsFromCache(bool markForInvalidation) { m_filter.clear(); @@ -77,11 +82,7 @@ PassRefPtr<SVGFilterBuilder> RenderSVGResourceFilter::buildPrimitives(SVGFilter* // Add effects to the builder RefPtr<SVGFilterBuilder> builder = SVGFilterBuilder::create(SourceGraphic::create(filter), SourceAlpha::create(filter)); - for (Node* node = filterElement->firstChild(); node; node = node->nextSibling()) { - if (!node->isSVGElement()) - continue; - - SVGElement* element = toSVGElement(node); + for (SVGElement* element = Traversal<SVGElement>::firstChild(*filterElement); element; element = Traversal<SVGElement>::nextSibling(*element)) { if (!element->isFilterEffect() || !element->renderer()) continue; @@ -89,46 +90,40 @@ PassRefPtr<SVGFilterBuilder> RenderSVGResourceFilter::buildPrimitives(SVGFilter* RefPtr<FilterEffect> effect = effectElement->build(builder.get(), filter); if (!effect) { builder->clearEffects(); - return 0; + return nullptr; } builder->appendEffectToEffectReferences(effect, effectElement->renderer()); effectElement->setStandardAttributes(effect.get()); - effect->setEffectBoundaries(SVGLengthContext::resolveRectangle<SVGFilterPrimitiveStandardAttributes>(effectElement, filterElement->primitiveUnitsCurrentValue(), targetBoundingBox)); + effect->setEffectBoundaries(SVGLengthContext::resolveRectangle<SVGFilterPrimitiveStandardAttributes>(effectElement, filterElement->primitiveUnits()->currentValue()->enumValue(), targetBoundingBox)); effect->setOperatingColorSpace( effectElement->renderer()->style()->svgStyle()->colorInterpolationFilters() == CI_LINEARRGB ? ColorSpaceLinearRGB : ColorSpaceDeviceRGB); - builder->add(effectElement->resultCurrentValue(), effect); + builder->add(AtomicString(effectElement->result()->currentValue()->value()), effect); } return builder.release(); } -bool RenderSVGResourceFilter::fitsInMaximumImageSize(const FloatSize& size, FloatSize& scale) +void RenderSVGResourceFilter::adjustScaleForMaximumImageSize(const FloatSize& size, FloatSize& filterScale) { - bool matchesFilterSize = true; - if (size.width() > kMaxFilterSize) { - scale.setWidth(scale.width() * kMaxFilterSize / size.width()); - matchesFilterSize = false; - } - if (size.height() > kMaxFilterSize) { - scale.setHeight(scale.height() * kMaxFilterSize / size.height()); - matchesFilterSize = false; - } + FloatSize scaledSize(size); + scaledSize.scale(filterScale.width(), filterScale.height()); + float scaledArea = scaledSize.width() * scaledSize.height(); + + if (scaledArea <= FilterEffect::maxFilterArea()) + return; - return matchesFilterSize; + // If area of scaled size is bigger than the upper limit, adjust the scale + // to fit. + filterScale.scale(sqrt(FilterEffect::maxFilterArea() / scaledArea)); } -static bool createImageBuffer(const FloatRect& targetRect, const AffineTransform& absoluteTransform, - OwnPtr<ImageBuffer>& imageBuffer, bool accelerated) +static bool createImageBuffer(const Filter* filter, OwnPtr<ImageBuffer>& imageBuffer) { - IntRect paintRect = SVGRenderingContext::calculateImageBufferRect(targetRect, absoluteTransform); + IntRect paintRect = filter->sourceImageRect(); // Don't create empty ImageBuffers. if (paintRect.isEmpty()) return false; - OwnPtr<ImageBufferSurface> surface; - if (accelerated) - surface = adoptPtr(new AcceleratedImageBufferSurface(paintRect.size())); - if (!accelerated || !surface->isValid()) - surface = adoptPtr(new UnacceleratedImageBufferSurface(paintRect.size())); + OwnPtr<ImageBufferSurface> surface = adoptPtr(new UnacceleratedImageBufferSurface(paintRect.size())); if (!surface->isValid()) return false; OwnPtr<ImageBuffer> image = ImageBuffer::create(surface.release()); @@ -137,12 +132,71 @@ static bool createImageBuffer(const FloatRect& targetRect, const AffineTransform ASSERT(imageContext); imageContext->translate(-paintRect.x(), -paintRect.y()); - imageContext->concatCTM(absoluteTransform); - + imageContext->concatCTM(filter->absoluteTransform()); imageBuffer = image.release(); return true; } +static void beginDeferredFilter(GraphicsContext* context, FilterData* filterData, SVGFilterElement* filterElement) +{ + SkiaImageFilterBuilder builder(context); + RefPtr<ImageFilter> imageFilter = builder.build(filterData->builder->lastEffect(), ColorSpaceDeviceRGB); + // FIXME: Remove the cache when impl-size painting is enabled on every platform and the non impl-side painting path is removed + if (!context->isRecordingCanvas()) // Recording canvases do not use the cache + filterData->filter->enableCache(); + FloatRect boundaries = enclosingIntRect(filterData->boundaries); + context->save(); + float scaledArea = boundaries.width() * boundaries.height(); + + // If area of scaled size is bigger than the upper limit, adjust the scale + // to fit. + if (scaledArea > FilterEffect::maxFilterArea()) { + float scale = sqrtf(FilterEffect::maxFilterArea() / scaledArea); + context->scale(scale, scale); + } + // Clip drawing of filtered image to primitive boundaries. + context->clipRect(boundaries); + if (filterElement->hasAttribute(SVGNames::filterResAttr)) { + // Get boundaries in device coords. + // FIXME: See crbug.com/382491. Is the use of getCTM OK here, given it does not include device + // zoom or High DPI adjustments? + FloatSize size = context->getCTM().mapSize(boundaries.size()); + // Compute the scale amount required so that the resulting offscreen is exactly filterResX by filterResY pixels. + float filterResScaleX = filterElement->filterResX()->currentValue()->value() / size.width(); + float filterResScaleY = filterElement->filterResY()->currentValue()->value() / size.height(); + // Scale the CTM so the primitive is drawn to filterRes. + context->scale(filterResScaleX, filterResScaleY); + // Create a resize filter with the inverse scale. + AffineTransform resizeMatrix; + resizeMatrix.scale(1 / filterResScaleX, 1 / filterResScaleY); + imageFilter = builder.buildTransform(resizeMatrix, imageFilter.get()); + } + // If the CTM contains rotation or shearing, apply the filter to + // the unsheared/unrotated matrix, and do the shearing/rotation + // as a final pass. + AffineTransform ctm = context->getCTM(); + if (ctm.b() || ctm.c()) { + AffineTransform scaleAndTranslate; + scaleAndTranslate.translate(ctm.e(), ctm.f()); + scaleAndTranslate.scale(ctm.xScale(), ctm.yScale()); + ASSERT(scaleAndTranslate.isInvertible()); + AffineTransform shearAndRotate = scaleAndTranslate.inverse(); + shearAndRotate.multiply(ctm); + context->setCTM(scaleAndTranslate); + imageFilter = builder.buildTransform(shearAndRotate, imageFilter.get()); + } + context->beginLayer(1, CompositeSourceOver, &boundaries, ColorFilterNone, imageFilter.get()); +} + +static void endDeferredFilter(GraphicsContext* context, FilterData* filterData) +{ + context->endLayer(); + context->restore(); + // FIXME: Remove the cache when impl-size painting is enabled on every platform and the non impl-side painting path is removed + if (!context->isRecordingCanvas()) // Recording canvases do not use the cache + filterData->filter->disableCache(); +} + bool RenderSVGResourceFilter::applyResource(RenderObject* object, RenderStyle*, GraphicsContext*& context, unsigned short resourceMode) { ASSERT(object); @@ -151,10 +205,16 @@ bool RenderSVGResourceFilter::applyResource(RenderObject* object, RenderStyle*, clearInvalidationMask(); + bool deferredFiltersEnabled = object->document().settings()->deferredFiltersEnabled(); if (m_filter.contains(object)) { FilterData* filterData = m_filter.get(object); if (filterData->state == FilterData::PaintingSource || filterData->state == FilterData::Applying) filterData->state = FilterData::CycleDetected; + if (deferredFiltersEnabled && filterData->state == FilterData::Built) { + SVGFilterElement* filterElement = toSVGFilterElement(element()); + beginDeferredFilter(context, filterData, filterElement); + return true; + } return false; // Already built, or we're in a cycle, or we're marked for removal. Regardless, just do nothing more now. } @@ -162,64 +222,65 @@ bool RenderSVGResourceFilter::applyResource(RenderObject* object, RenderStyle*, FloatRect targetBoundingBox = object->objectBoundingBox(); SVGFilterElement* filterElement = toSVGFilterElement(element()); - filterData->boundaries = SVGLengthContext::resolveRectangle<SVGFilterElement>(filterElement, filterElement->filterUnitsCurrentValue(), targetBoundingBox); + filterData->boundaries = SVGLengthContext::resolveRectangle<SVGFilterElement>(filterElement, filterElement->filterUnits()->currentValue()->enumValue(), targetBoundingBox); if (filterData->boundaries.isEmpty()) return false; // Determine absolute transformation matrix for filter. AffineTransform absoluteTransform; - SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(object, absoluteTransform); + SVGRenderingContext::calculateDeviceSpaceTransformation(object, absoluteTransform); if (!absoluteTransform.isInvertible()) return false; - // Eliminate shear of the absolute transformation matrix, to be able to produce unsheared tile images for feTile. - filterData->shearFreeAbsoluteTransform = AffineTransform(absoluteTransform.xScale(), 0, 0, absoluteTransform.yScale(), 0, 0); + // Filters cannot handle a full transformation, only scales in each direction. + FloatSize filterScale; + + // Calculate the scale factor for the filter. + // Also see http://www.w3.org/TR/SVG/filters.html#FilterEffectsRegion + if (filterElement->hasAttribute(SVGNames::filterResAttr)) { + // If resolution is specified, scale to match it. + filterScale = FloatSize( + filterElement->filterResX()->currentValue()->value() / filterData->boundaries.width(), + filterElement->filterResY()->currentValue()->value() / filterData->boundaries.height()); + } else { + // Otherwise, use the scale of the absolute transform. + filterScale = FloatSize(absoluteTransform.xScale(), absoluteTransform.yScale()); + } + // The size of the scaled filter boundaries shouldn't be bigger than kMaxFilterSize. + // Intermediate filters are limited by the filter boundaries so they can't be bigger than this. + adjustScaleForMaximumImageSize(filterData->boundaries.size(), filterScale); - // Determine absolute boundaries of the filter and the drawing region. - FloatRect absoluteFilterBoundaries = filterData->shearFreeAbsoluteTransform.mapRect(filterData->boundaries); filterData->drawingRegion = object->strokeBoundingBox(); filterData->drawingRegion.intersect(filterData->boundaries); - FloatRect absoluteDrawingRegion = filterData->shearFreeAbsoluteTransform.mapRect(filterData->drawingRegion); + FloatRect absoluteDrawingRegion = filterData->drawingRegion; + if (!deferredFiltersEnabled) + absoluteDrawingRegion.scale(filterScale.width(), filterScale.height()); + + IntRect intDrawingRegion = enclosingIntRect(absoluteDrawingRegion); // Create the SVGFilter object. - bool primitiveBoundingBoxMode = filterElement->primitiveUnitsCurrentValue() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX; - filterData->filter = SVGFilter::create(filterData->shearFreeAbsoluteTransform, absoluteDrawingRegion, targetBoundingBox, filterData->boundaries, primitiveBoundingBoxMode); + bool primitiveBoundingBoxMode = filterElement->primitiveUnits()->currentValue()->enumValue() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX; + filterData->shearFreeAbsoluteTransform = AffineTransform(); + if (!deferredFiltersEnabled) + filterData->shearFreeAbsoluteTransform.scale(filterScale.width(), filterScale.height()); + filterData->filter = SVGFilter::create(filterData->shearFreeAbsoluteTransform, intDrawingRegion, targetBoundingBox, filterData->boundaries, primitiveBoundingBoxMode); // Create all relevant filter primitives. filterData->builder = buildPrimitives(filterData->filter.get()); if (!filterData->builder) return false; - // Calculate the scale factor for the use of filterRes. - // Also see http://www.w3.org/TR/SVG/filters.html#FilterEffectsRegion - FloatSize scale(1, 1); - if (filterElement->hasAttribute(SVGNames::filterResAttr)) { - scale.setWidth(filterElement->filterResXCurrentValue() / absoluteFilterBoundaries.width()); - scale.setHeight(filterElement->filterResYCurrentValue() / absoluteFilterBoundaries.height()); - } - - if (scale.isEmpty()) - return false; - - // Determine scale factor for filter. The size of intermediate ImageBuffers shouldn't be bigger than kMaxFilterSize. - FloatRect tempSourceRect = absoluteDrawingRegion; - tempSourceRect.scale(scale.width(), scale.height()); - fitsInMaximumImageSize(tempSourceRect.size(), scale); - - // Set the scale level in SVGFilter. - filterData->filter->setFilterResolution(scale); - FilterEffect* lastEffect = filterData->builder->lastEffect(); if (!lastEffect) return false; lastEffect->determineFilterPrimitiveSubregion(ClipToFilterRegion); - FloatRect subRegion = lastEffect->maxEffectRect(); - // At least one FilterEffect has a too big image size, - // recalculate the effect sizes with new scale factors. - if (!fitsInMaximumImageSize(subRegion.size(), scale)) { - filterData->filter->setFilterResolution(scale); - lastEffect->determineFilterPrimitiveSubregion(ClipToFilterRegion); + + if (deferredFiltersEnabled) { + FilterData* data = filterData.get(); + m_filter.set(object, filterData.release()); + beginDeferredFilter(context, data, filterElement); + return true; } // If the drawingRegion is empty, we have something like <g filter=".."/>. @@ -231,23 +292,14 @@ bool RenderSVGResourceFilter::applyResource(RenderObject* object, RenderStyle*, return false; } - // Change the coordinate transformation applied to the filtered element to reflect the resolution of the filter. - AffineTransform effectiveTransform; - effectiveTransform.scale(scale.width(), scale.height()); - effectiveTransform.multiply(filterData->shearFreeAbsoluteTransform); - OwnPtr<ImageBuffer> sourceGraphic; - bool isAccelerated = object->document().settings()->acceleratedFiltersEnabled(); - if (!createImageBuffer(filterData->drawingRegion, effectiveTransform, sourceGraphic, isAccelerated)) { + if (!createImageBuffer(filterData->filter.get(), sourceGraphic)) { ASSERT(!m_filter.contains(object)); filterData->savedContext = context; m_filter.set(object, filterData.release()); return false; } - // Set the rendering mode from the page's settings. - filterData->filter->setIsAccelerated(isAccelerated); - GraphicsContext* sourceGraphicContext = sourceGraphic->context(); ASSERT(sourceGraphicContext); @@ -272,6 +324,12 @@ void RenderSVGResourceFilter::postApplyResource(RenderObject* object, GraphicsCo if (!filterData) return; + if (object->document().settings()->deferredFiltersEnabled() && (filterData->state == FilterData::PaintingSource || filterData->state == FilterData::Built)) { + endDeferredFilter(context, filterData); + filterData->state = FilterData::Built; + return; + } + switch (filterData->state) { case FilterData::MarkedForRemoval: m_filter.remove(object); @@ -319,22 +377,16 @@ void RenderSVGResourceFilter::postApplyResource(RenderObject* object, GraphicsCo ImageBuffer* resultImage = lastEffect->asImageBuffer(); if (resultImage) { - context->concatCTM(filterData->shearFreeAbsoluteTransform.inverse()); - - context->scale(FloatSize(1 / filterData->filter->filterResolution().width(), 1 / filterData->filter->filterResolution().height())); - context->drawImageBuffer(resultImage, lastEffect->absolutePaintRect()); - context->scale(filterData->filter->filterResolution()); - - context->concatCTM(filterData->shearFreeAbsoluteTransform); + context->drawImageBuffer(resultImage, filterData->filter->mapAbsoluteRectToLocalRect(lastEffect->absolutePaintRect())); } } filterData->sourceGraphicBuffer.clear(); } -FloatRect RenderSVGResourceFilter::resourceBoundingBox(RenderObject* object) +FloatRect RenderSVGResourceFilter::resourceBoundingBox(const RenderObject* object) { if (SVGFilterElement* element = toSVGFilterElement(this->element())) - return SVGLengthContext::resolveRectangle<SVGFilterElement>(element, element->filterUnitsCurrentValue(), object->objectBoundingBox()); + return SVGLengthContext::resolveRectangle<SVGFilterElement>(element, element->filterUnits()->currentValue()->enumValue(), object->objectBoundingBox()); return FloatRect(); } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceFilter.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceFilter.h index 6455b039284..1c679130ccc 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceFilter.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceFilter.h @@ -60,30 +60,32 @@ public: explicit RenderSVGResourceFilter(SVGFilterElement*); virtual ~RenderSVGResourceFilter(); - virtual const char* renderName() const { return "RenderSVGResourceFilter"; } + virtual bool isChildAllowed(RenderObject*, RenderStyle*) const OVERRIDE; + + virtual const char* renderName() const OVERRIDE { return "RenderSVGResourceFilter"; } virtual bool isSVGResourceFilter() const OVERRIDE { return true; } - virtual void removeAllClientsFromCache(bool markForInvalidation = true); - virtual void removeClientFromCache(RenderObject*, bool markForInvalidation = true); + virtual void removeAllClientsFromCache(bool markForInvalidation = true) OVERRIDE; + virtual void removeClientFromCache(RenderObject*, bool markForInvalidation = true) OVERRIDE; - virtual bool applyResource(RenderObject*, RenderStyle*, GraphicsContext*&, unsigned short resourceMode); - virtual void postApplyResource(RenderObject*, GraphicsContext*&, unsigned short resourceMode, const Path*, const RenderSVGShape*); + virtual bool applyResource(RenderObject*, RenderStyle*, GraphicsContext*&, unsigned short resourceMode) OVERRIDE; + virtual void postApplyResource(RenderObject*, GraphicsContext*&, unsigned short resourceMode, const Path*, const RenderSVGShape*) OVERRIDE; - FloatRect resourceBoundingBox(RenderObject*); + FloatRect resourceBoundingBox(const RenderObject*); PassRefPtr<SVGFilterBuilder> buildPrimitives(SVGFilter*); - SVGUnitTypes::SVGUnitType filterUnits() const { return toSVGFilterElement(element())->filterUnitsCurrentValue(); } - SVGUnitTypes::SVGUnitType primitiveUnits() const { return toSVGFilterElement(element())->primitiveUnitsCurrentValue(); } + SVGUnitTypes::SVGUnitType filterUnits() const { return toSVGFilterElement(element())->filterUnits()->currentValue()->enumValue(); } + SVGUnitTypes::SVGUnitType primitiveUnits() const { return toSVGFilterElement(element())->primitiveUnits()->currentValue()->enumValue(); } void primitiveAttributeChanged(RenderObject*, const QualifiedName&); - virtual RenderSVGResourceType resourceType() const { return s_resourceType; } + virtual RenderSVGResourceType resourceType() const OVERRIDE { return s_resourceType; } static const RenderSVGResourceType s_resourceType; FloatRect drawingRegion(RenderObject*) const; private: - bool fitsInMaximumImageSize(const FloatSize&, FloatSize&); + void adjustScaleForMaximumImageSize(const FloatSize&, FloatSize&); typedef HashMap<RenderObject*, OwnPtr<FilterData> > FilterMap; FilterMap m_filter; diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceFilterPrimitive.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceFilterPrimitive.cpp index e34449d35ea..f7fce429304 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceFilterPrimitive.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceFilterPrimitive.cpp @@ -40,16 +40,17 @@ void RenderSVGResourceFilterPrimitive::styleDidChange(StyleDifference diff, cons return; ASSERT(filter->isSVGResourceFilter()); - if (diff == StyleDifferenceEqual || !oldStyle) + if (diff.hasNoChange() || !oldStyle) return; const SVGRenderStyle* newStyle = this->style()->svgStyle(); - if (element()->hasTagName(SVGNames::feFloodTag)) { + ASSERT(element()); + if (isSVGFEFloodElement(*element())) { if (newStyle->floodColor() != oldStyle->svgStyle()->floodColor()) toRenderSVGResourceFilter(filter)->primitiveAttributeChanged(this, SVGNames::flood_colorAttr); if (newStyle->floodOpacity() != oldStyle->svgStyle()->floodOpacity()) toRenderSVGResourceFilter(filter)->primitiveAttributeChanged(this, SVGNames::flood_opacityAttr); - } else if (element()->hasTagName(SVGNames::feDiffuseLightingTag) || element()->hasTagName(SVGNames::feSpecularLightingTag)) { + } else if (isSVGFEDiffuseLightingElement(*element()) || isSVGFESpecularLightingElement(*element())) { if (newStyle->lightingColor() != oldStyle->svgStyle()->lightingColor()) toRenderSVGResourceFilter(filter)->primitiveAttributeChanged(this, SVGNames::lighting_colorAttr); } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceFilterPrimitive.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceFilterPrimitive.h index 704df3d4075..b2a293d68fe 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceFilterPrimitive.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceFilterPrimitive.h @@ -38,10 +38,12 @@ public: { } - virtual void styleDidChange(StyleDifference, const RenderStyle*); + virtual bool isChildAllowed(RenderObject*, RenderStyle*) const OVERRIDE { return false; } - virtual const char* renderName() const { return "RenderSVGResourceFilterPrimitive"; } - virtual bool isSVGResourceFilterPrimitive() const { return true; } + virtual void styleDidChange(StyleDifference, const RenderStyle*) OVERRIDE; + + virtual const char* renderName() const OVERRIDE { return "RenderSVGResourceFilterPrimitive"; } + virtual bool isSVGResourceFilterPrimitive() const OVERRIDE { return true; } inline void primitiveAttributeChanged(const QualifiedName& attribute) { diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceGradient.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceGradient.cpp index 4e432a56082..6f44a65b116 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceGradient.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceGradient.cpp @@ -81,12 +81,10 @@ bool RenderSVGResourceGradient::applyResource(RenderObject* object, RenderStyle* if (gradientUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX && objectBoundingBox.isEmpty()) return false; - OwnPtr<GradientData>& gradientData = m_gradientMap.add(object, nullptr).iterator->value; + OwnPtr<GradientData>& gradientData = m_gradientMap.add(object, nullptr).storedValue->value; if (!gradientData) gradientData = adoptPtr(new GradientData); - bool isPaintingText = resourceMode & ApplyToTextMode; - // Create gradient object if (!gradientData->gradient) { buildGradient(gradientData.get()); @@ -101,36 +99,29 @@ bool RenderSVGResourceGradient::applyResource(RenderObject* object, RenderStyle* calculateGradientTransform(gradientTransform); gradientData->userspaceTransform *= gradientTransform; - if (isPaintingText) { - // Depending on font scaling factor, we may need to rescale the gradient here since - // text painting removes the scale factor from the context. - AffineTransform additionalTextTransform; - if (shouldTransformOnTextPainting(object, additionalTextTransform)) - gradientData->userspaceTransform *= additionalTextTransform; - } - gradientData->gradient->setGradientSpaceTransform(gradientData->userspaceTransform); } if (!gradientData->gradient) return false; + const SVGRenderStyle* svgStyle = style->svgStyle(); + ASSERT(svgStyle); + + AffineTransform computedGradientSpaceTransform = computeResourceSpaceTransform(object, gradientData->userspaceTransform, svgStyle, resourceMode); + gradientData->gradient->setGradientSpaceTransform(computedGradientSpaceTransform); + // Draw gradient context->save(); - if (isPaintingText) + if (resourceMode & ApplyToTextMode) context->setTextDrawingMode(resourceMode & ApplyToFillMode ? TextModeFill : TextModeStroke); - const SVGRenderStyle* svgStyle = style->svgStyle(); - ASSERT(svgStyle); - if (resourceMode & ApplyToFillMode) { - context->setAlpha(svgStyle->fillOpacity()); + context->setAlphaAsFloat(svgStyle->fillOpacity()); context->setFillGradient(gradientData->gradient); context->setFillRule(svgStyle->fillRule()); } else if (resourceMode & ApplyToStrokeMode) { - if (svgStyle->vectorEffect() == VE_NON_SCALING_STROKE) - gradientData->gradient->setGradientSpaceTransform(transformOnNonScalingStroke(object, gradientData->userspaceTransform)); - context->setAlpha(svgStyle->strokeOpacity()); + context->setAlphaAsFloat(svgStyle->strokeOpacity()); context->setStrokeGradient(gradientData->gradient); SVGRenderSupport::applyStrokeStyleToContext(context, style, object); } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceLinearGradient.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceLinearGradient.h index ba1c3d27884..b829e403004 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceLinearGradient.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceLinearGradient.h @@ -33,15 +33,15 @@ public: explicit RenderSVGResourceLinearGradient(SVGLinearGradientElement*); virtual ~RenderSVGResourceLinearGradient(); - virtual const char* renderName() const { return "RenderSVGResourceLinearGradient"; } + virtual const char* renderName() const OVERRIDE { return "RenderSVGResourceLinearGradient"; } - virtual RenderSVGResourceType resourceType() const { return s_resourceType; } + virtual RenderSVGResourceType resourceType() const OVERRIDE { return s_resourceType; } static const RenderSVGResourceType s_resourceType; - virtual SVGUnitTypes::SVGUnitType gradientUnits() const { return m_attributes.gradientUnits(); } - virtual void calculateGradientTransform(AffineTransform& transform) { transform = m_attributes.gradientTransform(); } - virtual bool collectGradientAttributes(SVGGradientElement*); - virtual void buildGradient(GradientData*) const; + virtual SVGUnitTypes::SVGUnitType gradientUnits() const OVERRIDE { return m_attributes.gradientUnits(); } + virtual void calculateGradientTransform(AffineTransform& transform) OVERRIDE { transform = m_attributes.gradientTransform(); } + virtual bool collectGradientAttributes(SVGGradientElement*) OVERRIDE; + virtual void buildGradient(GradientData*) const OVERRIDE; FloatPoint startPoint(const LinearGradientAttributes&) const; FloatPoint endPoint(const LinearGradientAttributes&) const; diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceMarker.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceMarker.cpp index d3de3b7cc64..be93b479b2d 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceMarker.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceMarker.cpp @@ -23,7 +23,7 @@ #include "core/rendering/svg/RenderSVGResourceMarker.h" -#include "core/rendering/LayoutRectRecorder.h" +#include "core/rendering/PaintInfo.h" #include "core/rendering/svg/RenderSVGContainer.h" #include "core/rendering/svg/SVGRenderSupport.h" #include "platform/graphics/GraphicsContextStateSaver.h" @@ -49,13 +49,8 @@ void RenderSVGResourceMarker::layout() if (m_isInLayout) return; - LayoutRectRecorder recorder(*this); TemporaryChange<bool> inLayoutChange(m_isInLayout, true); - // Invalidate all resources if our layout changed. - if (everHadLayout() && selfNeedsLayout()) - removeAllClientsFromCache(); - // RenderSVGHiddenContainer overwrites layout(). We need the // layouting of RenderSVGContainer for calculating local // transformations and repaint. @@ -83,7 +78,7 @@ void RenderSVGResourceMarker::applyViewportClip(PaintInfo& paintInfo) FloatRect RenderSVGResourceMarker::markerBoundaries(const AffineTransform& markerTransformation) const { - FloatRect coordinates = RenderSVGContainer::repaintRectInLocalCoordinates(); + FloatRect coordinates = RenderSVGContainer::paintInvalidationRectInLocalCoordinates(); // Map repaint rect into parent coordinate space, in which the marker boundaries have to be evaluated coordinates = localToParentTransform().mapRect(coordinates); @@ -105,7 +100,7 @@ FloatPoint RenderSVGResourceMarker::referencePoint() const ASSERT(marker); SVGLengthContext lengthContext(marker); - return FloatPoint(marker->refXCurrentValue().value(lengthContext), marker->refYCurrentValue().value(lengthContext)); + return FloatPoint(marker->refX()->currentValue()->value(lengthContext), marker->refY()->currentValue()->value(lengthContext)); } float RenderSVGResourceMarker::angle() const @@ -114,8 +109,8 @@ float RenderSVGResourceMarker::angle() const ASSERT(marker); float angle = -1; - if (marker->orientTypeCurrentValue() == SVGMarkerOrientAngle) - angle = marker->orientAngleCurrentValue().value(); + if (marker->orientType()->currentValue()->enumValue() == SVGMarkerOrientAngle) + angle = marker->orientAngle()->currentValue()->value(); return angle; } @@ -126,7 +121,7 @@ AffineTransform RenderSVGResourceMarker::markerTransformation(const FloatPoint& ASSERT(marker); float markerAngle = angle(); - bool useStrokeWidth = marker->markerUnitsCurrentValue() == SVGMarkerUnitsStrokeWidth; + bool useStrokeWidth = marker->markerUnits()->currentValue()->enumValue() == SVGMarkerUnitsStrokeWidth; AffineTransform transform; transform.translate(origin.x(), origin.y()); @@ -142,12 +137,15 @@ void RenderSVGResourceMarker::draw(PaintInfo& paintInfo, const AffineTransform& // An empty viewBox disables rendering. SVGMarkerElement* marker = toSVGMarkerElement(element()); ASSERT(marker); - if (marker->hasAttribute(SVGNames::viewBoxAttr) && marker->viewBoxCurrentValue().isValid() && marker->viewBoxCurrentValue().isEmpty()) + if (marker->hasAttribute(SVGNames::viewBoxAttr) && marker->viewBox()->currentValue()->isValid() && marker->viewBox()->currentValue()->value().isEmpty()) return; PaintInfo info(paintInfo); - GraphicsContextStateSaver stateSaver(*info.context); - info.applyTransform(transform); + GraphicsContextStateSaver stateSaver(*info.context, false); + if (!transform.isIdentity()) { + stateSaver.save(); + info.applyTransform(transform, false); + } RenderSVGContainer::paint(info, IntPoint()); } @@ -181,8 +179,8 @@ void RenderSVGResourceMarker::calcViewport() ASSERT(marker); SVGLengthContext lengthContext(marker); - float w = marker->markerWidthCurrentValue().value(lengthContext); - float h = marker->markerHeightCurrentValue().value(lengthContext); + float w = marker->markerWidth()->currentValue()->value(lengthContext); + float h = marker->markerHeight()->currentValue()->value(lengthContext); m_viewport = FloatRect(0, 0, w, h); } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceMarker.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceMarker.h index 625b37a652a..ba31fb21e45 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceMarker.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceMarker.h @@ -28,7 +28,6 @@ namespace WebCore { -class AffineTransform; class RenderObject; class RenderSVGResourceMarker FINAL : public RenderSVGResourceContainer { @@ -36,30 +35,30 @@ public: explicit RenderSVGResourceMarker(SVGMarkerElement*); virtual ~RenderSVGResourceMarker(); - virtual const char* renderName() const { return "RenderSVGResourceMarker"; } + virtual const char* renderName() const OVERRIDE { return "RenderSVGResourceMarker"; } - virtual void removeAllClientsFromCache(bool markForInvalidation = true); - virtual void removeClientFromCache(RenderObject*, bool markForInvalidation = true); + virtual void removeAllClientsFromCache(bool markForInvalidation = true) OVERRIDE; + virtual void removeClientFromCache(RenderObject*, bool markForInvalidation = true) OVERRIDE; void draw(PaintInfo&, const AffineTransform&); // Calculates marker boundaries, mapped to the target element's coordinate space FloatRect markerBoundaries(const AffineTransform& markerTransformation) const; - virtual void applyViewportClip(PaintInfo&); - virtual void layout(); - virtual void calcViewport(); + virtual void applyViewportClip(PaintInfo&) OVERRIDE; + virtual void layout() OVERRIDE; + virtual void calcViewport() OVERRIDE; - virtual const AffineTransform& localToParentTransform() const; + virtual const AffineTransform& localToParentTransform() const OVERRIDE; AffineTransform markerTransformation(const FloatPoint& origin, float angle, float strokeWidth) const; - virtual bool applyResource(RenderObject*, RenderStyle*, GraphicsContext*&, unsigned short) { return false; } + virtual bool applyResource(RenderObject*, RenderStyle*, GraphicsContext*&, unsigned short) OVERRIDE { return false; } FloatPoint referencePoint() const; float angle() const; - SVGMarkerUnitsType markerUnits() const { return toSVGMarkerElement(element())->markerUnitsCurrentValue(); } + SVGMarkerUnitsType markerUnits() const { return toSVGMarkerElement(element())->markerUnits()->currentValue()->enumValue(); } - virtual RenderSVGResourceType resourceType() const { return s_resourceType; } + virtual RenderSVGResourceType resourceType() const OVERRIDE { return s_resourceType; } static const RenderSVGResourceType s_resourceType; private: diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceMasker.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceMasker.cpp index 43c64ca081d..98a6d4c7639 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceMasker.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceMasker.cpp @@ -66,8 +66,8 @@ bool RenderSVGResourceMasker::applyResource(RenderObject* object, RenderStyle*, clearInvalidationMask(); - FloatRect repaintRect = object->repaintRectInLocalCoordinates(); - if (repaintRect.isEmpty() || !element()->hasChildNodes()) + FloatRect repaintRect = object->paintInvalidationRectInLocalCoordinates(); + if (repaintRect.isEmpty() || !element()->hasChildren()) return false; // Content layer start. @@ -85,7 +85,7 @@ void RenderSVGResourceMasker::postApplyResource(RenderObject* object, GraphicsCo ASSERT_UNUSED(resourceMode, resourceMode == ApplyToDefaultMode); ASSERT_WITH_SECURITY_IMPLICATION(!needsLayout()); - FloatRect repaintRect = object->repaintRectInLocalCoordinates(); + FloatRect repaintRect = object->paintInvalidationRectInLocalCoordinates(); const SVGRenderStyle* svgStyle = style()->svgStyle(); ASSERT(svgStyle); @@ -115,7 +115,7 @@ void RenderSVGResourceMasker::drawMaskForRenderer(GraphicsContext* context, cons ASSERT(context); AffineTransform contentTransformation; - SVGUnitTypes::SVGUnitType contentUnits = toSVGMaskElement(element())->maskContentUnitsCurrentValue(); + SVGUnitTypes::SVGUnitType contentUnits = toSVGMaskElement(element())->maskContentUnits()->currentValue()->enumValue(); if (contentUnits == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { contentTransformation.translate(targetBoundingBox.x(), targetBoundingBox.y()); contentTransformation.scaleNonUniform(targetBoundingBox.width(), targetBoundingBox.height()); @@ -133,10 +133,13 @@ PassRefPtr<DisplayList> RenderSVGResourceMasker::asDisplayList(GraphicsContext* { ASSERT(context); - context->beginRecording(repaintRectInLocalCoordinates()); - for (Node* childNode = element()->firstChild(); childNode; childNode = childNode->nextSibling()) { - RenderObject* renderer = childNode->renderer(); - if (!childNode->isSVGElement() || !renderer) + // Using strokeBoundingBox (instead of paintInvalidationRectInLocalCoordinates) to avoid the intersection + // with local clips/mask, which may yield incorrect results when mixing objectBoundingBox and + // userSpaceOnUse units (http://crbug.com/294900). + context->beginRecording(strokeBoundingBox()); + for (Element* childElement = ElementTraversal::firstWithin(*element()); childElement; childElement = ElementTraversal::nextSibling(*childElement)) { + RenderObject* renderer = childElement->renderer(); + if (!childElement->isSVGElement() || !renderer) continue; RenderStyle* style = renderer->style(); if (!style || style->display() == NONE || style->visibility() != VISIBLE) @@ -150,24 +153,24 @@ PassRefPtr<DisplayList> RenderSVGResourceMasker::asDisplayList(GraphicsContext* void RenderSVGResourceMasker::calculateMaskContentRepaintRect() { - for (Node* childNode = element()->firstChild(); childNode; childNode = childNode->nextSibling()) { - RenderObject* renderer = childNode->renderer(); - if (!childNode->isSVGElement() || !renderer) + for (SVGElement* childElement = Traversal<SVGElement>::firstChild(*element()); childElement; childElement = Traversal<SVGElement>::nextSibling(*childElement)) { + RenderObject* renderer = childElement->renderer(); + if (!renderer) continue; RenderStyle* style = renderer->style(); if (!style || style->display() == NONE || style->visibility() != VISIBLE) continue; - m_maskContentBoundaries.unite(renderer->localToParentTransform().mapRect(renderer->repaintRectInLocalCoordinates())); + m_maskContentBoundaries.unite(renderer->localToParentTransform().mapRect(renderer->paintInvalidationRectInLocalCoordinates())); } } -FloatRect RenderSVGResourceMasker::resourceBoundingBox(RenderObject* object) +FloatRect RenderSVGResourceMasker::resourceBoundingBox(const RenderObject* object) { SVGMaskElement* maskElement = toSVGMaskElement(element()); ASSERT(maskElement); FloatRect objectBoundingBox = object->objectBoundingBox(); - FloatRect maskBoundaries = SVGLengthContext::resolveRectangle<SVGMaskElement>(maskElement, maskElement->maskUnitsCurrentValue(), objectBoundingBox); + FloatRect maskBoundaries = SVGLengthContext::resolveRectangle<SVGMaskElement>(maskElement, maskElement->maskUnits()->currentValue()->enumValue(), objectBoundingBox); // Resource was not layouted yet. Give back clipping rect of the mask. if (selfNeedsLayout()) @@ -177,7 +180,7 @@ FloatRect RenderSVGResourceMasker::resourceBoundingBox(RenderObject* object) calculateMaskContentRepaintRect(); FloatRect maskRect = m_maskContentBoundaries; - if (maskElement->maskContentUnitsCurrentValue() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { + if (maskElement->maskContentUnits()->currentValue()->value() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { AffineTransform transform; transform.translate(objectBoundingBox.x(), objectBoundingBox.y()); transform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height()); diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceMasker.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceMasker.h index 2af52752127..e05fc0d9b95 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceMasker.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceMasker.h @@ -25,7 +25,6 @@ #include "core/svg/SVGUnitTypes.h" #include "platform/geometry/FloatRect.h" #include "platform/geometry/IntSize.h" -#include "platform/graphics/GraphicsContext.h" #include "platform/graphics/ImageBuffer.h" #include "wtf/HashMap.h" @@ -34,24 +33,25 @@ namespace WebCore { class DisplayList; +class GraphicsContext; class RenderSVGResourceMasker FINAL : public RenderSVGResourceContainer { public: explicit RenderSVGResourceMasker(SVGMaskElement*); virtual ~RenderSVGResourceMasker(); - virtual const char* renderName() const { return "RenderSVGResourceMasker"; } + virtual const char* renderName() const OVERRIDE { return "RenderSVGResourceMasker"; } - virtual void removeAllClientsFromCache(bool markForInvalidation = true); - virtual void removeClientFromCache(RenderObject*, bool markForInvalidation = true); + virtual void removeAllClientsFromCache(bool markForInvalidation = true) OVERRIDE; + virtual void removeClientFromCache(RenderObject*, bool markForInvalidation = true) OVERRIDE; virtual bool applyResource(RenderObject*, RenderStyle*, GraphicsContext*&, unsigned short resourceMode) OVERRIDE; virtual void postApplyResource(RenderObject*, GraphicsContext*&, unsigned short, const Path*, const RenderSVGShape*) OVERRIDE; - FloatRect resourceBoundingBox(RenderObject*); + FloatRect resourceBoundingBox(const RenderObject*); - SVGUnitTypes::SVGUnitType maskUnits() const { return toSVGMaskElement(element())->maskUnitsCurrentValue(); } - SVGUnitTypes::SVGUnitType maskContentUnits() const { return toSVGMaskElement(element())->maskContentUnitsCurrentValue(); } + SVGUnitTypes::SVGUnitType maskUnits() const { return toSVGMaskElement(element())->maskUnits()->currentValue()->enumValue(); } + SVGUnitTypes::SVGUnitType maskContentUnits() const { return toSVGMaskElement(element())->maskContentUnits()->currentValue()->enumValue(); } - virtual RenderSVGResourceType resourceType() const { return s_resourceType; } + virtual RenderSVGResourceType resourceType() const OVERRIDE { return s_resourceType; } static const RenderSVGResourceType s_resourceType; private: diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourcePattern.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourcePattern.cpp index c107a793f4a..401a29057a8 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourcePattern.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourcePattern.cpp @@ -53,6 +53,7 @@ void RenderSVGResourcePattern::removeClientFromCache(RenderObject* client, bool PatternData* RenderSVGResourcePattern::buildPattern(RenderObject* object, unsigned short resourceMode) { + ASSERT(object); PatternData* currentData = m_patternMap.get(object); if (currentData && currentData->pattern) return currentData; @@ -84,19 +85,18 @@ PatternData* RenderSVGResourcePattern::buildPattern(RenderObject* object, unsign return 0; AffineTransform absoluteTransformIgnoringRotation; - SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(object, absoluteTransformIgnoringRotation); + SVGRenderingContext::calculateDeviceSpaceTransformation(object, absoluteTransformIgnoringRotation); // Ignore 2D rotation, as it doesn't affect the size of the tile. SVGRenderingContext::clear2DRotation(absoluteTransformIgnoringRotation); FloatRect absoluteTileBoundaries = absoluteTransformIgnoringRotation.mapRect(tileBoundaries); - FloatRect clampedAbsoluteTileBoundaries; // Scale the tile size to match the scale level of the patternTransform. absoluteTileBoundaries.scale(static_cast<float>(m_attributes.patternTransform().xScale()), static_cast<float>(m_attributes.patternTransform().yScale())); // Build tile image. - OwnPtr<ImageBuffer> tileImage = createTileImage(m_attributes, tileBoundaries, absoluteTileBoundaries, tileImageTransform, clampedAbsoluteTileBoundaries); + OwnPtr<ImageBuffer> tileImage = createTileImage(m_attributes, tileBoundaries, absoluteTileBoundaries, tileImageTransform); if (!tileImage) return 0; @@ -117,18 +117,10 @@ PatternData* RenderSVGResourcePattern::buildPattern(RenderObject* object, unsign if (!patternTransform.isIdentity()) patternData->transform = patternTransform * patternData->transform; - // Account for text drawing resetting the context to non-scaled, see SVGInlineTextBox::paintTextWithShadows. - if (resourceMode & ApplyToTextMode) { - AffineTransform additionalTextTransformation; - if (shouldTransformOnTextPainting(object, additionalTextTransformation)) - patternData->transform *= additionalTextTransformation; - } - patternData->pattern->setPatternSpaceTransform(patternData->transform); - // Various calls above may trigger invalidations in some fringe cases (ImageBuffer allocation // failures in the SVG image cache for example). To avoid having our PatternData deleted by // removeAllClientsFromCache(), we only make it visible in the cache at the very end. - return m_patternMap.set(object, patternData.release()).iterator->value.get(); + return m_patternMap.set(object, patternData.release()).storedValue->value.get(); } bool RenderSVGResourcePattern::applyResource(RenderObject* object, RenderStyle* style, GraphicsContext*& context, unsigned short resourceMode) @@ -150,20 +142,21 @@ bool RenderSVGResourcePattern::applyResource(RenderObject* object, RenderStyle* if (!patternData) return false; - // Draw pattern - context->save(); - const SVGRenderStyle* svgStyle = style->svgStyle(); ASSERT(svgStyle); + AffineTransform computedPatternSpaceTransform = computeResourceSpaceTransform(object, patternData->transform, svgStyle, resourceMode); + patternData->pattern->setPatternSpaceTransform(computedPatternSpaceTransform); + + // Draw pattern + context->save(); + if (resourceMode & ApplyToFillMode) { - context->setAlpha(svgStyle->fillOpacity()); + context->setAlphaAsFloat(svgStyle->fillOpacity()); context->setFillPattern(patternData->pattern); context->setFillRule(svgStyle->fillRule()); } else if (resourceMode & ApplyToStrokeMode) { - if (svgStyle->vectorEffect() == VE_NON_SCALING_STROKE) - patternData->pattern->setPatternSpaceTransform(transformOnNonScalingStroke(object, patternData->transform)); - context->setAlpha(svgStyle->strokeOpacity()); + context->setAlphaAsFloat(svgStyle->strokeOpacity()); context->setStrokePattern(patternData->pattern); SVGRenderSupport::applyStrokeStyleToContext(context, style, object); } @@ -235,10 +228,9 @@ bool RenderSVGResourcePattern::buildTileImageTransform(RenderObject* renderer, PassOwnPtr<ImageBuffer> RenderSVGResourcePattern::createTileImage(const PatternAttributes& attributes, const FloatRect& tileBoundaries, const FloatRect& absoluteTileBoundaries, - const AffineTransform& tileImageTransform, - FloatRect& clampedAbsoluteTileBoundaries) const + const AffineTransform& tileImageTransform) const { - clampedAbsoluteTileBoundaries = SVGRenderingContext::clampedAbsoluteTargetRect(absoluteTileBoundaries); + FloatRect clampedAbsoluteTileBoundaries = SVGRenderingContext::clampedAbsoluteTargetRect(absoluteTileBoundaries); IntSize imageSize(roundedIntSize(clampedAbsoluteTileBoundaries.size())); if (imageSize.isEmpty()) @@ -250,11 +242,12 @@ PassOwnPtr<ImageBuffer> RenderSVGResourcePattern::createTileImage(const PatternA GraphicsContext* tileImageContext = tileImage->context(); ASSERT(tileImageContext); IntSize unclampedImageSize(roundedIntSize(absoluteTileBoundaries.size())); - tileImageContext->scale(FloatSize(unclampedImageSize.width() / absoluteTileBoundaries.width(), unclampedImageSize.height() / absoluteTileBoundaries.height())); + tileImageContext->scale(unclampedImageSize.width() / absoluteTileBoundaries.width(), unclampedImageSize.height() / absoluteTileBoundaries.height()); // The image buffer represents the final rendered size, so the content has to be scaled (to avoid pixelation). - tileImageContext->scale(FloatSize(clampedAbsoluteTileBoundaries.width() / tileBoundaries.width(), - clampedAbsoluteTileBoundaries.height() / tileBoundaries.height())); + tileImageContext->scale( + clampedAbsoluteTileBoundaries.width() / tileBoundaries.width(), + clampedAbsoluteTileBoundaries.height() / tileBoundaries.height()); // Apply tile image transformations. if (!tileImageTransform.isIdentity()) @@ -265,12 +258,12 @@ PassOwnPtr<ImageBuffer> RenderSVGResourcePattern::createTileImage(const PatternA contentTransformation = tileImageTransform; // Draw the content into the ImageBuffer. - for (Node* node = attributes.patternContentElement()->firstChild(); node; node = node->nextSibling()) { - if (!node->isSVGElement() || !node->renderer()) + for (Element* element = ElementTraversal::firstWithin(*attributes.patternContentElement()); element; element = ElementTraversal::nextSibling(*element)) { + if (!element->isSVGElement() || !element->renderer()) continue; - if (node->renderer()->needsLayout()) + if (element->renderer()->needsLayout()) return nullptr; - SVGRenderingContext::renderSubtree(tileImage->context(), node->renderer(), contentTransformation); + SVGRenderingContext::renderSubtree(tileImage->context(), element->renderer(), contentTransformation); } return tileImage.release(); diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourcePattern.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourcePattern.h index 56a8318e06d..d6b4f12e577 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourcePattern.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourcePattern.h @@ -46,23 +46,22 @@ class RenderSVGResourcePattern FINAL : public RenderSVGResourceContainer { public: explicit RenderSVGResourcePattern(SVGPatternElement*); - virtual const char* renderName() const { return "RenderSVGResourcePattern"; } + virtual const char* renderName() const OVERRIDE { return "RenderSVGResourcePattern"; } - virtual void removeAllClientsFromCache(bool markForInvalidation = true); - virtual void removeClientFromCache(RenderObject*, bool markForInvalidation = true); + virtual void removeAllClientsFromCache(bool markForInvalidation = true) OVERRIDE; + virtual void removeClientFromCache(RenderObject*, bool markForInvalidation = true) OVERRIDE; - virtual bool applyResource(RenderObject*, RenderStyle*, GraphicsContext*&, unsigned short resourceMode); - virtual void postApplyResource(RenderObject*, GraphicsContext*&, unsigned short resourceMode, const Path*, const RenderSVGShape*); + virtual bool applyResource(RenderObject*, RenderStyle*, GraphicsContext*&, unsigned short resourceMode) OVERRIDE; + virtual void postApplyResource(RenderObject*, GraphicsContext*&, unsigned short resourceMode, const Path*, const RenderSVGShape*) OVERRIDE; - virtual RenderSVGResourceType resourceType() const { return s_resourceType; } + virtual RenderSVGResourceType resourceType() const OVERRIDE { return s_resourceType; } static const RenderSVGResourceType s_resourceType; private: bool buildTileImageTransform(RenderObject*, const PatternAttributes&, const SVGPatternElement*, FloatRect& patternBoundaries, AffineTransform& tileImageTransform) const; PassOwnPtr<ImageBuffer> createTileImage(const PatternAttributes&, const FloatRect& tileBoundaries, - const FloatRect& absoluteTileBoundaries, const AffineTransform& tileImageTransform, - FloatRect& clampedAbsoluteTileBoundaries) const; + const FloatRect& absoluteTileBoundaries, const AffineTransform& tileImageTransform) const; PatternData* buildPattern(RenderObject*, unsigned short resourceMode); diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceRadialGradient.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceRadialGradient.h index 43ee07601e0..1f9145a02bd 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceRadialGradient.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceRadialGradient.h @@ -33,15 +33,15 @@ public: explicit RenderSVGResourceRadialGradient(SVGRadialGradientElement*); virtual ~RenderSVGResourceRadialGradient(); - virtual const char* renderName() const { return "RenderSVGResourceRadialGradient"; } + virtual const char* renderName() const OVERRIDE { return "RenderSVGResourceRadialGradient"; } - virtual RenderSVGResourceType resourceType() const { return s_resourceType; } + virtual RenderSVGResourceType resourceType() const OVERRIDE { return s_resourceType; } static const RenderSVGResourceType s_resourceType; - virtual SVGUnitTypes::SVGUnitType gradientUnits() const { return m_attributes.gradientUnits(); } - virtual void calculateGradientTransform(AffineTransform& transform) { transform = m_attributes.gradientTransform(); } - virtual bool collectGradientAttributes(SVGGradientElement*); - virtual void buildGradient(GradientData*) const; + virtual SVGUnitTypes::SVGUnitType gradientUnits() const OVERRIDE { return m_attributes.gradientUnits(); } + virtual void calculateGradientTransform(AffineTransform& transform) OVERRIDE { transform = m_attributes.gradientTransform(); } + virtual bool collectGradientAttributes(SVGGradientElement*) OVERRIDE; + virtual void buildGradient(GradientData*) const OVERRIDE; FloatPoint centerPoint(const RadialGradientAttributes&) const; FloatPoint focalPoint(const RadialGradientAttributes&) const; diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceSolidColor.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceSolidColor.cpp index a79ad3ad916..fac2a846c9a 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceSolidColor.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceSolidColor.cpp @@ -21,8 +21,8 @@ #include "core/rendering/svg/RenderSVGResourceSolidColor.h" -#include "core/frame/Frame.h" #include "core/frame/FrameView.h" +#include "core/frame/LocalFrame.h" #include "core/rendering/style/RenderStyle.h" #include "core/rendering/svg/RenderSVGShape.h" #include "core/rendering/svg/SVGRenderSupport.h" @@ -56,9 +56,9 @@ bool RenderSVGResourceSolidColor::applyResource(RenderObject* object, RenderStyl if (resourceMode & ApplyToFillMode) { if (!isRenderingMask && svgStyle) - context->setAlpha(svgStyle->fillOpacity()); + context->setAlphaAsFloat(svgStyle->fillOpacity()); else - context->setAlpha(1); + context->setAlphaAsFloat(1); context->setFillColor(m_color); if (!isRenderingMask) context->setFillRule(svgStyle ? svgStyle->fillRule() : RULE_NONZERO); @@ -68,7 +68,7 @@ bool RenderSVGResourceSolidColor::applyResource(RenderObject* object, RenderStyl } else if (resourceMode & ApplyToStrokeMode) { // When rendering the mask for a RenderSVGResourceClipper, the stroke code path is never hit. ASSERT(!isRenderingMask); - context->setAlpha(svgStyle ? svgStyle->strokeOpacity() : 1); + context->setAlphaAsFloat(svgStyle ? svgStyle->strokeOpacity() : 1); context->setStrokeColor(m_color); if (style) diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceSolidColor.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceSolidColor.h index 85937ce9ef1..3583a0d1aec 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceSolidColor.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceSolidColor.h @@ -26,18 +26,18 @@ namespace WebCore { -class RenderSVGResourceSolidColor : public RenderSVGResource { +class RenderSVGResourceSolidColor FINAL : public RenderSVGResource { public: RenderSVGResourceSolidColor(); virtual ~RenderSVGResourceSolidColor(); - virtual void removeAllClientsFromCache(bool = true) { } - virtual void removeClientFromCache(RenderObject*, bool = true) { } + virtual void removeAllClientsFromCache(bool = true) OVERRIDE { } + virtual void removeClientFromCache(RenderObject*, bool = true) OVERRIDE { } - virtual bool applyResource(RenderObject*, RenderStyle*, GraphicsContext*&, unsigned short resourceMode); - virtual void postApplyResource(RenderObject*, GraphicsContext*&, unsigned short resourceMode, const Path*, const RenderSVGShape*); + virtual bool applyResource(RenderObject*, RenderStyle*, GraphicsContext*&, unsigned short resourceMode) OVERRIDE; + virtual void postApplyResource(RenderObject*, GraphicsContext*&, unsigned short resourceMode, const Path*, const RenderSVGShape*) OVERRIDE; - virtual RenderSVGResourceType resourceType() const { return s_resourceType; } + virtual RenderSVGResourceType resourceType() const OVERRIDE { return s_resourceType; } static const RenderSVGResourceType s_resourceType; const Color& color() const { return m_color; } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGRoot.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGRoot.cpp index a4355cd4d9a..d88947d3574 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGRoot.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGRoot.cpp @@ -25,19 +25,21 @@ #include "core/rendering/svg/RenderSVGRoot.h" -#include "core/frame/Frame.h" +#include "core/frame/LocalFrame.h" #include "core/rendering/HitTestResult.h" -#include "core/rendering/LayoutRectRecorder.h" #include "core/rendering/LayoutRepainter.h" +#include "core/rendering/RenderLayer.h" #include "core/rendering/RenderPart.h" #include "core/rendering/RenderView.h" #include "core/rendering/svg/RenderSVGResourceContainer.h" +#include "core/rendering/svg/SVGRenderSupport.h" #include "core/rendering/svg/SVGRenderingContext.h" #include "core/rendering/svg/SVGResources.h" #include "core/rendering/svg/SVGResourcesCache.h" #include "core/svg/SVGElement.h" #include "core/svg/SVGSVGElement.h" #include "core/svg/graphics/SVGImage.h" +#include "platform/LengthFunctions.h" #include "platform/graphics/GraphicsContext.h" using namespace std; @@ -49,6 +51,7 @@ RenderSVGRoot::RenderSVGRoot(SVGElement* node) , m_objectBoundingBoxValid(false) , m_isLayoutSizeChanged(false) , m_needsBoundariesOrTransformUpdate(true) + , m_hasBoxDecorations(false) { } @@ -56,19 +59,13 @@ RenderSVGRoot::~RenderSVGRoot() { } -void RenderSVGRoot::computeIntrinsicRatioInformation(FloatSize& intrinsicSize, double& intrinsicRatio, bool& isPercentageIntrinsicSize) const +void RenderSVGRoot::computeIntrinsicRatioInformation(FloatSize& intrinsicSize, double& intrinsicRatio) const { // Spec: http://www.w3.org/TR/SVG/coords.html#IntrinsicSizing // SVG needs to specify how to calculate some intrinsic sizing properties to enable inclusion within other languages. // The intrinsic width and height of the viewport of SVG content must be determined from the ‘width’ and ‘height’ attributes. - // If either of these are not specified, a value of '100%' must be assumed. Note: the ‘width’ and ‘height’ attributes are not - // the same as the CSS width and height properties. Specifically, percentage values do not provide an intrinsic width or height, - // and do not indicate a percentage of the containing block. Rather, once the viewport is established, they indicate the portion - // of the viewport that is actually covered by image data. SVGSVGElement* svg = toSVGSVGElement(node()); ASSERT(svg); - Length intrinsicWidthAttribute = svg->intrinsicWidth(SVGSVGElement::IgnoreCSSProperties); - Length intrinsicHeightAttribute = svg->intrinsicHeight(SVGSVGElement::IgnoreCSSProperties); // The intrinsic aspect ratio of the viewport of SVG content is necessary for example, when including SVG from an ‘object’ // element in HTML styled with CSS. It is possible (indeed, common) for an SVG graphic to have an intrinsic aspect ratio but @@ -77,33 +74,21 @@ void RenderSVGRoot::computeIntrinsicRatioInformation(FloatSize& intrinsicSize, d // - If the ‘width’ and ‘height’ of the rootmost ‘svg’ element are both specified with unit identifiers (in, mm, cm, pt, pc, // px, em, ex) or in user units, then the aspect ratio is calculated from the ‘width’ and ‘height’ attributes after // resolving both values to user units. - if (intrinsicWidthAttribute.isFixed() || intrinsicHeightAttribute.isFixed()) { - if (intrinsicWidthAttribute.isFixed()) - intrinsicSize.setWidth(floatValueForLength(intrinsicWidthAttribute, 0, 0)); - if (intrinsicHeightAttribute.isFixed()) - intrinsicSize.setHeight(floatValueForLength(intrinsicHeightAttribute, 0, 0)); - if (!intrinsicSize.isEmpty()) - intrinsicRatio = intrinsicSize.width() / static_cast<double>(intrinsicSize.height()); - return; - } + intrinsicSize.setWidth(floatValueForLength(svg->intrinsicWidth(), 0)); + intrinsicSize.setHeight(floatValueForLength(svg->intrinsicHeight(), 0)); - // - If either/both of the ‘width’ and ‘height’ of the rootmost ‘svg’ element are in percentage units (or omitted), the - // aspect ratio is calculated from the width and height values of the ‘viewBox’ specified for the current SVG document - // fragment. If the ‘viewBox’ is not correctly specified, or set to 'none', the intrinsic aspect ratio cannot be - // calculated and is considered unspecified. - intrinsicSize = svg->viewBoxCurrentValue().size(); if (!intrinsicSize.isEmpty()) { - // The viewBox can only yield an intrinsic ratio, not an intrinsic size. intrinsicRatio = intrinsicSize.width() / static_cast<double>(intrinsicSize.height()); - intrinsicSize = FloatSize(); - return; - } - - // If our intrinsic size is in percentage units, return those to the caller through the intrinsicSize. Notify the caller - // about the special situation, by setting isPercentageIntrinsicSize=true, so it knows how to interpret the return values. - if (intrinsicWidthAttribute.isPercent() && intrinsicHeightAttribute.isPercent()) { - isPercentageIntrinsicSize = true; - intrinsicSize = FloatSize(intrinsicWidthAttribute.percent(), intrinsicHeightAttribute.percent()); + } else { + // - If either/both of the ‘width’ and ‘height’ of the rootmost ‘svg’ element are in percentage units (or omitted), the + // aspect ratio is calculated from the width and height values of the ‘viewBox’ specified for the current SVG document + // fragment. If the ‘viewBox’ is not correctly specified, or set to 'none', the intrinsic aspect ratio cannot be + // calculated and is considered unspecified. + FloatSize viewBoxSize = svg->viewBox()->currentValue()->value().size(); + if (!viewBoxSize.isEmpty()) { + // The viewBox can only yield an intrinsic ratio, not an intrinsic size. + intrinsicRatio = viewBoxSize.width() / static_cast<double>(viewBoxSize.height()); + } } } @@ -117,20 +102,20 @@ bool RenderSVGRoot::isEmbeddedThroughFrameContainingSVGDocument() const if (!node()) return false; - Frame* frame = node()->document().frame(); + LocalFrame* frame = node()->document().frame(); if (!frame) return false; // If our frame has an owner renderer, we're embedded through eg. object/embed/iframe, - // but we only negotiate if we're in an SVG document. - if (!frame->ownerRenderer()) + // but we only negotiate if we're in an SVG document inside a embedded object (object/embed). + if (!frame->ownerRenderer() || !frame->ownerRenderer()->isEmbeddedObject()) return false; return frame->document()->isSVGDocument(); } -static inline LayoutUnit resolveLengthAttributeForSVG(const Length& length, float scale, float maxSize, RenderView* renderView) +static inline LayoutUnit resolveLengthAttributeForSVG(const Length& length, float scale, float maxSize) { - return static_cast<LayoutUnit>(valueForLength(length, maxSize, renderView) * (length.isFixed() ? scale : 1)); + return static_cast<LayoutUnit>(valueForLength(length, maxSize) * (length.isFixed() ? scale : 1)); } LayoutUnit RenderSVGRoot::computeReplacedLogicalWidth(ShouldComputePreferred shouldComputePreferred) const @@ -142,15 +127,14 @@ LayoutUnit RenderSVGRoot::computeReplacedLogicalWidth(ShouldComputePreferred sho if (!m_containerSize.isEmpty()) return m_containerSize.width(); + if (isEmbeddedThroughFrameContainingSVGDocument()) + return containingBlock()->availableLogicalWidth(); + if (style()->logicalWidth().isSpecified() || style()->logicalMaxWidth().isSpecified()) return RenderReplaced::computeReplacedLogicalWidth(shouldComputePreferred); - if (svg->widthAttributeEstablishesViewport()) - return resolveLengthAttributeForSVG(svg->intrinsicWidth(SVGSVGElement::IgnoreCSSProperties), style()->effectiveZoom(), containingBlock()->availableLogicalWidth(), view()); - - // SVG embedded through object/embed/iframe. - if (isEmbeddedThroughFrameContainingSVGDocument()) - return document().frame()->ownerRenderer()->availableLogicalWidth(); + if (svg->hasIntrinsicWidth()) + return resolveLengthAttributeForSVG(svg->intrinsicWidth(), style()->effectiveZoom(), containingBlock()->availableLogicalWidth().toFloat()); // SVG embedded via SVGImage (background-image/border-image/etc) / Inline SVG. return RenderReplaced::computeReplacedLogicalWidth(shouldComputePreferred); @@ -165,27 +149,14 @@ LayoutUnit RenderSVGRoot::computeReplacedLogicalHeight() const if (!m_containerSize.isEmpty()) return m_containerSize.height(); + if (isEmbeddedThroughFrameContainingSVGDocument()) + return containingBlock()->availableLogicalHeight(IncludeMarginBorderPadding); + if (style()->logicalHeight().isSpecified() || style()->logicalMaxHeight().isSpecified()) return RenderReplaced::computeReplacedLogicalHeight(); - if (svg->heightAttributeEstablishesViewport()) { - Length height = svg->intrinsicHeight(SVGSVGElement::IgnoreCSSProperties); - if (height.isPercent()) { - RenderBlock* cb = containingBlock(); - ASSERT(cb); - while (cb->isAnonymous()) { - cb = cb->containingBlock(); - cb->addPercentHeightDescendant(const_cast<RenderSVGRoot*>(this)); - } - } else - RenderBlock::removePercentHeightDescendant(const_cast<RenderSVGRoot*>(this)); - - return resolveLengthAttributeForSVG(height, style()->effectiveZoom(), containingBlock()->availableLogicalHeight(IncludeMarginBorderPadding), view()); - } - - // SVG embedded through object/embed/iframe. - if (isEmbeddedThroughFrameContainingSVGDocument()) - return document().frame()->ownerRenderer()->availableLogicalHeight(IncludeMarginBorderPadding); + if (svg->hasIntrinsicHeight()) + return resolveLengthAttributeForSVG(svg->intrinsicHeight(), style()->effectiveZoom(), containingBlock()->availableLogicalHeight(IncludeMarginBorderPadding).toFloat()); // SVG embedded via SVGImage (background-image/border-image/etc) / Inline SVG. return RenderReplaced::computeReplacedLogicalHeight(); @@ -195,13 +166,11 @@ void RenderSVGRoot::layout() { ASSERT(needsLayout()); - LayoutRectRecorder recorder(*this); - // Arbitrary affine transforms are incompatible with LayoutState. - LayoutStateDisabler layoutStateDisabler(view()); + ForceHorriblySlowRectMapping slowRectMapping(*this); bool needsLayout = selfNeedsLayout(); - LayoutRepainter repainter(*this, checkForRepaintDuringLayout() && needsLayout); + LayoutRepainter repainter(*this, checkForPaintInvalidationDuringLayout() && needsLayout); LayoutSize oldSize = size(); updateLogicalWidth(); @@ -222,13 +191,34 @@ void RenderSVGRoot::layout() m_needsBoundariesOrTransformUpdate = false; } - updateLayerTransform(); + m_overflow.clear(); + addVisualEffectOverflow(); - repainter.repaintAfterLayout(); + if (!shouldApplyViewportClip()) { + FloatRect contentRepaintRect = paintInvalidationRectInLocalCoordinates(); + contentRepaintRect = m_localToBorderBoxTransform.mapRect(contentRepaintRect); + addVisualOverflow(enclosingLayoutRect(contentRepaintRect)); + } + updateLayerTransformAfterLayout(); + m_hasBoxDecorations = isDocumentElement() ? calculateHasBoxDecorations() : hasBoxDecorations(); + invalidateBackgroundObscurationStatus(); + + repainter.repaintAfterLayout(); clearNeedsLayout(); } +bool RenderSVGRoot::shouldApplyViewportClip() const +{ + // the outermost svg is clipped if auto, and svg document roots are always clipped + // When the svg is stand-alone (isDocumentElement() == true) the viewport clipping should always + // be applied, noting that the window scrollbars should be hidden if overflow=hidden. + return style()->overflowX() == OHIDDEN + || style()->overflowX() == OAUTO + || style()->overflowX() == OSCROLL + || this->isDocumentElement(); +} + void RenderSVGRoot::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { // An empty viewport disables rendering. @@ -239,6 +229,10 @@ void RenderSVGRoot::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paint if (paintInfo.context->paintingDisabled()) return; + // SVG outlines are painted during PaintPhaseForeground. + if (paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) + return; + // An empty viewBox also disables rendering. // (http://www.w3.org/TR/SVG/coords.html#ViewBoxAttribute) SVGSVGElement* svg = toSVGSVGElement(node()); @@ -257,8 +251,9 @@ void RenderSVGRoot::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paint PaintInfo childPaintInfo(paintInfo); childPaintInfo.context->save(); - // Apply initial viewport clip - not affected by overflow handling - childPaintInfo.context->clip(pixelSnappedIntRect(overflowClipRect(paintOffset, paintInfo.renderRegion))); + // Apply initial viewport clip + if (shouldApplyViewportClip()) + childPaintInfo.context->clip(pixelSnappedIntRect(overflowClipRect(paintOffset))); // Convert from container offsets (html renderers) to a relative transform (svg renderers). // Transform from our paint container's coordinate system to our local coords. @@ -292,13 +287,22 @@ void RenderSVGRoot::willBeDestroyed() void RenderSVGRoot::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { - if (diff == StyleDifferenceLayout) + if (diff.needsFullLayout()) setNeedsBoundariesUpdate(); + if (diff.needsRepaint()) { + // Box decorations may have appeared/disappeared - recompute status. + m_hasBoxDecorations = calculateHasBoxDecorations(); + } RenderReplaced::styleDidChange(diff, oldStyle); SVGResourcesCache::clientStyleChanged(this, diff, style()); } +bool RenderSVGRoot::isChildAllowed(RenderObject* child, RenderStyle*) const +{ + return child->isSVG() && !(child->isSVGInline() || child->isSVGInlineText()); +} + void RenderSVGRoot::addChild(RenderObject* child, RenderObject* beforeChild) { RenderReplaced::addChild(child, beforeChild); @@ -330,12 +334,13 @@ void RenderSVGRoot::buildLocalToBorderBoxTransform() SVGSVGElement* svg = toSVGSVGElement(node()); ASSERT(svg); float scale = style()->effectiveZoom(); - SVGPoint translate = svg->currentTranslate(); + FloatPoint translate = svg->currentTranslate(); LayoutSize borderAndPadding(borderLeft() + paddingLeft(), borderTop() + paddingTop()); m_localToBorderBoxTransform = svg->viewBoxToViewTransform(contentWidth() / scale, contentHeight() / scale); - if (borderAndPadding.isEmpty() && scale == 1 && translate == SVGPoint::zero()) + AffineTransform viewToBorderBoxTransform(scale, 0, 0, scale, borderAndPadding.width() + translate.x(), borderAndPadding.height() + translate.y()); + if (viewToBorderBoxTransform.isIdentity()) return; - m_localToBorderBoxTransform = AffineTransform(scale, 0, 0, scale, borderAndPadding.width() + translate.x(), borderAndPadding.height() + translate.y()) * m_localToBorderBoxTransform; + m_localToBorderBoxTransform = viewToBorderBoxTransform * m_localToBorderBoxTransform; } const AffineTransform& RenderSVGRoot::localToParentTransform() const @@ -349,23 +354,53 @@ const AffineTransform& RenderSVGRoot::localToParentTransform() const return m_localToParentTransform; } -LayoutRect RenderSVGRoot::clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const +LayoutRect RenderSVGRoot::clippedOverflowRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer) const { - return SVGRenderSupport::clippedOverflowRectForRepaint(this, repaintContainer); + // This is an open-coded aggregate of SVGRenderSupport::clippedOverflowRectForPaintInvalidation, + // RenderSVGRoot::computeFloatRectForPaintInvalidation and RenderReplaced::clippedOverflowRectForPaintInvalidation. + // The reason for this is to optimize/minimize the repaint rect when the box is not "decorated" + // (does not have background/border/etc.) + + // Return early for any cases where we don't actually paint. + if (style()->visibility() != VISIBLE && !enclosingLayer()->hasVisibleContent()) + return LayoutRect(); + + // Compute the repaint rect of the content of the SVG in the border-box coordinate space. + FloatRect contentRepaintRect = paintInvalidationRectInLocalCoordinates(); + contentRepaintRect = m_localToBorderBoxTransform.mapRect(contentRepaintRect); + + // Apply initial viewport clip, overflow:visible content is added to visualOverflow + // but the most common case is that overflow is hidden, so always intersect. + contentRepaintRect.intersect(pixelSnappedBorderBoxRect()); + + LayoutRect repaintRect = enclosingLayoutRect(contentRepaintRect); + // If the box is decorated or is overflowing, extend it to include the border-box and overflow. + if (m_hasBoxDecorations || hasRenderOverflow()) { + // The selectionRect can project outside of the overflowRect, so take their union + // for repainting to avoid selection painting glitches. + LayoutRect decoratedRepaintRect = unionRect(localSelectionRect(false), visualOverflowRect()); + repaintRect.unite(decoratedRepaintRect); + } + + // Compute the repaint rect in the parent coordinate space. + LayoutRect rect = enclosingIntRect(repaintRect); + RenderReplaced::mapRectToPaintInvalidationBacking(paintInvalidationContainer, rect); + return rect; } -void RenderSVGRoot::computeFloatRectForRepaint(const RenderLayerModelObject* repaintContainer, FloatRect& repaintRect, bool fixed) const +void RenderSVGRoot::computeFloatRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer, FloatRect& paintInvalidationRect, bool fixed) const { // Apply our local transforms (except for x/y translation), then our shadow, // and then call RenderBox's method to handle all the normal CSS Box model bits - repaintRect = m_localToBorderBoxTransform.mapRect(repaintRect); + paintInvalidationRect = m_localToBorderBoxTransform.mapRect(paintInvalidationRect); - // Apply initial viewport clip - not affected by overflow settings - repaintRect.intersect(pixelSnappedBorderBoxRect()); + // Apply initial viewport clip + if (shouldApplyViewportClip()) + paintInvalidationRect.intersect(pixelSnappedBorderBoxRect()); - LayoutRect rect = enclosingIntRect(repaintRect); - RenderReplaced::computeRectForRepaint(repaintContainer, rect, fixed); - repaintRect = rect; + LayoutRect rect = enclosingIntRect(paintInvalidationRect); + RenderReplaced::mapRectToPaintInvalidationBacking(paintInvalidationContainer, rect, fixed); + paintInvalidationRect = rect; } // This method expects local CSS box coordinates. @@ -374,7 +409,9 @@ void RenderSVGRoot::computeFloatRectForRepaint(const RenderLayerModelObject* rep void RenderSVGRoot::mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed) const { ASSERT(mode & ~IsFixed); // We should have no fixed content in the SVG rendering tree. - ASSERT(mode & UseTransforms); // mapping a point through SVG w/o respecting trasnforms is useless. + // We used to have this ASSERT here, but we removed it when enabling layer squashing. + // See http://crbug.com/364901 + // ASSERT(mode & UseTransforms); // mapping a point through SVG w/o respecting trasnforms is useless. RenderReplaced::mapLocalToContainer(repaintContainer, transformState, mode | ApplyContainerFlip, wasFixed); } @@ -388,7 +425,6 @@ void RenderSVGRoot::updateCachedBoundaries() { SVGRenderSupport::computeContainerBoundingBoxes(this, m_objectBoundingBox, m_objectBoundingBoxValid, m_strokeBoundingBox, m_repaintBoundingBox); SVGRenderSupport::intersectRepaintRectWithResources(this, m_repaintBoundingBox); - m_repaintBoundingBox.inflate(borderAndPaddingWidth()); } bool RenderSVGRoot::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction) @@ -412,11 +448,11 @@ bool RenderSVGRoot::nodeAtPoint(const HitTestRequest& request, HitTestResult& re } // If we didn't early exit above, we've just hit the container <svg> element. Unlike SVG 1.1, 2nd Edition allows container elements to be hit. - if (hitTestAction == HitTestBlockBackground && visibleToHitTestRequest(request)) { - // Only return true here, if the last hit testing phase 'BlockBackground' is executed. If we'd return true in the 'Foreground' phase, - // hit testing would stop immediately. For SVG only trees this doesn't matter. Though when we have a <foreignObject> subtree we need - // to be able to detect hits on the background of a <div> element. If we'd return true here in the 'Foreground' phase, we are not able - // to detect these hits anymore. + if ((hitTestAction == HitTestBlockBackground || hitTestAction == HitTestChildBlockBackground) && visibleToHitTestRequest(request)) { + // Only return true here, if the last hit testing phase 'BlockBackground' (or 'ChildBlockBackground' - depending on context) is executed. + // If we'd return true in the 'Foreground' phase, hit testing would stop immediately. For SVG only trees this doesn't matter. + // Though when we have a <foreignObject> subtree we need to be able to detect hits on the background of a <div> element. + // If we'd return true here in the 'Foreground' phase, we are not able to detect these hits anymore. LayoutRect boundsRect(accumulatedOffset + location(), size()); if (locationInContainer.intersects(boundsRect)) { updateHitTestResult(result, pointInBorderBox); @@ -428,27 +464,4 @@ bool RenderSVGRoot::nodeAtPoint(const HitTestRequest& request, HitTestResult& re return false; } -bool RenderSVGRoot::hasRelativeDimensions() const -{ - SVGSVGElement* svg = toSVGSVGElement(node()); - ASSERT(svg); - - return svg->intrinsicHeight(SVGSVGElement::IgnoreCSSProperties).isPercent() || svg->intrinsicWidth(SVGSVGElement::IgnoreCSSProperties).isPercent(); -} - -bool RenderSVGRoot::hasRelativeIntrinsicLogicalWidth() const -{ - SVGSVGElement* svg = toSVGSVGElement(node()); - ASSERT(svg); - return svg->intrinsicWidth(SVGSVGElement::IgnoreCSSProperties).isPercent(); -} - -bool RenderSVGRoot::hasRelativeLogicalHeight() const -{ - SVGSVGElement* svg = toSVGSVGElement(node()); - ASSERT(svg); - - return svg->intrinsicHeight(SVGSVGElement::IgnoreCSSProperties).isPercent(); -} - } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGRoot.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGRoot.h index f907222eb81..b38d51cbde8 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGRoot.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGRoot.h @@ -24,12 +24,10 @@ #define RenderSVGRoot_h #include "core/rendering/RenderReplaced.h" -#include "core/rendering/svg/SVGRenderSupport.h" #include "platform/geometry/FloatRect.h" namespace WebCore { -class AffineTransform; class SVGElement; class RenderSVGRoot FINAL : public RenderReplaced { @@ -40,66 +38,77 @@ public: bool isEmbeddedThroughSVGImage() const; bool isEmbeddedThroughFrameContainingSVGDocument() const; - virtual void computeIntrinsicRatioInformation(FloatSize& intrinsicSize, double& intrinsicRatio, bool& isPercentageIntrinsicSize) const; + virtual void computeIntrinsicRatioInformation(FloatSize& intrinsicSize, double& intrinsicRatio) const OVERRIDE; RenderObject* firstChild() const { ASSERT(children() == virtualChildren()); return children()->firstChild(); } RenderObject* lastChild() const { ASSERT(children() == virtualChildren()); return children()->lastChild(); } + // If you have a RenderSVGRoot, use firstChild or lastChild instead. + void slowFirstChild() const WTF_DELETED_FUNCTION; + void slowLastChild() const WTF_DELETED_FUNCTION; + const RenderObjectChildList* children() const { return &m_children; } RenderObjectChildList* children() { return &m_children; } bool isLayoutSizeChanged() const { return m_isLayoutSizeChanged; } - virtual void setNeedsBoundariesUpdate() { m_needsBoundariesOrTransformUpdate = true; } - virtual bool needsBoundariesUpdate() OVERRIDE { return m_needsBoundariesOrTransformUpdate; } - virtual void setNeedsTransformUpdate() { m_needsBoundariesOrTransformUpdate = true; } + virtual void setNeedsBoundariesUpdate() OVERRIDE { m_needsBoundariesOrTransformUpdate = true; } + virtual void setNeedsTransformUpdate() OVERRIDE { m_needsBoundariesOrTransformUpdate = true; } IntSize containerSize() const { return m_containerSize; } - void setContainerSize(const IntSize& containerSize) { m_containerSize = containerSize; } - - virtual bool hasRelativeDimensions() const OVERRIDE; - virtual bool hasRelativeIntrinsicLogicalWidth() const OVERRIDE; - virtual bool hasRelativeLogicalHeight() const OVERRIDE; + void setContainerSize(const IntSize& containerSize) + { + // SVGImage::draw() does a view layout prior to painting, + // and we need that layout to know of the new size otherwise + // the rendering may be incorrectly using the old size. + if (m_containerSize != containerSize) + setNeedsLayoutAndFullPaintInvalidation(); + m_containerSize = containerSize; + } // localToBorderBoxTransform maps local SVG viewport coordinates to local CSS box coordinates. const AffineTransform& localToBorderBoxTransform() const { return m_localToBorderBoxTransform; } private: - virtual RenderObjectChildList* virtualChildren() { return children(); } - virtual const RenderObjectChildList* virtualChildren() const { return children(); } + virtual RenderObjectChildList* virtualChildren() OVERRIDE { return children(); } + virtual const RenderObjectChildList* virtualChildren() const OVERRIDE { return children(); } - virtual bool isSVGRoot() const { return true; } - virtual const char* renderName() const { return "RenderSVGRoot"; } + virtual const char* renderName() const OVERRIDE { return "RenderSVGRoot"; } + virtual bool isSVGRoot() const OVERRIDE { return true; } + virtual bool isSVG() const OVERRIDE { return true; } virtual LayoutUnit computeReplacedLogicalWidth(ShouldComputePreferred = ComputeActual) const OVERRIDE; - virtual LayoutUnit computeReplacedLogicalHeight() const; - virtual void layout(); - virtual void paintReplaced(PaintInfo&, const LayoutPoint&); + virtual LayoutUnit computeReplacedLogicalHeight() const OVERRIDE; + virtual void layout() OVERRIDE; + virtual void paintReplaced(PaintInfo&, const LayoutPoint&) OVERRIDE; - virtual void willBeDestroyed(); - virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); + virtual void willBeDestroyed() OVERRIDE; + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) OVERRIDE; + virtual bool isChildAllowed(RenderObject*, RenderStyle*) const OVERRIDE; virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0) OVERRIDE; virtual void removeChild(RenderObject*) OVERRIDE; + virtual bool canHaveWhitespaceChildren() const OVERRIDE { return false; } virtual void insertedIntoTree() OVERRIDE; virtual void willBeRemovedFromTree() OVERRIDE; - virtual const AffineTransform& localToParentTransform() const; + virtual const AffineTransform& localToParentTransform() const OVERRIDE; - virtual FloatRect objectBoundingBox() const { return m_objectBoundingBox; } - virtual FloatRect strokeBoundingBox() const { return m_strokeBoundingBox; } - virtual FloatRect repaintRectInLocalCoordinates() const { return m_repaintBoundingBox; } + virtual FloatRect objectBoundingBox() const OVERRIDE { return m_objectBoundingBox; } + virtual FloatRect strokeBoundingBox() const OVERRIDE { return m_strokeBoundingBox; } + virtual FloatRect paintInvalidationRectInLocalCoordinates() const OVERRIDE { return m_repaintBoundingBox; } virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; - virtual LayoutRect clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const OVERRIDE; - virtual void computeFloatRectForRepaint(const RenderLayerModelObject* repaintContainer, FloatRect& repaintRect, bool fixed) const OVERRIDE; + virtual LayoutRect clippedOverflowRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer) const OVERRIDE; + virtual void computeFloatRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer, FloatRect& paintInvalidationRect, bool fixed) const OVERRIDE; virtual void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = 0) const OVERRIDE; virtual const RenderObject* pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap&) const OVERRIDE; - virtual bool canBeSelectionLeaf() const { return false; } - virtual bool canHaveChildren() const { return true; } + virtual bool canBeSelectionLeaf() const OVERRIDE { return false; } + virtual bool canHaveChildren() const OVERRIDE { return true; } + bool shouldApplyViewportClip() const; void updateCachedBoundaries(); void buildLocalToBorderBoxTransform(); @@ -113,6 +122,7 @@ private: AffineTransform m_localToBorderBoxTransform; bool m_isLayoutSizeChanged : 1; bool m_needsBoundariesOrTransformUpdate : 1; + bool m_hasBoxDecorations : 1; }; DEFINE_RENDER_OBJECT_TYPE_CASTS(RenderSVGRoot, isSVGRoot()); diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGShape.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGShape.cpp index 04298f7e49d..dfd09e70aef 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGShape.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGShape.cpp @@ -26,17 +26,16 @@ */ #include "config.h" - #include "core/rendering/svg/RenderSVGShape.h" #include "core/rendering/GraphicsContextAnnotator.h" #include "core/rendering/HitTestRequest.h" -#include "core/rendering/LayoutRectRecorder.h" #include "core/rendering/LayoutRepainter.h" #include "core/rendering/PointerEventsHitRules.h" #include "core/rendering/svg/RenderSVGResourceMarker.h" #include "core/rendering/svg/RenderSVGResourceSolidColor.h" #include "core/rendering/svg/SVGPathData.h" +#include "core/rendering/svg/SVGRenderSupport.h" #include "core/rendering/svg/SVGRenderingContext.h" #include "core/rendering/svg/SVGResources.h" #include "core/rendering/svg/SVGResourcesCache.h" @@ -63,7 +62,7 @@ void RenderSVGShape::updateShapeFromElement() { m_path.clear(); m_path = adoptPtr(new Path); - ASSERT(RenderSVGShape::isEmpty()); + ASSERT(RenderSVGShape::isShapeEmpty()); updatePathFromGraphicsElement(toSVGGraphicsElement(element()), path()); processMarkerPositions(); @@ -72,11 +71,6 @@ void RenderSVGShape::updateShapeFromElement() m_strokeBoundingBox = calculateStrokeBoundingBox(); } -bool RenderSVGShape::isEmpty() const -{ - return path().isEmpty(); -} - void RenderSVGShape::fillShape(GraphicsContext* context) const { context->fillPath(path()); @@ -119,8 +113,8 @@ bool RenderSVGShape::fillContains(const FloatPoint& point, bool requiresFill, co if (!m_fillBoundingBox.contains(point)) return false; - Color fallbackColor; - if (requiresFill && !RenderSVGResource::fillPaintingResource(this, style(), fallbackColor)) + bool hasFallback; + if (requiresFill && !RenderSVGResource::fillPaintingResource(this, style(), hasFallback)) return false; return shapeDependentFillContains(point, fillRule); @@ -131,8 +125,8 @@ bool RenderSVGShape::strokeContains(const FloatPoint& point, bool requiresStroke if (!strokeBoundingBox().contains(point)) return false; - Color fallbackColor; - if (requiresStroke && !RenderSVGResource::strokePaintingResource(this, style(), fallbackColor)) + bool hasFallback; + if (requiresStroke && !RenderSVGResource::strokePaintingResource(this, style(), hasFallback)) return false; return shapeDependentStrokeContains(point); @@ -140,7 +134,6 @@ bool RenderSVGShape::strokeContains(const FloatPoint& point, bool requiresStroke void RenderSVGShape::layout() { - LayoutRectRecorder recorder(*this); LayoutRepainter repainter(*this, SVGRenderSupport::checkForSVGRepaintDuringLayout(this) && selfNeedsLayout()); bool updateCachedBoundariesInParents = false; @@ -201,7 +194,7 @@ bool RenderSVGShape::shouldGenerateMarkerPositions() const if (!style()->svgStyle()->hasMarkers()) return false; - if (!toSVGGraphicsElement(element())->supportsMarkers()) + if (!SVGResources::supportsMarkers(*toSVGGraphicsElement(element()))) return false; SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(this); @@ -213,13 +206,12 @@ bool RenderSVGShape::shouldGenerateMarkerPositions() const void RenderSVGShape::fillShape(RenderStyle* style, GraphicsContext* context) { - Color fallbackColor; - if (RenderSVGResource* fillPaintingResource = RenderSVGResource::fillPaintingResource(this, style, fallbackColor)) { - if (fillPaintingResource->applyResource(this, style, context, ApplyToFillMode)) + bool hasFallback; + if (RenderSVGResource* fillPaintingResource = RenderSVGResource::fillPaintingResource(this, style, hasFallback)) { + if (fillPaintingResource->applyResource(this, style, context, ApplyToFillMode)) { fillPaintingResource->postApplyResource(this, context, ApplyToFillMode, 0, this); - else if (fallbackColor.isValid()) { + } else if (hasFallback) { RenderSVGResourceSolidColor* fallbackResource = RenderSVGResource::sharedSolidPaintingResource(); - fallbackResource->setColor(fallbackColor); if (fallbackResource->applyResource(this, style, context, ApplyToFillMode)) fallbackResource->postApplyResource(this, context, ApplyToFillMode, 0, this); } @@ -228,13 +220,12 @@ void RenderSVGShape::fillShape(RenderStyle* style, GraphicsContext* context) void RenderSVGShape::strokeShape(RenderStyle* style, GraphicsContext* context) { - Color fallbackColor; - if (RenderSVGResource* strokePaintingResource = RenderSVGResource::strokePaintingResource(this, style, fallbackColor)) { - if (strokePaintingResource->applyResource(this, style, context, ApplyToStrokeMode)) + bool hasFallback; + if (RenderSVGResource* strokePaintingResource = RenderSVGResource::strokePaintingResource(this, style, hasFallback)) { + if (strokePaintingResource->applyResource(this, style, context, ApplyToStrokeMode)) { strokePaintingResource->postApplyResource(this, context, ApplyToStrokeMode, 0, this); - else if (fallbackColor.isValid()) { + } else if (hasFallback) { RenderSVGResourceSolidColor* fallbackResource = RenderSVGResource::sharedSolidPaintingResource(); - fallbackResource->setColor(fallbackColor); if (fallbackResource->applyResource(this, style, context, ApplyToStrokeMode)) fallbackResource->postApplyResource(this, context, ApplyToStrokeMode, 0, this); } @@ -244,68 +235,67 @@ void RenderSVGShape::strokeShape(RenderStyle* style, GraphicsContext* context) void RenderSVGShape::paint(PaintInfo& paintInfo, const LayoutPoint&) { ANNOTATE_GRAPHICS_CONTEXT(paintInfo, this); - - if (paintInfo.context->paintingDisabled() || style()->visibility() == HIDDEN || isEmpty()) + if (paintInfo.context->paintingDisabled() + || paintInfo.phase != PaintPhaseForeground + || style()->visibility() == HIDDEN + || isShapeEmpty()) return; - FloatRect boundingBox = repaintRectInLocalCoordinates(); + + FloatRect boundingBox = paintInvalidationRectInLocalCoordinates(); if (!SVGRenderSupport::paintInfoIntersectsRepaintRect(boundingBox, m_localTransform, paintInfo)) return; PaintInfo childPaintInfo(paintInfo); - bool drawsOutline = style()->outlineWidth() && (childPaintInfo.phase == PaintPhaseOutline || childPaintInfo.phase == PaintPhaseSelfOutline); - if (drawsOutline || childPaintInfo.phase == PaintPhaseForeground) { - GraphicsContextStateSaver stateSaver(*childPaintInfo.context); - childPaintInfo.applyTransform(m_localTransform); - - if (childPaintInfo.phase == PaintPhaseForeground) { - SVGRenderingContext renderingContext(this, childPaintInfo); - - if (renderingContext.isRenderingPrepared()) { - const SVGRenderStyle* svgStyle = style()->svgStyle(); - if (svgStyle->shapeRendering() == SR_CRISPEDGES) - childPaintInfo.context->setShouldAntialias(false); - - for (int i = 0; i < 3; i++) { - switch (svgStyle->paintOrderType(i)) { - case PT_FILL: - fillShape(this->style(), childPaintInfo.context); - break; - case PT_STROKE: - if (svgStyle->hasVisibleStroke()) { - GraphicsContextStateSaver stateSaver(*childPaintInfo.context, false); - AffineTransform nonScalingTransform; - - if (hasNonScalingStroke()) { - AffineTransform nonScalingTransform = nonScalingStrokeTransform(); - if (!setupNonScalingStrokeContext(nonScalingTransform, stateSaver)) - return; - } - - strokeShape(this->style(), childPaintInfo.context); - } - break; - case PT_MARKERS: - if (!m_markerPositions.isEmpty()) - drawMarkers(childPaintInfo); - break; - default: - ASSERT_NOT_REACHED(); - break; + + GraphicsContextStateSaver stateSaver(*childPaintInfo.context); + childPaintInfo.applyTransform(m_localTransform); + + SVGRenderingContext renderingContext(this, childPaintInfo); + + if (renderingContext.isRenderingPrepared()) { + const SVGRenderStyle* svgStyle = style()->svgStyle(); + if (svgStyle->shapeRendering() == SR_CRISPEDGES) + childPaintInfo.context->setShouldAntialias(false); + + for (int i = 0; i < 3; i++) { + switch (svgStyle->paintOrderType(i)) { + case PT_FILL: + fillShape(this->style(), childPaintInfo.context); + break; + case PT_STROKE: + if (svgStyle->hasVisibleStroke()) { + GraphicsContextStateSaver stateSaver(*childPaintInfo.context, false); + AffineTransform nonScalingTransform; + + if (hasNonScalingStroke()) { + AffineTransform nonScalingTransform = nonScalingStrokeTransform(); + if (!setupNonScalingStrokeContext(nonScalingTransform, stateSaver)) + return; } + + strokeShape(this->style(), childPaintInfo.context); } + break; + case PT_MARKERS: + if (!m_markerPositions.isEmpty()) + drawMarkers(childPaintInfo); + break; + default: + ASSERT_NOT_REACHED(); + break; } } - - if (drawsOutline) - paintOutline(childPaintInfo, IntRect(boundingBox)); } + + if (style()->outlineWidth()) + paintOutline(childPaintInfo, IntRect(boundingBox)); } // This method is called from inside paintOutline() since we call paintOutline() // while transformed to our coord system, return local coords void RenderSVGShape::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint&, const RenderLayerModelObject*) { - IntRect rect = enclosingIntRect(repaintRectInLocalCoordinates()); + IntRect rect = enclosingIntRect(paintInvalidationRectInLocalCoordinates()); if (!rect.isEmpty()) rects.append(rect); } @@ -417,7 +407,7 @@ FloatRect RenderSVGShape::calculateStrokeBoundingBox() const void RenderSVGShape::updateRepaintBoundingBox() { m_repaintBoundingBox = strokeBoundingBox(); - if (strokeWidth() < 1.0f) + if (strokeWidth() < 1.0f && !m_repaintBoundingBox.isEmpty()) m_repaintBoundingBox.inflate(1); SVGRenderSupport::intersectRepaintRectWithResources(this, m_repaintBoundingBox); } @@ -425,13 +415,13 @@ void RenderSVGShape::updateRepaintBoundingBox() float RenderSVGShape::strokeWidth() const { SVGLengthContext lengthContext(element()); - return style()->svgStyle()->strokeWidth().value(lengthContext); + return style()->svgStyle()->strokeWidth()->value(lengthContext); } bool RenderSVGShape::hasSmoothStroke() const { const SVGRenderStyle* svgStyle = style()->svgStyle(); - return svgStyle->strokeDashArray().isEmpty() + return svgStyle->strokeDashArray()->isEmpty() && svgStyle->strokeMiterLimit() == svgStyle->initialStrokeMiterLimit() && svgStyle->joinStyle() == svgStyle->initialJoinStyle() && svgStyle->capStyle() == svgStyle->initialCapStyle(); diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGShape.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGShape.h index f800b2db555..12a703f063b 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGShape.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGShape.h @@ -38,9 +38,6 @@ namespace WebCore { class FloatPoint; class GraphicsContextStateSaver; class PointerEventsHitRules; -class RenderSVGContainer; -class RenderSVGPath; -class RenderSVGResource; class SVGGraphicsElement; class RenderSVGShape : public RenderSVGModelObject { @@ -51,7 +48,6 @@ public: void setNeedsShapeUpdate() { m_needsShapeUpdate = true; } virtual void setNeedsBoundariesUpdate() OVERRIDE FINAL { m_needsBoundariesUpdate = true; } - virtual bool needsBoundariesUpdate() OVERRIDE FINAL { return m_needsBoundariesUpdate; } virtual void setNeedsTransformUpdate() OVERRIDE FINAL { m_needsTransformUpdate = true; } virtual void fillShape(GraphicsContext*) const; virtual void strokeShape(GraphicsContext*) const; @@ -66,7 +62,7 @@ public: protected: virtual void updateShapeFromElement(); - virtual bool isEmpty() const; + virtual bool isShapeEmpty() const { return path().isEmpty(); } virtual bool shapeDependentStrokeContains(const FloatPoint&); virtual bool shapeDependentFillContains(const FloatPoint&, const WindRule) const; float strokeWidth() const; @@ -85,12 +81,12 @@ private: bool fillContains(const FloatPoint&, bool requiresFill = true, const WindRule fillRule = RULE_NONZERO); bool strokeContains(const FloatPoint&, bool requiresStroke = true); - virtual FloatRect repaintRectInLocalCoordinates() const OVERRIDE FINAL { return m_repaintBoundingBox; } + virtual FloatRect paintInvalidationRectInLocalCoordinates() const OVERRIDE FINAL { return m_repaintBoundingBox; } virtual const AffineTransform& localToParentTransform() const OVERRIDE FINAL { return m_localTransform; } virtual AffineTransform localTransform() const OVERRIDE FINAL { return m_localTransform; } virtual bool isSVGShape() const OVERRIDE FINAL { return true; } - virtual const char* renderName() const { return "RenderSVGShape"; } + virtual const char* renderName() const OVERRIDE { return "RenderSVGShape"; } virtual void layout() OVERRIDE FINAL; virtual void paint(PaintInfo&, const LayoutPoint&) OVERRIDE FINAL; @@ -116,7 +112,6 @@ private: private: FloatRect m_repaintBoundingBox; - FloatRect m_repaintBoundingBoxExcludingShadow; AffineTransform m_localTransform; OwnPtr<Path> m_path; Vector<MarkerPosition> m_markerPositions; diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGTSpan.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGTSpan.cpp index 5f34538620b..30c06454d59 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGTSpan.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGTSpan.cpp @@ -24,6 +24,9 @@ #include "core/rendering/svg/RenderSVGTSpan.h" +#include "core/rendering/svg/SVGRenderSupport.h" +#include "core/svg/SVGAltGlyphElement.h" + namespace WebCore { RenderSVGTSpan::RenderSVGTSpan(Element* element) @@ -31,4 +34,20 @@ RenderSVGTSpan::RenderSVGTSpan(Element* element) { } +bool RenderSVGTSpan::isChildAllowed(RenderObject* child, RenderStyle*) const +{ + // Always allow text (except empty textnodes and <br>). + if (child->isText()) + return SVGRenderSupport::isRenderableTextNode(child); + +#if ENABLE(SVG_FONTS) + // Only allow other types of children if this is not an 'altGlyph'. + ASSERT(node()); + if (isSVGAltGlyphElement(*node())) + return false; +#endif + + return child->isSVGInline() && !child->isSVGTextPath(); +} + } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGTSpan.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGTSpan.h index ba8cb31e1e0..7875119a34f 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGTSpan.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGTSpan.h @@ -28,7 +28,10 @@ namespace WebCore { class RenderSVGTSpan FINAL : public RenderSVGInline { public: explicit RenderSVGTSpan(Element*); - virtual const char* renderName() const { return "RenderSVGTSpan"; } + + virtual bool isChildAllowed(RenderObject* child, RenderStyle*) const OVERRIDE; + + virtual const char* renderName() const OVERRIDE { return "RenderSVGTSpan"; } }; } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGText.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGText.cpp index ba45ce98f18..8536029524b 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGText.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGText.cpp @@ -30,10 +30,11 @@ #include "core/rendering/HitTestRequest.h" #include "core/rendering/HitTestResult.h" -#include "core/rendering/LayoutRectRecorder.h" #include "core/rendering/LayoutRepainter.h" +#include "core/rendering/PaintInfo.h" #include "core/rendering/PointerEventsHitRules.h" #include "core/rendering/style/ShadowList.h" +#include "core/rendering/svg/RenderSVGInline.h" #include "core/rendering/svg/RenderSVGInlineText.h" #include "core/rendering/svg/RenderSVGResource.h" #include "core/rendering/svg/RenderSVGRoot.h" @@ -70,7 +71,7 @@ RenderSVGText::~RenderSVGText() bool RenderSVGText::isChildAllowed(RenderObject* child, RenderStyle*) const { - return child->isInline() && !SVGRenderSupport::isEmptySVGInlineText(child); + return child->isSVGInline() || (child->isText() && SVGRenderSupport::isRenderableTextNode(child)); } RenderSVGText* RenderSVGText::locateRenderSVGTextAncestor(RenderObject* start) @@ -93,33 +94,13 @@ const RenderSVGText* RenderSVGText::locateRenderSVGTextAncestor(const RenderObje return toRenderSVGText(start); } -LayoutRect RenderSVGText::clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const -{ - return SVGRenderSupport::clippedOverflowRectForRepaint(this, repaintContainer); -} - -void RenderSVGText::computeRectForRepaint(const RenderLayerModelObject* repaintContainer, LayoutRect& rect, bool fixed) const +void RenderSVGText::mapRectToPaintInvalidationBacking(const RenderLayerModelObject* paintInvalidationContainer, LayoutRect& rect, bool fixed) const { FloatRect repaintRect = rect; - computeFloatRectForRepaint(repaintContainer, repaintRect, fixed); + computeFloatRectForPaintInvalidation(paintInvalidationContainer, repaintRect, fixed); rect = enclosingLayoutRect(repaintRect); } -void RenderSVGText::computeFloatRectForRepaint(const RenderLayerModelObject* repaintContainer, FloatRect& repaintRect, bool fixed) const -{ - SVGRenderSupport::computeFloatRectForRepaint(this, repaintContainer, repaintRect, fixed); -} - -void RenderSVGText::mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState& transformState, MapCoordinatesFlags, bool* wasFixed) const -{ - SVGRenderSupport::mapLocalToContainer(this, repaintContainer, transformState, wasFixed); -} - -const RenderObject* RenderSVGText::pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap& geometryMap) const -{ - return SVGRenderSupport::pushMappingToContainer(this, ancestorToStopAt, geometryMap); -} - static inline void collectLayoutAttributes(RenderObject* text, Vector<SVGTextLayoutAttributes*>& attributes) { for (RenderObject* descendant = text; descendant; descendant = descendant->nextInPreOrder(text)) { @@ -128,14 +109,15 @@ static inline void collectLayoutAttributes(RenderObject* text, Vector<SVGTextLay } } -static inline bool findPreviousAndNextAttributes(RenderObject* start, RenderSVGInlineText* locateElement, bool& stopAfterNext, SVGTextLayoutAttributes*& previous, SVGTextLayoutAttributes*& next) +static inline bool findPreviousAndNextAttributes(RenderSVGText* root, RenderSVGInlineText* locateElement, SVGTextLayoutAttributes*& previous, SVGTextLayoutAttributes*& next) { - ASSERT(start); + ASSERT(root); ASSERT(locateElement); - // FIXME: Make this iterative. - for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) { - if (child->isSVGInlineText()) { - RenderSVGInlineText* text = toRenderSVGInlineText(child); + bool stopAfterNext = false; + RenderObject* current = root->firstChild(); + while (current) { + if (current->isSVGInlineText()) { + RenderSVGInlineText* text = toRenderSVGInlineText(current); if (locateElement != text) { if (stopAfterNext) { next = text->layoutAttributes(); @@ -143,20 +125,19 @@ static inline bool findPreviousAndNextAttributes(RenderObject* start, RenderSVGI } previous = text->layoutAttributes(); + } else { + stopAfterNext = true; + } + } else if (current->isSVGInline()) { + // Descend into text content (if possible). + if (RenderObject* child = toRenderSVGInline(current)->firstChild()) { + current = child; continue; } - - stopAfterNext = true; - continue; } - if (!child->isSVGInline()) - continue; - - if (findPreviousAndNextAttributes(child, locateElement, stopAfterNext, previous, next)) - return true; + current = current->nextInPreOrderAfterChildren(root); } - return false; } @@ -201,11 +182,10 @@ void RenderSVGText::subtreeChildWasAdded(RenderObject* child) attributes = newLayoutAttributes[i]; if (m_layoutAttributes.find(attributes) == kNotFound) { // Every time this is invoked, there's only a single new entry in the newLayoutAttributes list, compared to the old in m_layoutAttributes. - bool stopAfterNext = false; SVGTextLayoutAttributes* previous = 0; SVGTextLayoutAttributes* next = 0; ASSERT_UNUSED(child, attributes->context() == child); - findPreviousAndNextAttributes(this, attributes->context(), stopAfterNext, previous, next); + findPreviousAndNextAttributes(this, attributes->context(), previous, next); if (previous) m_layoutAttributesBuilder.buildLayoutAttributesForTextRenderer(previous->context()); @@ -258,11 +238,10 @@ void RenderSVGText::subtreeChildWillBeRemoved(RenderObject* child, Vector<SVGTex // This logic requires that the 'text' child is still inserted in the tree. RenderSVGInlineText* text = toRenderSVGInlineText(child); - bool stopAfterNext = false; SVGTextLayoutAttributes* previous = 0; SVGTextLayoutAttributes* next = 0; if (!documentBeingDestroyed()) - findPreviousAndNextAttributes(this, text, stopAfterNext, previous, next); + findPreviousAndNextAttributes(this, text, previous, next); if (previous) affectedAttributes.append(previous); @@ -288,9 +267,8 @@ void RenderSVGText::subtreeChildWasRemoved(const Vector<SVGTextLayoutAttributes* m_layoutAttributesBuilder.buildLayoutAttributesForTextRenderer(affectedAttributes[i]->context()); } -void RenderSVGText::subtreeStyleDidChange(RenderSVGInlineText* text) +void RenderSVGText::subtreeStyleDidChange() { - ASSERT(text); if (!shouldHandleSubtreeMutations() || documentBeingDestroyed()) return; @@ -299,7 +277,7 @@ void RenderSVGText::subtreeStyleDidChange(RenderSVGInlineText* text) // Only update the metrics cache, but not the text positioning element cache // nor the layout attributes cached in the leaf #text renderers. FontCachePurgePreventer fontCachePurgePreventer; - for (RenderObject* descendant = text; descendant; descendant = descendant->nextInPreOrder(text)) { + for (RenderObject* descendant = firstChild(); descendant; descendant = descendant->nextInPreOrder(this)) { if (descendant->isSVGInlineText()) m_layoutAttributesBuilder.rebuildMetricsForTextRenderer(toRenderSVGInlineText(descendant)); } @@ -344,7 +322,9 @@ static inline void updateFontInAllDescendants(RenderObject* start, SVGTextLayout void RenderSVGText::layout() { ASSERT(needsLayout()); - LayoutRectRecorder recorder(*this); + + subtreeStyleDidChange(); + LayoutRepainter repainter(*this, SVGRenderSupport::checkForSVGRepaintDuringLayout(this)); bool updateCachedBoundariesInParents = false; @@ -408,7 +388,16 @@ void RenderSVGText::layout() // FIXME: We need to find a way to only layout the child boxes, if needed. FloatRect oldBoundaries = objectBoundingBox(); ASSERT(childrenInline()); - forceLayoutInlineChildren(); + + rebuildFloatsFromIntruding(); + + LayoutUnit beforeEdge = borderBefore() + paddingBefore(); + LayoutUnit afterEdge = borderAfter() + paddingAfter() + scrollbarLogicalHeight(); + setLogicalHeight(beforeEdge); + + LayoutUnit repaintLogicalTop = 0; + LayoutUnit repaintLogicalBottom = 0; + layoutInlineChildren(true, repaintLogicalTop, repaintLogicalBottom, afterEdge); if (m_needsReordering) m_needsReordering = false; @@ -430,7 +419,7 @@ void RenderSVGText::layout() RootInlineBox* RenderSVGText::createRootInlineBox() { - RootInlineBox* box = new SVGRootInlineBox(this); + RootInlineBox* box = new SVGRootInlineBox(*this); box->setHasVirtualLogicalHeight(); return box; } @@ -458,12 +447,6 @@ bool RenderSVGText::nodeAtFloatPoint(const HitTestRequest& request, HitTestResul return false; } -bool RenderSVGText::nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation&, const LayoutPoint&, HitTestAction) -{ - ASSERT_NOT_REACHED(); - return false; -} - PositionWithAffinity RenderSVGText::positionForPoint(const LayoutPoint& pointInContents) { RootInlineBox* rootBox = firstRootBox(); @@ -477,7 +460,7 @@ PositionWithAffinity RenderSVGText::positionForPoint(const LayoutPoint& pointInC if (!closestBox) return createPositionWithAffinity(0, DOWNSTREAM); - return closestBox->renderer()->positionForPoint(LayoutPoint(pointInContents.x(), closestBox->y())); + return closestBox->renderer().positionForPoint(LayoutPoint(pointInContents.x(), closestBox->y())); } void RenderSVGText::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const @@ -491,14 +474,23 @@ void RenderSVGText::paint(PaintInfo& paintInfo, const LayoutPoint&) return; if (paintInfo.phase != PaintPhaseForeground - && paintInfo.phase != PaintPhaseSelfOutline && paintInfo.phase != PaintPhaseSelection) return; PaintInfo blockInfo(paintInfo); - GraphicsContextStateSaver stateSaver(*blockInfo.context); - blockInfo.applyTransform(localToParentTransform()); + GraphicsContextStateSaver stateSaver(*blockInfo.context, false); + const AffineTransform& localTransform = localToParentTransform(); + if (!localTransform.isIdentity()) { + stateSaver.save(); + blockInfo.applyTransform(localTransform, false); + } RenderBlock::paint(blockInfo, LayoutPoint()); + + // Paint the outlines, if any + if (paintInfo.phase == PaintPhaseForeground) { + blockInfo.phase = PaintPhaseSelfOutline; + RenderBlock::paint(blockInfo, LayoutPoint()); + } } FloatRect RenderSVGText::strokeBoundingBox() const @@ -511,11 +503,11 @@ FloatRect RenderSVGText::strokeBoundingBox() const ASSERT(node()); ASSERT(node()->isSVGElement()); SVGLengthContext lengthContext(toSVGElement(node())); - strokeBoundaries.inflate(svgStyle->strokeWidth().value(lengthContext)); + strokeBoundaries.inflate(svgStyle->strokeWidth()->value(lengthContext)); return strokeBoundaries; } -FloatRect RenderSVGText::repaintRectInLocalCoordinates() const +FloatRect RenderSVGText::paintInvalidationRectInLocalCoordinates() const { FloatRect repaintRect = strokeBoundingBox(); SVGRenderSupport::intersectRepaintRectWithResources(this, repaintRect); diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGText.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGText.h index 56fb0db8e49..dfac5394a68 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGText.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGText.h @@ -37,12 +37,12 @@ public: explicit RenderSVGText(SVGTextElement*); virtual ~RenderSVGText(); - virtual bool isChildAllowed(RenderObject*, RenderStyle*) const; + virtual bool isChildAllowed(RenderObject*, RenderStyle*) const OVERRIDE; void setNeedsPositioningValuesUpdate() { m_needsPositioningValuesUpdate = true; } - virtual void setNeedsTransformUpdate() { m_needsTransformUpdate = true; } + virtual void setNeedsTransformUpdate() OVERRIDE { m_needsTransformUpdate = true; } void setNeedsTextMetricsUpdate() { m_needsTextMetricsUpdate = true; } - virtual FloatRect repaintRectInLocalCoordinates() const; + virtual FloatRect paintInvalidationRectInLocalCoordinates() const OVERRIDE; static RenderSVGText* locateRenderSVGTextAncestor(RenderObject*); static const RenderSVGText* locateRenderSVGTextAncestor(const RenderObject*); @@ -53,42 +53,35 @@ public: void subtreeChildWasAdded(RenderObject*); void subtreeChildWillBeRemoved(RenderObject*, Vector<SVGTextLayoutAttributes*, 2>& affectedAttributes); void subtreeChildWasRemoved(const Vector<SVGTextLayoutAttributes*, 2>& affectedAttributes); - void subtreeStyleDidChange(RenderSVGInlineText*); + void subtreeStyleDidChange(); void subtreeTextDidChange(RenderSVGInlineText*); private: - virtual const char* renderName() const { return "RenderSVGText"; } - virtual bool isSVGText() const { return true; } + virtual const char* renderName() const OVERRIDE { return "RenderSVGText"; } + virtual bool isSVGText() const OVERRIDE { return true; } - virtual void paint(PaintInfo&, const LayoutPoint&); - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; - virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction); - virtual PositionWithAffinity positionForPoint(const LayoutPoint&) OVERRIDE FINAL; + virtual void paint(PaintInfo&, const LayoutPoint&) OVERRIDE; + virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction) OVERRIDE; + virtual PositionWithAffinity positionForPoint(const LayoutPoint&) OVERRIDE; - virtual bool requiresLayer() const { return false; } - virtual void layout(); + virtual void layout() OVERRIDE; - virtual void absoluteQuads(Vector<FloatQuad>&, bool* wasFixed) const; + virtual void absoluteQuads(Vector<FloatQuad>&, bool* wasFixed) const OVERRIDE; - virtual LayoutRect clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const OVERRIDE; - virtual void computeRectForRepaint(const RenderLayerModelObject* repaintContainer, LayoutRect&, bool fixed = false) const OVERRIDE; - virtual void computeFloatRectForRepaint(const RenderLayerModelObject* repaintContainer, FloatRect&, bool fixed = false) const OVERRIDE; + virtual void mapRectToPaintInvalidationBacking(const RenderLayerModelObject* paintInvalidationContainer, LayoutRect&, bool fixed = false) const OVERRIDE; - virtual void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = 0) const OVERRIDE; - virtual const RenderObject* pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap&) const OVERRIDE; - virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0); + virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0) OVERRIDE; virtual void removeChild(RenderObject*) OVERRIDE; virtual void willBeDestroyed() OVERRIDE; - virtual FloatRect objectBoundingBox() const { return frameRect(); } - virtual FloatRect strokeBoundingBox() const; + virtual FloatRect objectBoundingBox() const OVERRIDE { return frameRect(); } + virtual FloatRect strokeBoundingBox() const OVERRIDE; - virtual const AffineTransform& localToParentTransform() const { return m_localTransform; } - virtual AffineTransform localTransform() const { return m_localTransform; } - virtual RootInlineBox* createRootInlineBox(); + virtual const AffineTransform& localToParentTransform() const OVERRIDE { return m_localTransform; } + virtual RootInlineBox* createRootInlineBox() OVERRIDE; - virtual RenderBlock* firstLineBlock() const; - virtual void updateFirstLetter(); + virtual RenderBlock* firstLineBlock() const OVERRIDE; + virtual void updateFirstLetter() OVERRIDE; bool shouldHandleSubtreeMutations() const; @@ -96,7 +89,6 @@ private: bool m_needsPositioningValuesUpdate : 1; bool m_needsTransformUpdate : 1; bool m_needsTextMetricsUpdate : 1; - AffineTransform m_localTransform; SVGTextLayoutAttributesBuilder m_layoutAttributesBuilder; Vector<SVGTextLayoutAttributes*> m_layoutAttributes; }; diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGTextPath.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGTextPath.cpp index aec2da5ac29..f9deafa7276 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGTextPath.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGTextPath.cpp @@ -21,8 +21,8 @@ #include "core/rendering/svg/RenderSVGTextPath.h" -#include "SVGNames.h" #include "core/rendering/svg/SVGPathData.h" +#include "core/rendering/svg/SVGRenderSupport.h" #include "core/svg/SVGPathElement.h" #include "core/svg/SVGTextPathElement.h" @@ -33,30 +33,45 @@ RenderSVGTextPath::RenderSVGTextPath(Element* element) { } +bool RenderSVGTextPath::isChildAllowed(RenderObject* child, RenderStyle*) const +{ + if (child->isText()) + return SVGRenderSupport::isRenderableTextNode(child); + +#if ENABLE(SVG_FONTS) + // 'altGlyph' is supported by the content model for 'textPath', but... + ASSERT(child->node()); + if (isSVGAltGlyphElement(*child->node())) + return false; +#endif + + return child->isSVGInline() && !child->isSVGTextPath(); +} + Path RenderSVGTextPath::layoutPath() const { SVGTextPathElement* textPathElement = toSVGTextPathElement(node()); - Element* targetElement = SVGURIReference::targetElementFromIRIString(textPathElement->hrefCurrentValue(), textPathElement->document()); - if (!targetElement || !targetElement->hasTagName(SVGNames::pathTag)) + Element* targetElement = SVGURIReference::targetElementFromIRIString(textPathElement->href()->currentValue()->value(), textPathElement->treeScope()); + if (!isSVGPathElement(targetElement)) return Path(); - SVGPathElement* pathElement = toSVGPathElement(targetElement); + SVGPathElement& pathElement = toSVGPathElement(*targetElement); Path pathData; - updatePathFromGraphicsElement(pathElement, pathData); + updatePathFromGraphicsElement(&pathElement, pathData); // Spec: The transform attribute on the referenced 'path' element represents a // supplemental transformation relative to the current user coordinate system for // the current 'text' element, including any adjustments to the current user coordinate // system due to a possible transform attribute on the current 'text' element. // http://www.w3.org/TR/SVG/text.html#TextPathElement - pathData.transform(pathElement->animatedLocalTransform()); + pathData.transform(pathElement.animatedLocalTransform()); return pathData; } float RenderSVGTextPath::startOffset() const { - return toSVGTextPathElement(node())->startOffsetCurrentValue().valueAsPercentage(); + return toSVGTextPathElement(node())->startOffset()->currentValue()->valueAsPercentage(); } } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGTextPath.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGTextPath.h index 6e14b5528f6..6d98871341f 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGTextPath.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGTextPath.h @@ -32,10 +32,12 @@ public: Path layoutPath() const; float startOffset() const; - virtual bool isSVGTextPath() const { return true; } + virtual bool isChildAllowed(RenderObject*, RenderStyle*) const OVERRIDE; + + virtual bool isSVGTextPath() const OVERRIDE { return true; } private: - virtual const char* renderName() const { return "RenderSVGTextPath"; } + virtual const char* renderName() const OVERRIDE { return "RenderSVGTextPath"; } Path m_layoutPath; }; diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGTransformableContainer.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGTransformableContainer.cpp index 52516c4c268..841bec55ec1 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGTransformableContainer.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGTransformableContainer.cpp @@ -23,8 +23,8 @@ #include "core/rendering/svg/RenderSVGTransformableContainer.h" -#include "SVGNames.h" #include "core/rendering/svg/SVGRenderSupport.h" +#include "core/svg/SVGGElement.h" #include "core/svg/SVGGraphicsElement.h" #include "core/svg/SVGUseElement.h" @@ -37,25 +37,60 @@ RenderSVGTransformableContainer::RenderSVGTransformableContainer(SVGGraphicsElem { } +static bool hasValidPredecessor(const Node* node) +{ + ASSERT(node); + while ((node = node->previousSibling())) { + if (node->isSVGElement() && toSVGElement(node)->isValid()) + return true; + } + return false; +} + +bool RenderSVGTransformableContainer::isChildAllowed(RenderObject* child, RenderStyle* style) const +{ + ASSERT(element()); + if (isSVGSwitchElement(*element())) { + Node* node = child->node(); + // Reject non-SVG/non-valid elements. + if (!node->isSVGElement() || !toSVGElement(node)->isValid()) + return false; + // Reject this child if it isn't the first valid node. + if (hasValidPredecessor(node)) + return false; + } else if (isSVGAElement(*element())) { + // http://www.w3.org/2003/01/REC-SVG11-20030114-errata#linking-text-environment + // The 'a' element may contain any element that its parent may contain, except itself. + if (isSVGAElement(*child->node())) + return false; + if (parent() && parent()->isSVG()) + return parent()->isChildAllowed(child, style); + } + return RenderSVGContainer::isChildAllowed(child, style); +} + bool RenderSVGTransformableContainer::calculateLocalTransform() { SVGGraphicsElement* element = toSVGGraphicsElement(this->element()); + ASSERT(element); // If we're either the renderer for a <use> element, or for any <g> element inside the shadow // tree, that was created during the use/symbol/svg expansion in SVGUseElement. These containers // need to respect the translations induced by their corresponding use elements x/y attributes. SVGUseElement* useElement = 0; - if (element->hasTagName(SVGNames::useTag)) + if (isSVGUseElement(*element)) { useElement = toSVGUseElement(element); - else if (element->isInShadowTree() && element->hasTagName(SVGNames::gTag)) { + } else if (isSVGGElement(*element) && toSVGGElement(element)->inUseShadowTree()) { SVGElement* correspondingElement = element->correspondingElement(); - if (correspondingElement && correspondingElement->hasTagName(SVGNames::useTag)) + if (isSVGUseElement(correspondingElement)) useElement = toSVGUseElement(correspondingElement); } if (useElement) { SVGLengthContext lengthContext(useElement); - FloatSize translation(useElement->xCurrentValue().value(lengthContext), useElement->yCurrentValue().value(lengthContext)); + FloatSize translation( + useElement->x()->currentValue()->value(lengthContext), + useElement->y()->currentValue()->value(lengthContext)); if (translation != m_lastTranslation) m_needsTransformUpdate = true; m_lastTranslation = translation; diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGTransformableContainer.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGTransformableContainer.h index 6aa752aa95d..4b03d8a330d 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGTransformableContainer.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGTransformableContainer.h @@ -30,14 +30,16 @@ class RenderSVGTransformableContainer FINAL : public RenderSVGContainer { public: explicit RenderSVGTransformableContainer(SVGGraphicsElement*); - virtual bool isSVGTransformableContainer() const { return true; } - virtual const AffineTransform& localToParentTransform() const { return m_localTransform; } - virtual void setNeedsTransformUpdate() { m_needsTransformUpdate = true; } - virtual bool didTransformToRootUpdate() { return m_didTransformToRootUpdate; } + virtual bool isChildAllowed(RenderObject*, RenderStyle*) const OVERRIDE; + + virtual bool isSVGTransformableContainer() const OVERRIDE { return true; } + virtual const AffineTransform& localToParentTransform() const OVERRIDE { return m_localTransform; } + virtual void setNeedsTransformUpdate() OVERRIDE { m_needsTransformUpdate = true; } + virtual bool didTransformToRootUpdate() OVERRIDE { return m_didTransformToRootUpdate; } private: - virtual bool calculateLocalTransform(); - virtual AffineTransform localTransform() const { return m_localTransform; } + virtual bool calculateLocalTransform() OVERRIDE; + virtual AffineTransform localTransform() const OVERRIDE { return m_localTransform; } bool m_needsTransformUpdate : 1; bool m_didTransformToRootUpdate : 1; diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGViewportContainer.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGViewportContainer.cpp index 05234c18b57..4b4d3d5d4c3 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGViewportContainer.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGViewportContainer.cpp @@ -21,11 +21,10 @@ */ #include "config.h" - #include "core/rendering/svg/RenderSVGViewportContainer.h" -#include "SVGNames.h" -#include "core/svg/SVGElementInstance.h" +#include "core/rendering/PaintInfo.h" +#include "core/rendering/svg/SVGRenderSupport.h" #include "core/svg/SVGSVGElement.h" #include "core/svg/SVGUseElement.h" #include "platform/graphics/GraphicsContext.h" @@ -42,7 +41,8 @@ RenderSVGViewportContainer::RenderSVGViewportContainer(SVGElement* node) void RenderSVGViewportContainer::determineIfLayoutSizeChanged() { - if (!element()->hasTagName(SVGNames::svgTag)) + ASSERT(element()); + if (!isSVGSVGElement(*element())) return; m_isLayoutSizeChanged = toSVGSVGElement(element())->hasRelativeLengths() && selfNeedsLayout(); @@ -57,59 +57,14 @@ void RenderSVGViewportContainer::applyViewportClip(PaintInfo& paintInfo) void RenderSVGViewportContainer::calcViewport() { SVGElement* element = this->element(); - if (!element->hasTagName(SVGNames::svgTag)) + ASSERT(element); + if (!isSVGSVGElement(*element)) return; SVGSVGElement* svg = toSVGSVGElement(element); FloatRect oldViewport = m_viewport; SVGLengthContext lengthContext(element); - m_viewport = FloatRect(svg->xCurrentValue().value(lengthContext), svg->yCurrentValue().value(lengthContext), svg->widthCurrentValue().value(lengthContext), svg->heightCurrentValue().value(lengthContext)); - - SVGElement* correspondingElement = svg->correspondingElement(); - if (correspondingElement && svg->isInShadowTree()) { - const HashSet<SVGElementInstance*>& instances = correspondingElement->instancesForElement(); - ASSERT(!instances.isEmpty()); - - SVGUseElement* useElement = 0; - const HashSet<SVGElementInstance*>::const_iterator end = instances.end(); - for (HashSet<SVGElementInstance*>::const_iterator it = instances.begin(); it != end; ++it) { - const SVGElementInstance* instance = (*it); - ASSERT(instance->correspondingElement()->hasTagName(SVGNames::svgTag) || instance->correspondingElement()->hasTagName(SVGNames::symbolTag)); - if (instance->shadowTreeElement() == svg) { - ASSERT(correspondingElement == instance->correspondingElement()); - useElement = instance->directUseElement(); - if (!useElement) - useElement = instance->correspondingUseElement(); - break; - } - } - - ASSERT(useElement); - bool isSymbolElement = correspondingElement->hasTagName(SVGNames::symbolTag); - - // Spec (<use> on <symbol>): This generated 'svg' will always have explicit values for attributes width and height. - // If attributes width and/or height are provided on the 'use' element, then these attributes - // will be transferred to the generated 'svg'. If attributes width and/or height are not specified, - // the generated 'svg' element will use values of 100% for these attributes. - - // Spec (<use> on <svg>): If attributes width and/or height are provided on the 'use' element, then these - // values will override the corresponding attributes on the 'svg' in the generated tree. - - SVGLengthContext lengthContext(element); - if (useElement->hasAttribute(SVGNames::widthAttr)) - m_viewport.setWidth(useElement->widthCurrentValue().value(lengthContext)); - else if (isSymbolElement && svg->hasAttribute(SVGNames::widthAttr)) { - SVGLength containerWidth(LengthModeWidth, "100%"); - m_viewport.setWidth(containerWidth.value(lengthContext)); - } - - if (useElement->hasAttribute(SVGNames::heightAttr)) - m_viewport.setHeight(useElement->heightCurrentValue().value(lengthContext)); - else if (isSymbolElement && svg->hasAttribute(SVGNames::heightAttr)) { - SVGLength containerHeight(LengthModeHeight, "100%"); - m_viewport.setHeight(containerHeight.value(lengthContext)); - } - } + m_viewport = FloatRect(svg->x()->currentValue()->value(lengthContext), svg->y()->currentValue()->value(lengthContext), svg->width()->currentValue()->value(lengthContext), svg->height()->currentValue()->value(lengthContext)); if (oldViewport != m_viewport) { setNeedsBoundariesUpdate(); @@ -130,7 +85,8 @@ bool RenderSVGViewportContainer::calculateLocalTransform() AffineTransform RenderSVGViewportContainer::viewportTransform() const { - if (element()->hasTagName(SVGNames::svgTag)) { + ASSERT(element()); + if (isSVGSVGElement(*element())) { SVGSVGElement* svg = toSVGSVGElement(element()); return svg->viewBoxToViewTransform(m_viewport.width(), m_viewport.height()); } @@ -149,11 +105,10 @@ bool RenderSVGViewportContainer::pointIsInsideViewportClip(const FloatPoint& poi void RenderSVGViewportContainer::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { + ASSERT(element()); // An empty viewBox disables rendering. - if (element()->hasTagName(SVGNames::svgTag)) { - if (toSVGSVGElement(element())->hasEmptyViewBox()) - return; - } + if (isSVGSVGElement(*element()) && toSVGSVGElement(*element()).hasEmptyViewBox()) + return; RenderSVGContainer::paint(paintInfo, paintOffset); } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGViewportContainer.h b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGViewportContainer.h index b1b79ed5e31..679bd051dc7 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGViewportContainer.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/RenderSVGViewportContainer.h @@ -35,25 +35,25 @@ public: FloatRect viewport() const { return m_viewport; } bool isLayoutSizeChanged() const { return m_isLayoutSizeChanged; } - virtual bool didTransformToRootUpdate() { return m_didTransformToRootUpdate; } + virtual bool didTransformToRootUpdate() OVERRIDE { return m_didTransformToRootUpdate; } - virtual void determineIfLayoutSizeChanged(); - virtual void setNeedsTransformUpdate() { m_needsTransformUpdate = true; } + virtual void determineIfLayoutSizeChanged() OVERRIDE; + virtual void setNeedsTransformUpdate() OVERRIDE { m_needsTransformUpdate = true; } virtual void paint(PaintInfo&, const LayoutPoint&) OVERRIDE; private: - virtual bool isSVGViewportContainer() const { return true; } - virtual const char* renderName() const { return "RenderSVGViewportContainer"; } + virtual bool isSVGViewportContainer() const OVERRIDE { return true; } + virtual const char* renderName() const OVERRIDE { return "RenderSVGViewportContainer"; } AffineTransform viewportTransform() const; - virtual const AffineTransform& localToParentTransform() const { return m_localToParentTransform; } + virtual const AffineTransform& localToParentTransform() const OVERRIDE { return m_localToParentTransform; } - virtual void calcViewport(); - virtual bool calculateLocalTransform(); + virtual void calcViewport() OVERRIDE; + virtual bool calculateLocalTransform() OVERRIDE; - virtual void applyViewportClip(PaintInfo&); - virtual bool pointIsInsideViewportClip(const FloatPoint& pointInParent); + virtual void applyViewportClip(PaintInfo&) OVERRIDE; + virtual bool pointIsInsideViewportClip(const FloatPoint& pointInParent) OVERRIDE; FloatRect m_viewport; mutable AffineTransform m_localToParentTransform; diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGInlineFlowBox.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGInlineFlowBox.cpp index c4f5cdb1203..d4a861c3db2 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGInlineFlowBox.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGInlineFlowBox.cpp @@ -23,8 +23,6 @@ #include "config.h" #include "core/rendering/svg/SVGInlineFlowBox.h" -#include "core/dom/DocumentMarkerController.h" -#include "core/dom/RenderedDocumentMarker.h" #include "core/rendering/svg/RenderSVGInlineText.h" #include "core/rendering/svg/SVGInlineTextBox.h" #include "core/rendering/svg/SVGRenderingContext.h" @@ -47,22 +45,15 @@ void SVGInlineFlowBox::paintSelectionBackground(PaintInfo& paintInfo) } } -void SVGInlineFlowBox::paint(PaintInfo& paintInfo, const LayoutPoint&, LayoutUnit, LayoutUnit) +void SVGInlineFlowBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit, LayoutUnit) { ASSERT(paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection); ASSERT(!paintInfo.context->paintingDisabled()); - RenderObject* boxRenderer = renderer(); - ASSERT(boxRenderer); - - SVGRenderingContext renderingContext(boxRenderer, paintInfo, SVGRenderingContext::SaveGraphicsContext); + SVGRenderingContext renderingContext(&renderer(), paintInfo, SVGRenderingContext::SaveGraphicsContext); if (renderingContext.isRenderingPrepared()) { - for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) { - if (child->isSVGInlineTextBox()) - computeTextMatchMarkerRectForRenderer(toRenderSVGInlineText(toSVGInlineTextBox(child)->textRenderer())); - - child->paint(paintInfo, LayoutPoint(), 0, 0); - } + for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) + child->paint(paintInfo, paintOffset, 0, 0); } } @@ -77,66 +68,4 @@ FloatRect SVGInlineFlowBox::calculateBoundaries() const return childRect; } -void SVGInlineFlowBox::computeTextMatchMarkerRectForRenderer(RenderSVGInlineText* textRenderer) -{ - ASSERT(textRenderer); - - Node* node = textRenderer->node(); - if (!node || !node->inDocument()) - return; - - RenderStyle* style = textRenderer->style(); - ASSERT(style); - - AffineTransform fragmentTransform; - Document& document = textRenderer->document(); - Vector<DocumentMarker*> markers = document.markers()->markersFor(textRenderer->node()); - - Vector<DocumentMarker*>::iterator markerEnd = markers.end(); - for (Vector<DocumentMarker*>::iterator markerIt = markers.begin(); markerIt != markerEnd; ++markerIt) { - DocumentMarker* marker = *markerIt; - - // SVG is only interessted in the TextMatch marker, for now. - if (marker->type() != DocumentMarker::TextMatch) - continue; - - FloatRect markerRect; - for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) { - if (!box->isSVGInlineTextBox()) - continue; - - SVGInlineTextBox* textBox = toSVGInlineTextBox(box); - - int markerStartPosition = max<int>(marker->startOffset() - textBox->start(), 0); - int markerEndPosition = min<int>(marker->endOffset() - textBox->start(), textBox->len()); - - if (markerStartPosition >= markerEndPosition) - continue; - - int fragmentStartPosition = 0; - int fragmentEndPosition = 0; - - const Vector<SVGTextFragment>& fragments = textBox->textFragments(); - unsigned textFragmentsSize = fragments.size(); - for (unsigned i = 0; i < textFragmentsSize; ++i) { - const SVGTextFragment& fragment = fragments.at(i); - - fragmentStartPosition = markerStartPosition; - fragmentEndPosition = markerEndPosition; - if (!textBox->mapStartEndPositionsIntoFragmentCoordinates(fragment, fragmentStartPosition, fragmentEndPosition)) - continue; - - FloatRect fragmentRect = textBox->selectionRectForTextFragment(fragment, fragmentStartPosition, fragmentEndPosition, style); - fragment.buildFragmentTransform(fragmentTransform); - if (!fragmentTransform.isIdentity()) - fragmentRect = fragmentTransform.mapRect(fragmentRect); - - markerRect.unite(fragmentRect); - } - } - - toRenderedDocumentMarker(marker)->setRenderedRect(textRenderer->localToAbsoluteQuad(markerRect).enclosingBoundingBox()); - } -} - } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGInlineFlowBox.h b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGInlineFlowBox.h index e76a9ccdafc..0d66044e42b 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGInlineFlowBox.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGInlineFlowBox.h @@ -25,26 +25,22 @@ namespace WebCore { -class RenderSVGInlineText; - class SVGInlineFlowBox FINAL : public InlineFlowBox { public: - SVGInlineFlowBox(RenderObject* obj) + SVGInlineFlowBox(RenderObject& obj) : InlineFlowBox(obj) , m_logicalHeight(0) { } - virtual bool isSVGInlineFlowBox() const { return true; } - virtual float virtualLogicalHeight() const { return m_logicalHeight; } + virtual bool isSVGInlineFlowBox() const OVERRIDE { return true; } + virtual float virtualLogicalHeight() const OVERRIDE { return m_logicalHeight; } void setLogicalHeight(float h) { m_logicalHeight = h; } void paintSelectionBackground(PaintInfo&); - virtual void paint(PaintInfo&, const LayoutPoint&, LayoutUnit lineTop, LayoutUnit lineBottom); - - virtual FloatRect calculateBoundaries() const; + virtual void paint(PaintInfo&, const LayoutPoint&, LayoutUnit lineTop, LayoutUnit lineBottom) OVERRIDE; - static void computeTextMatchMarkerRectForRenderer(RenderSVGInlineText*); + virtual FloatRect calculateBoundaries() const OVERRIDE; private: float m_logicalHeight; diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGInlineTextBox.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGInlineTextBox.cpp index 6c593827328..a5dc2fc742c 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGInlineTextBox.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGInlineTextBox.cpp @@ -22,11 +22,17 @@ #include "config.h" #include "core/rendering/svg/SVGInlineTextBox.h" -#include "core/frame/Frame.h" +#include "core/dom/DocumentMarkerController.h" +#include "core/dom/RenderedDocumentMarker.h" +#include "core/editing/Editor.h" #include "core/frame/FrameView.h" +#include "core/frame/LocalFrame.h" #include "core/rendering/HitTestResult.h" #include "core/rendering/InlineFlowBox.h" +#include "core/rendering/PaintInfo.h" #include "core/rendering/PointerEventsHitRules.h" +#include "core/rendering/RenderInline.h" +#include "core/rendering/RenderTheme.h" #include "core/rendering/style/ShadowList.h" #include "core/rendering/svg/RenderSVGInlineText.h" #include "core/rendering/svg/RenderSVGResource.h" @@ -35,7 +41,7 @@ #include "core/rendering/svg/SVGTextRunRenderingContext.h" #include "platform/FloatConversion.h" #include "platform/fonts/FontCache.h" -#include "platform/graphics/DrawLooper.h" +#include "platform/graphics/DrawLooperBuilder.h" #include "platform/graphics/GraphicsContextStateSaver.h" using namespace std; @@ -44,17 +50,16 @@ namespace WebCore { struct ExpectedSVGInlineTextBoxSize : public InlineTextBox { float float1; - uint32_t bitfields : 5; + uint32_t bitfields : 1; void* pointer; Vector<SVGTextFragment> vector; }; COMPILE_ASSERT(sizeof(SVGInlineTextBox) == sizeof(ExpectedSVGInlineTextBoxSize), SVGInlineTextBox_is_not_of_expected_size); -SVGInlineTextBox::SVGInlineTextBox(RenderObject* object) +SVGInlineTextBox::SVGInlineTextBox(RenderObject& object) : InlineTextBox(object) , m_logicalHeight(0) - , m_paintingResourceMode(ApplyToDefaultMode) , m_startsNewTextChunk(false) , m_paintingResource(0) { @@ -84,13 +89,12 @@ int SVGInlineTextBox::offsetForPosition(float, bool) const int SVGInlineTextBox::offsetForPositionInFragment(const SVGTextFragment& fragment, float position, bool includePartialGlyphs) const { - RenderSVGInlineText* textRenderer = toRenderSVGInlineText(this->textRenderer()); - ASSERT(textRenderer); + RenderSVGInlineText& textRenderer = toRenderSVGInlineText(this->textRenderer()); - float scalingFactor = textRenderer->scalingFactor(); + float scalingFactor = textRenderer.scalingFactor(); ASSERT(scalingFactor); - RenderStyle* style = textRenderer->style(); + RenderStyle* style = textRenderer.style(); ASSERT(style); TextRun textRun = constructTextRun(style, fragment); @@ -102,7 +106,7 @@ int SVGInlineTextBox::offsetForPositionInFragment(const SVGTextFragment& fragmen if (!fragmentTransform.isIdentity()) textRun.setHorizontalGlyphStretch(narrowPrecisionToFloat(fragmentTransform.xScale())); - return fragment.characterOffset - start() + textRenderer->scaledFont().offsetForPosition(textRun, position * scalingFactor, includePartialGlyphs); + return fragment.characterOffset - start() + textRenderer.scaledFont().offsetForPosition(textRun, position * scalingFactor, includePartialGlyphs); } float SVGInlineTextBox::positionForOffset(int) const @@ -119,13 +123,12 @@ FloatRect SVGInlineTextBox::selectionRectForTextFragment(const SVGTextFragment& FontCachePurgePreventer fontCachePurgePreventer; - RenderSVGInlineText* textRenderer = toRenderSVGInlineText(this->textRenderer()); - ASSERT(textRenderer); + RenderSVGInlineText& textRenderer = toRenderSVGInlineText(this->textRenderer()); - float scalingFactor = textRenderer->scalingFactor(); + float scalingFactor = textRenderer.scalingFactor(); ASSERT(scalingFactor); - const Font& scaledFont = textRenderer->scaledFont(); + const Font& scaledFont = textRenderer.scaledFont(); const FontMetrics& scaledFontMetrics = scaledFont.fontMetrics(); FloatPoint textOrigin(fragment.x, fragment.y); if (scalingFactor != 1) @@ -149,10 +152,7 @@ LayoutRect SVGInlineTextBox::localSelectionRect(int startPosition, int endPositi if (startPosition >= endPosition) return LayoutRect(); - RenderText* text = textRenderer(); - ASSERT(text); - - RenderStyle* style = text->style(); + RenderStyle* style = textRenderer().style(); ASSERT(style); AffineTransform fragmentTransform; @@ -171,8 +171,7 @@ LayoutRect SVGInlineTextBox::localSelectionRect(int startPosition, int endPositi FloatRect fragmentRect = selectionRectForTextFragment(fragment, fragmentStartPosition, fragmentEndPosition, style); fragment.buildFragmentTransform(fragmentTransform); - if (!fragmentTransform.isIdentity()) - fragmentRect = fragmentTransform.mapRect(fragmentRect); + fragmentRect = fragmentTransform.mapRect(fragmentRect); selectionRect.unite(fragmentRect); } @@ -180,25 +179,24 @@ LayoutRect SVGInlineTextBox::localSelectionRect(int startPosition, int endPositi return enclosingIntRect(selectionRect); } -static inline bool textShouldBePainted(RenderSVGInlineText* textRenderer) +static inline bool textShouldBePainted(RenderSVGInlineText& textRenderer) { // Font::pixelSize(), returns FontDescription::computedPixelSize(), which returns "int(x + 0.5)". // If the absolute font size on screen is below x=0.5, don't render anything. - return textRenderer->scaledFont().pixelSize(); + return textRenderer.scaledFont().fontDescription().computedPixelSize(); } void SVGInlineTextBox::paintSelectionBackground(PaintInfo& paintInfo) { - ASSERT(paintInfo.shouldPaintWithinRoot(renderer())); + ASSERT(paintInfo.shouldPaintWithinRoot(&renderer())); ASSERT(paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection); ASSERT(truncation() == cNoTruncation); - if (renderer()->style()->visibility() != VISIBLE) + if (renderer().style()->visibility() != VISIBLE) return; - RenderObject* parentRenderer = parent()->renderer(); - ASSERT(parentRenderer); - ASSERT(!parentRenderer->document().printing()); + RenderObject& parentRenderer = parent()->renderer(); + ASSERT(!parentRenderer.document().printing()); // Determine whether or not we're selected. bool paintSelectedTextOnly = paintInfo.phase == PaintPhaseSelection; @@ -206,25 +204,17 @@ void SVGInlineTextBox::paintSelectionBackground(PaintInfo& paintInfo) if (!hasSelection || paintSelectedTextOnly) return; - Color backgroundColor = renderer()->selectionBackgroundColor(); - if (!backgroundColor.isValid() || !backgroundColor.alpha()) + Color backgroundColor = renderer().selectionBackgroundColor(); + if (!backgroundColor.alpha()) return; - RenderSVGInlineText* textRenderer = toRenderSVGInlineText(this->textRenderer()); - ASSERT(textRenderer); + RenderSVGInlineText& textRenderer = toRenderSVGInlineText(this->textRenderer()); if (!textShouldBePainted(textRenderer)) return; - RenderStyle* style = parentRenderer->style(); + RenderStyle* style = parentRenderer.style(); ASSERT(style); - RenderStyle* selectionStyle = style; - if (hasSelection) { - selectionStyle = parentRenderer->getCachedPseudoStyle(SELECTION); - if (!selectionStyle) - selectionStyle = style; - } - int startPosition, endPosition; selectionStartEnd(startPosition, endPosition); @@ -248,41 +238,39 @@ void SVGInlineTextBox::paintSelectionBackground(PaintInfo& paintInfo) paintInfo.context->setFillColor(backgroundColor); paintInfo.context->fillRect(selectionRectForTextFragment(fragment, fragmentStartPosition, fragmentEndPosition, style), backgroundColor); - - m_paintingResourceMode = ApplyToDefaultMode; } ASSERT(!m_paintingResource); } -void SVGInlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint&, LayoutUnit, LayoutUnit) +void SVGInlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit, LayoutUnit) { - ASSERT(paintInfo.shouldPaintWithinRoot(renderer())); + ASSERT(paintInfo.shouldPaintWithinRoot(&renderer())); ASSERT(paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection); ASSERT(truncation() == cNoTruncation); - if (renderer()->style()->visibility() != VISIBLE) + if (renderer().style()->visibility() != VISIBLE) return; // Note: We're explicitely not supporting composition & custom underlines and custom highlighters - unlike InlineTextBox. // If we ever need that for SVG, it's very easy to refactor and reuse the code. - RenderObject* parentRenderer = parent()->renderer(); - ASSERT(parentRenderer); + RenderObject& parentRenderer = parent()->renderer(); bool paintSelectedTextOnly = paintInfo.phase == PaintPhaseSelection; - bool hasSelection = !parentRenderer->document().printing() && selectionState() != RenderObject::SelectionNone; + bool hasSelection = !parentRenderer.document().printing() && selectionState() != RenderObject::SelectionNone; if (!hasSelection && paintSelectedTextOnly) return; - RenderSVGInlineText* textRenderer = toRenderSVGInlineText(this->textRenderer()); - ASSERT(textRenderer); + RenderSVGInlineText& textRenderer = toRenderSVGInlineText(this->textRenderer()); if (!textShouldBePainted(textRenderer)) return; - RenderStyle* style = parentRenderer->style(); + RenderStyle* style = parentRenderer.style(); ASSERT(style); + paintDocumentMarkers(paintInfo.context, paintOffset, style, textRenderer.scaledFont(), true); + const SVGRenderStyle* svgStyle = style->svgStyle(); ASSERT(svgStyle); @@ -291,7 +279,7 @@ void SVGInlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint&, LayoutUni RenderStyle* selectionStyle = style; if (hasSelection) { - selectionStyle = parentRenderer->getCachedPseudoStyle(SELECTION); + selectionStyle = parentRenderer.getCachedPseudoStyle(SELECTION); if (selectionStyle) { const SVGRenderStyle* svgSelectionStyle = selectionStyle->svgStyle(); ASSERT(svgSelectionStyle); @@ -300,11 +288,12 @@ void SVGInlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint&, LayoutUni hasFill = svgSelectionStyle->hasFill(); if (!hasVisibleStroke) hasVisibleStroke = svgSelectionStyle->hasVisibleStroke(); - } else + } else { selectionStyle = style; + } } - if (textRenderer->frame() && textRenderer->frame()->view() && textRenderer->frame()->view()->paintBehavior() & PaintBehaviorRenderingSVGMask) { + if (textRenderer.frame() && textRenderer.frame()->view() && textRenderer.frame()->view()->paintBehavior() & PaintBehaviorRenderingSVGMask) { hasFill = true; hasVisibleStroke = false; } @@ -315,10 +304,12 @@ void SVGInlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint&, LayoutUni SVGTextFragment& fragment = m_textFragments.at(i); ASSERT(!m_paintingResource); - GraphicsContextStateSaver stateSaver(*paintInfo.context); + GraphicsContextStateSaver stateSaver(*paintInfo.context, false); fragment.buildFragmentTransform(fragmentTransform); - if (!fragmentTransform.isIdentity()) + if (!fragmentTransform.isIdentity()) { + stateSaver.save(); 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. unsigned decorations = style->textDecorationsInEffect(); @@ -332,15 +323,15 @@ void SVGInlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint&, LayoutUni case PT_FILL: // Fill text if (hasFill) { - m_paintingResourceMode = ApplyToFillMode | ApplyToTextMode; - paintText(paintInfo.context, style, selectionStyle, fragment, hasSelection, paintSelectedTextOnly); + paintText(paintInfo.context, style, selectionStyle, fragment, + ApplyToFillMode | ApplyToTextMode, hasSelection, paintSelectedTextOnly); } break; case PT_STROKE: // Stroke text if (hasVisibleStroke) { - m_paintingResourceMode = ApplyToStrokeMode | ApplyToTextMode; - paintText(paintInfo.context, style, selectionStyle, fragment, hasSelection, paintSelectedTextOnly); + paintText(paintInfo.context, style, selectionStyle, fragment, + ApplyToStrokeMode | ApplyToTextMode, hasSelection, paintSelectedTextOnly); } break; case PT_MARKERS: @@ -355,25 +346,29 @@ void SVGInlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint&, LayoutUni // Spec: Line-through should be drawn after the text is filled and stroked; thus, the line-through is rendered on top of the text. if (decorations & TextDecorationLineThrough) paintDecoration(paintInfo.context, TextDecorationLineThrough, fragment); - - m_paintingResourceMode = ApplyToDefaultMode; } + // finally, paint the outline if any + if (style->hasOutline() && parentRenderer.isRenderInline()) + toRenderInline(parentRenderer).paintOutline(paintInfo, paintOffset); + ASSERT(!m_paintingResource); } -bool SVGInlineTextBox::acquirePaintingResource(GraphicsContext*& context, float scalingFactor, RenderObject* renderer, RenderStyle* style) +bool SVGInlineTextBox::acquirePaintingResource(GraphicsContext*& context, float scalingFactor, + RenderObject* renderer, RenderStyle* style, RenderSVGResourceModeFlags resourceMode) { + // Callers must save the context state before calling when scalingFactor is not 1. ASSERT(scalingFactor); ASSERT(renderer); ASSERT(style); - ASSERT(m_paintingResourceMode != ApplyToDefaultMode); + ASSERT(resourceMode != ApplyToDefaultMode); - Color fallbackColor; - if (m_paintingResourceMode & ApplyToFillMode) - m_paintingResource = RenderSVGResource::fillPaintingResource(renderer, style, fallbackColor); - else if (m_paintingResourceMode & ApplyToStrokeMode) - m_paintingResource = RenderSVGResource::strokePaintingResource(renderer, style, fallbackColor); + bool hasFallback = false; + if (resourceMode & ApplyToFillMode) + m_paintingResource = RenderSVGResource::fillPaintingResource(renderer, style, hasFallback); + else if (resourceMode & ApplyToStrokeMode) + m_paintingResource = RenderSVGResource::strokePaintingResource(renderer, style, hasFallback); else { // We're either called for stroking or filling. ASSERT_NOT_REACHED(); @@ -382,36 +377,32 @@ bool SVGInlineTextBox::acquirePaintingResource(GraphicsContext*& context, float if (!m_paintingResource) return false; - if (!m_paintingResource->applyResource(renderer, style, context, m_paintingResourceMode)) { - if (fallbackColor.isValid()) { - RenderSVGResourceSolidColor* fallbackResource = RenderSVGResource::sharedSolidPaintingResource(); - fallbackResource->setColor(fallbackColor); - - m_paintingResource = fallbackResource; - m_paintingResource->applyResource(renderer, style, context, m_paintingResourceMode); + if (!m_paintingResource->applyResource(renderer, style, context, resourceMode)) { + if (hasFallback) { + m_paintingResource = RenderSVGResource::sharedSolidPaintingResource(); + m_paintingResource->applyResource(renderer, style, context, resourceMode); } } - if (scalingFactor != 1 && m_paintingResourceMode & ApplyToStrokeMode) + if (scalingFactor != 1 && resourceMode & ApplyToStrokeMode) context->setStrokeThickness(context->strokeThickness() * scalingFactor); return true; } -void SVGInlineTextBox::releasePaintingResource(GraphicsContext*& context, const Path* path) +void SVGInlineTextBox::releasePaintingResource(GraphicsContext*& context, const Path* path, + RenderSVGResourceModeFlags resourceMode) { ASSERT(m_paintingResource); - RenderObject* parentRenderer = parent()->renderer(); - ASSERT(parentRenderer); - - m_paintingResource->postApplyResource(parentRenderer, context, m_paintingResourceMode, path, /*RenderSVGShape*/ 0); + m_paintingResource->postApplyResource(&parent()->renderer(), context, resourceMode, path, 0); m_paintingResource = 0; } -bool SVGInlineTextBox::prepareGraphicsContextForTextPainting(GraphicsContext*& context, float scalingFactor, TextRun& textRun, RenderStyle* style) +bool SVGInlineTextBox::prepareGraphicsContextForTextPainting(GraphicsContext*& context, + float scalingFactor, TextRun& textRun, RenderStyle* style, RenderSVGResourceModeFlags resourceMode) { - bool acquiredResource = acquirePaintingResource(context, scalingFactor, parent()->renderer(), style); + bool acquiredResource = acquirePaintingResource(context, scalingFactor, &parent()->renderer(), style, resourceMode); if (!acquiredResource) return false; @@ -425,9 +416,10 @@ bool SVGInlineTextBox::prepareGraphicsContextForTextPainting(GraphicsContext*& c return true; } -void SVGInlineTextBox::restoreGraphicsContextAfterTextPainting(GraphicsContext*& context, TextRun& textRun) +void SVGInlineTextBox::restoreGraphicsContextAfterTextPainting(GraphicsContext*& context, + TextRun& textRun, RenderSVGResourceModeFlags resourceMode) { - releasePaintingResource(context, /* path */0); + releasePaintingResource(context, 0, resourceMode); #if ENABLE(SVG_FONTS) TextRun::RenderingContext* renderingContext = textRun.renderingContext(); @@ -439,10 +431,8 @@ void SVGInlineTextBox::restoreGraphicsContextAfterTextPainting(GraphicsContext*& TextRun SVGInlineTextBox::constructTextRun(RenderStyle* style, const SVGTextFragment& fragment) const { ASSERT(style); - ASSERT(textRenderer()); - RenderText* text = textRenderer(); - ASSERT(text); + RenderText* text = &textRenderer(); // FIXME(crbug.com/264211): This should not be necessary but can occur if we // layout during layout. Remove this when 264211 is fixed. @@ -523,7 +513,7 @@ static inline float thicknessForDecoration(TextDecoration, const Font& font) { // FIXME: For SVG Fonts we need to use the attributes defined in the <font-face> if specified. // Compatible with Batik/Opera - return font.size() / 20.0f; + return font.fontDescription().computedSize() / 20.0f; } static inline RenderObject* findRenderObjectDefininingTextDecoration(InlineFlowBox* parentBox) @@ -531,7 +521,7 @@ static inline RenderObject* findRenderObjectDefininingTextDecoration(InlineFlowB // Lookup first render object in parent hierarchy which has text-decoration set. RenderObject* renderer = 0; while (parentBox) { - renderer = parentBox->renderer(); + renderer = &parentBox->renderer(); if (renderer->style() && renderer->style()->textDecoration() != TextDecorationNone) break; @@ -545,7 +535,7 @@ static inline RenderObject* findRenderObjectDefininingTextDecoration(InlineFlowB void SVGInlineTextBox::paintDecoration(GraphicsContext* context, TextDecoration decoration, const SVGTextFragment& fragment) { - if (textRenderer()->style()->textDecorationsInEffect() == TextDecorationNone) + if (textRenderer().style()->textDecorationsInEffect() == TextDecorationNone) return; // Find out which render style defined the text-decoration, as its fill/stroke properties have to be used for drawing instead of ours. @@ -559,24 +549,29 @@ void SVGInlineTextBox::paintDecoration(GraphicsContext* context, TextDecoration const SVGRenderStyle* svgDecorationStyle = decorationStyle->svgStyle(); ASSERT(svgDecorationStyle); - bool hasDecorationFill = svgDecorationStyle->hasFill(); - bool hasVisibleDecorationStroke = svgDecorationStyle->hasVisibleStroke(); - - if (hasDecorationFill) { - m_paintingResourceMode = ApplyToFillMode; - paintDecorationWithStyle(context, decoration, fragment, decorationRenderer); - } - - if (hasVisibleDecorationStroke) { - m_paintingResourceMode = ApplyToStrokeMode; - paintDecorationWithStyle(context, decoration, fragment, decorationRenderer); + for (int i = 0; i < 3; i++) { + switch (svgDecorationStyle->paintOrderType(i)) { + case PT_FILL: + if (svgDecorationStyle->hasFill()) + paintDecorationWithStyle(context, decoration, fragment, decorationRenderer, ApplyToFillMode); + break; + case PT_STROKE: + if (svgDecorationStyle->hasVisibleStroke()) + paintDecorationWithStyle(context, decoration, fragment, decorationRenderer, ApplyToStrokeMode); + break; + case PT_MARKERS: + break; + default: + ASSERT_NOT_REACHED(); + } } } -void SVGInlineTextBox::paintDecorationWithStyle(GraphicsContext* context, TextDecoration decoration, const SVGTextFragment& fragment, RenderObject* decorationRenderer) +void SVGInlineTextBox::paintDecorationWithStyle(GraphicsContext* context, TextDecoration decoration, + const SVGTextFragment& fragment, RenderObject* decorationRenderer, RenderSVGResourceModeFlags resourceMode) { ASSERT(!m_paintingResource); - ASSERT(m_paintingResourceMode != ApplyToDefaultMode); + ASSERT(resourceMode != ApplyToDefaultMode); RenderStyle* decorationStyle = decorationRenderer->style(); ASSERT(decorationStyle); @@ -596,11 +591,12 @@ void SVGInlineTextBox::paintDecorationWithStyle(GraphicsContext* context, TextDe float width = fragment.width; const FontMetrics& scaledFontMetrics = scaledFont.fontMetrics(); - GraphicsContextStateSaver stateSaver(*context); + GraphicsContextStateSaver stateSaver(*context, false); if (scalingFactor != 1) { + stateSaver.save(); width *= scalingFactor; decorationOrigin.scale(scalingFactor, scalingFactor); - context->scale(FloatSize(1 / scalingFactor, 1 / scalingFactor)); + context->scale(1 / scalingFactor, 1 / scalingFactor); } decorationOrigin.move(0, -scaledFontMetrics.floatAscent() + positionOffsetForDecoration(decoration, scaledFontMetrics, thickness)); @@ -608,19 +604,22 @@ void SVGInlineTextBox::paintDecorationWithStyle(GraphicsContext* context, TextDe Path path; path.addRect(FloatRect(decorationOrigin, FloatSize(width, thickness))); - if (acquirePaintingResource(context, scalingFactor, decorationRenderer, decorationStyle)) - releasePaintingResource(context, &path); + // acquirePaintingResource also modifies state if the scalingFactor is non-identity. + // Above we have saved the state for this case. + if (acquirePaintingResource(context, scalingFactor, decorationRenderer, decorationStyle, resourceMode)) + releasePaintingResource(context, &path, resourceMode); } -void SVGInlineTextBox::paintTextWithShadows(GraphicsContext* context, RenderStyle* style, TextRun& textRun, const SVGTextFragment& fragment, int startPosition, int endPosition) +void SVGInlineTextBox::paintTextWithShadows(GraphicsContext* context, RenderStyle* style, + TextRun& textRun, const SVGTextFragment& fragment, int startPosition, int endPosition, + RenderSVGResourceModeFlags resourceMode) { - RenderSVGInlineText* textRenderer = toRenderSVGInlineText(this->textRenderer()); - ASSERT(textRenderer); + RenderSVGInlineText& textRenderer = toRenderSVGInlineText(this->textRenderer()); - float scalingFactor = textRenderer->scalingFactor(); + float scalingFactor = textRenderer.scalingFactor(); ASSERT(scalingFactor); - const Font& scaledFont = textRenderer->scaledFont(); + const Font& scaledFont = textRenderer.scaledFont(); const ShadowList* shadowList = style->textShadow(); // Text shadows are disabled when printing. http://crbug.com/258321 @@ -633,28 +632,28 @@ void SVGInlineTextBox::paintTextWithShadows(GraphicsContext* context, RenderStyl textOrigin.scale(scalingFactor, scalingFactor); textSize.scale(scalingFactor); context->save(); - context->scale(FloatSize(1 / scalingFactor, 1 / scalingFactor)); + context->scale(1 / scalingFactor, 1 / scalingFactor); } if (hasShadow) { - DrawLooper drawLooper; + OwnPtr<DrawLooperBuilder> drawLooperBuilder = DrawLooperBuilder::create(); for (size_t i = shadowList->shadows().size(); i--; ) { const ShadowData& shadow = shadowList->shadows()[i]; FloatSize offset(shadow.x(), shadow.y()); - drawLooper.addShadow(offset, shadow.blur(), shadow.color(), - DrawLooper::ShadowRespectsTransforms, DrawLooper::ShadowRespectsAlpha); + drawLooperBuilder->addShadow(offset, shadow.blur(), shadow.color(), + DrawLooperBuilder::ShadowRespectsTransforms, DrawLooperBuilder::ShadowRespectsAlpha); } - drawLooper.addUnmodifiedContent(); - context->setDrawLooper(drawLooper); + drawLooperBuilder->addUnmodifiedContent(); + context->setDrawLooper(drawLooperBuilder.release()); } - if (prepareGraphicsContextForTextPainting(context, scalingFactor, textRun, style)) { + if (prepareGraphicsContextForTextPainting(context, scalingFactor, textRun, style, resourceMode)) { TextRunPaintInfo textRunPaintInfo(textRun); textRunPaintInfo.from = startPosition; textRunPaintInfo.to = endPosition; textRunPaintInfo.bounds = FloatRect(textOrigin, textSize); scaledFont.drawText(context, textRunPaintInfo, textOrigin); - restoreGraphicsContextAfterTextPainting(context, textRun); + restoreGraphicsContextAfterTextPainting(context, textRun, resourceMode); } if (scalingFactor != 1) @@ -663,7 +662,9 @@ void SVGInlineTextBox::paintTextWithShadows(GraphicsContext* context, RenderStyl context->clearShadow(); } -void SVGInlineTextBox::paintText(GraphicsContext* context, RenderStyle* style, RenderStyle* selectionStyle, const SVGTextFragment& fragment, bool hasSelection, bool paintSelectedTextOnly) +void SVGInlineTextBox::paintText(GraphicsContext* context, RenderStyle* style, + RenderStyle* selectionStyle, const SVGTextFragment& fragment, + RenderSVGResourceModeFlags resourceMode, bool hasSelection, bool paintSelectedTextOnly) { ASSERT(style); ASSERT(selectionStyle); @@ -678,40 +679,104 @@ void SVGInlineTextBox::paintText(GraphicsContext* context, RenderStyle* style, R // Fast path if there is no selection, just draw the whole chunk part using the regular style TextRun textRun = constructTextRun(style, fragment); if (!hasSelection || startPosition >= endPosition) { - paintTextWithShadows(context, style, textRun, fragment, 0, fragment.length); + paintTextWithShadows(context, style, textRun, fragment, 0, fragment.length, resourceMode); return; } // Eventually draw text using regular style until the start position of the selection if (startPosition > 0 && !paintSelectedTextOnly) - paintTextWithShadows(context, style, textRun, fragment, 0, startPosition); + paintTextWithShadows(context, style, textRun, fragment, 0, startPosition, resourceMode); // Draw text using selection style from the start to the end position of the selection - if (style != selectionStyle) - SVGResourcesCache::clientStyleChanged(parent()->renderer(), StyleDifferenceRepaint, selectionStyle); + if (style != selectionStyle) { + StyleDifference diff; + diff.setNeedsRepaintObject(); + SVGResourcesCache::clientStyleChanged(&parent()->renderer(), diff, selectionStyle); + } - TextRun selectionTextRun = constructTextRun(selectionStyle, fragment); - paintTextWithShadows(context, selectionStyle, textRun, fragment, startPosition, endPosition); + paintTextWithShadows(context, selectionStyle, textRun, fragment, startPosition, endPosition, resourceMode); - if (style != selectionStyle) - SVGResourcesCache::clientStyleChanged(parent()->renderer(), StyleDifferenceRepaint, style); + if (style != selectionStyle) { + StyleDifference diff; + diff.setNeedsRepaintObject(); + SVGResourcesCache::clientStyleChanged(&parent()->renderer(), diff, selectionStyle); + } // Eventually draw text using regular style from the end position of the selection to the end of the current chunk part if (endPosition < static_cast<int>(fragment.length) && !paintSelectedTextOnly) - paintTextWithShadows(context, style, textRun, fragment, endPosition, fragment.length); + paintTextWithShadows(context, style, textRun, fragment, endPosition, fragment.length, resourceMode); +} + +void SVGInlineTextBox::paintDocumentMarker(GraphicsContext*, const FloatPoint&, DocumentMarker*, RenderStyle*, const Font&, bool) +{ + // SVG does not have support for generic document markers (e.g., spellchecking, etc). +} + +void SVGInlineTextBox::paintTextMatchMarker(GraphicsContext* context, const FloatPoint&, DocumentMarker* marker, RenderStyle* style, const Font& font) +{ + // SVG is only interested in the TextMatch markers. + if (marker->type() != DocumentMarker::TextMatch) + return; + + RenderSVGInlineText& textRenderer = toRenderSVGInlineText(this->textRenderer()); + + FloatRect markerRect; + AffineTransform fragmentTransform; + for (InlineTextBox* box = textRenderer.firstTextBox(); box; box = box->nextTextBox()) { + if (!box->isSVGInlineTextBox()) + continue; + + SVGInlineTextBox* textBox = toSVGInlineTextBox(box); + + int markerStartPosition = max<int>(marker->startOffset() - textBox->start(), 0); + int markerEndPosition = min<int>(marker->endOffset() - textBox->start(), textBox->len()); + + if (markerStartPosition >= markerEndPosition) + continue; + + const Vector<SVGTextFragment>& fragments = textBox->textFragments(); + unsigned textFragmentsSize = fragments.size(); + for (unsigned i = 0; i < textFragmentsSize; ++i) { + const SVGTextFragment& fragment = fragments.at(i); + + int fragmentStartPosition = markerStartPosition; + int fragmentEndPosition = markerEndPosition; + if (!textBox->mapStartEndPositionsIntoFragmentCoordinates(fragment, fragmentStartPosition, fragmentEndPosition)) + continue; + + FloatRect fragmentRect = textBox->selectionRectForTextFragment(fragment, fragmentStartPosition, fragmentEndPosition, style); + fragment.buildFragmentTransform(fragmentTransform); + + // Draw the marker highlight. + if (renderer().frame()->editor().markedTextMatchesAreHighlighted()) { + Color color = marker->activeMatch() ? + RenderTheme::theme().platformActiveTextSearchHighlightColor() : + RenderTheme::theme().platformInactiveTextSearchHighlightColor(); + GraphicsContextStateSaver stateSaver(*context); + if (!fragmentTransform.isIdentity()) + context->concatCTM(fragmentTransform); + context->setFillColor(color); + context->fillRect(fragmentRect, color); + } + + fragmentRect = fragmentTransform.mapRect(fragmentRect); + markerRect.unite(fragmentRect); + } + } + + toRenderedDocumentMarker(marker)->setRenderedRect(textRenderer.localToAbsoluteQuad(markerRect).enclosingBoundingBox()); } FloatRect SVGInlineTextBox::calculateBoundaries() const { FloatRect textRect; - RenderSVGInlineText* textRenderer = toRenderSVGInlineText(this->textRenderer()); - ASSERT(textRenderer); + RenderSVGInlineText& textRenderer = toRenderSVGInlineText(this->textRenderer()); - float scalingFactor = textRenderer->scalingFactor(); + float scalingFactor = textRenderer.scalingFactor(); ASSERT(scalingFactor); - float baseline = textRenderer->scaledFont().fontMetrics().floatAscent() / scalingFactor; + float baseline = textRenderer.scaledFont().fontMetrics().floatAscent() / scalingFactor; AffineTransform fragmentTransform; unsigned textFragmentsSize = m_textFragments.size(); @@ -719,8 +784,7 @@ FloatRect SVGInlineTextBox::calculateBoundaries() const const SVGTextFragment& fragment = m_textFragments.at(i); FloatRect fragmentRect(fragment.x, fragment.y - baseline, fragment.width, fragment.height); fragment.buildFragmentTransform(fragmentTransform); - if (!fragmentTransform.isIdentity()) - fragmentRect = fragmentTransform.mapRect(fragmentRect); + fragmentRect = fragmentTransform.mapRect(fragmentRect); textRect.unite(fragmentRect); } @@ -733,18 +797,18 @@ bool SVGInlineTextBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& // FIXME: integrate with InlineTextBox::nodeAtPoint better. ASSERT(!isLineBreak()); - PointerEventsHitRules hitRules(PointerEventsHitRules::SVG_TEXT_HITTESTING, request, renderer()->style()->pointerEvents()); - bool isVisible = renderer()->style()->visibility() == VISIBLE; + PointerEventsHitRules hitRules(PointerEventsHitRules::SVG_TEXT_HITTESTING, request, renderer().style()->pointerEvents()); + bool isVisible = renderer().style()->visibility() == VISIBLE; if (isVisible || !hitRules.requireVisible) { if (hitRules.canHitBoundingBox - || (hitRules.canHitStroke && (renderer()->style()->svgStyle()->hasStroke() || !hitRules.requireStroke)) - || (hitRules.canHitFill && (renderer()->style()->svgStyle()->hasFill() || !hitRules.requireFill))) { + || (hitRules.canHitStroke && (renderer().style()->svgStyle()->hasStroke() || !hitRules.requireStroke)) + || (hitRules.canHitFill && (renderer().style()->svgStyle()->hasFill() || !hitRules.requireFill))) { FloatPoint boxOrigin(x(), y()); boxOrigin.moveBy(accumulatedOffset); FloatRect rect(boxOrigin, size()); if (locationInContainer.intersects(rect)) { - renderer()->updateHitTestResult(result, locationInContainer.point() - toLayoutSize(accumulatedOffset)); - if (!result.addNodeToRectBasedTestResult(renderer()->node(), request, locationInContainer, rect)) + renderer().updateHitTestResult(result, locationInContainer.point() - toLayoutSize(accumulatedOffset)); + if (!result.addNodeToRectBasedTestResult(renderer().node(), request, locationInContainer, rect)) return true; } } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGInlineTextBox.h b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGInlineTextBox.h index ccec860b863..2a5cb1bcd0e 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGInlineTextBox.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGInlineTextBox.h @@ -23,38 +23,38 @@ #define SVGInlineTextBox_h #include "core/rendering/InlineTextBox.h" +#include "core/rendering/svg/RenderSVGResource.h" #include "core/rendering/svg/SVGTextLayoutEngine.h" namespace WebCore { class RenderSVGResource; -class SVGRootInlineBox; class SVGInlineTextBox FINAL : public InlineTextBox { public: - SVGInlineTextBox(RenderObject*); + SVGInlineTextBox(RenderObject&); - virtual bool isSVGInlineTextBox() const { return true; } + virtual bool isSVGInlineTextBox() const OVERRIDE { return true; } - virtual float virtualLogicalHeight() const { return m_logicalHeight; } + virtual float virtualLogicalHeight() const OVERRIDE { return m_logicalHeight; } void setLogicalHeight(float height) { m_logicalHeight = height; } - virtual int offsetForPosition(float x, bool includePartialGlyphs = true) const; - virtual float positionForOffset(int offset) const; + virtual int offsetForPosition(float x, bool includePartialGlyphs = true) const OVERRIDE; + virtual float positionForOffset(int offset) const OVERRIDE; void paintSelectionBackground(PaintInfo&); - virtual void paint(PaintInfo&, const LayoutPoint&, LayoutUnit lineTop, LayoutUnit lineBottom); - virtual LayoutRect localSelectionRect(int startPosition, int endPosition); + virtual void paint(PaintInfo&, const LayoutPoint&, LayoutUnit lineTop, LayoutUnit lineBottom) OVERRIDE; + virtual LayoutRect localSelectionRect(int startPosition, int endPosition) OVERRIDE; bool mapStartEndPositionsIntoFragmentCoordinates(const SVGTextFragment&, int& startPosition, int& endPosition) const; - virtual FloatRect calculateBoundaries() const; + virtual FloatRect calculateBoundaries() const OVERRIDE; void clearTextFragments() { m_textFragments.clear(); } Vector<SVGTextFragment>& textFragments() { return m_textFragments; } const Vector<SVGTextFragment>& textFragments() const { return m_textFragments; } - virtual void dirtyLineBoxes() OVERRIDE FINAL; + virtual void dirtyLineBoxes() OVERRIDE; bool startsNewTextChunk() const { return m_startsNewTextChunk; } void setStartsNewTextChunk(bool newTextChunk) { m_startsNewTextChunk = newTextChunk; } @@ -65,23 +65,30 @@ public: private: TextRun constructTextRun(RenderStyle*, const SVGTextFragment&) const; - bool acquirePaintingResource(GraphicsContext*&, float scalingFactor, RenderObject*, RenderStyle*); - void releasePaintingResource(GraphicsContext*&, const Path*); + bool acquirePaintingResource(GraphicsContext*&, float scalingFactor, RenderObject*, + RenderStyle*, RenderSVGResourceModeFlags); + void releasePaintingResource(GraphicsContext*&, const Path*, RenderSVGResourceModeFlags); - bool prepareGraphicsContextForTextPainting(GraphicsContext*&, float scalingFactor, TextRun&, RenderStyle*); - void restoreGraphicsContextAfterTextPainting(GraphicsContext*&, TextRun&); + bool prepareGraphicsContextForTextPainting(GraphicsContext*&, float scalingFactor, TextRun&, + RenderStyle*, RenderSVGResourceModeFlags); + void restoreGraphicsContextAfterTextPainting(GraphicsContext*&, TextRun&, RenderSVGResourceModeFlags); void paintDecoration(GraphicsContext*, TextDecoration, const SVGTextFragment&); - void paintDecorationWithStyle(GraphicsContext*, TextDecoration, const SVGTextFragment&, RenderObject* decorationRenderer); - void paintTextWithShadows(GraphicsContext*, RenderStyle*, TextRun&, const SVGTextFragment&, int startPosition, int endPosition); - void paintText(GraphicsContext*, RenderStyle*, RenderStyle* selectionStyle, const SVGTextFragment&, bool hasSelection, bool paintSelectedTextOnly); + void paintDecorationWithStyle(GraphicsContext*, TextDecoration, const SVGTextFragment&, + RenderObject* decorationRenderer, RenderSVGResourceModeFlags); + void paintTextWithShadows(GraphicsContext*, RenderStyle*, TextRun&, const SVGTextFragment&, + int startPosition, int endPosition, RenderSVGResourceModeFlags); + void paintText(GraphicsContext*, RenderStyle*, RenderStyle* selectionStyle, const SVGTextFragment&, + RenderSVGResourceModeFlags, bool hasSelection, bool paintSelectedTextOnly); + + virtual void paintDocumentMarker(GraphicsContext*, const FloatPoint&, DocumentMarker*, RenderStyle*, const Font&, bool) OVERRIDE FINAL; + virtual void paintTextMatchMarker(GraphicsContext*, const FloatPoint&, DocumentMarker*, RenderStyle*, const Font&) OVERRIDE FINAL; virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom) OVERRIDE; private: float m_logicalHeight; - unsigned m_paintingResourceMode : 4; - unsigned m_startsNewTextChunk : 1; + bool m_startsNewTextChunk : 1; RenderSVGResource* m_paintingResource; Vector<SVGTextFragment> m_textFragments; }; diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGMarkerData.h b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGMarkerData.h index aebd83b3e1a..1b31b98b87f 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGMarkerData.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGMarkerData.h @@ -26,8 +26,6 @@ namespace WebCore { -class RenderSVGResourceMarker; - enum SVGMarkerType { StartMarker, MidMarker, diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGPathData.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGPathData.cpp index f42f6410e57..5a18ba50295 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGPathData.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGPathData.cpp @@ -20,7 +20,7 @@ #include "config.h" #include "core/rendering/svg/SVGPathData.h" -#include "SVGNames.h" +#include "core/SVGNames.h" #include "core/svg/SVGCircleElement.h" #include "core/svg/SVGEllipseElement.h" #include "core/svg/SVGLineElement.h" @@ -34,14 +34,16 @@ namespace WebCore { +using namespace SVGNames; + static void updatePathFromCircleElement(SVGElement* element, Path& path) { SVGCircleElement* circle = toSVGCircleElement(element); SVGLengthContext lengthContext(element); - float r = circle->rCurrentValue().value(lengthContext); + float r = circle->r()->currentValue()->value(lengthContext); if (r > 0) - path.addEllipse(FloatRect(circle->cxCurrentValue().value(lengthContext) - r, circle->cyCurrentValue().value(lengthContext) - r, r * 2, r * 2)); + path.addEllipse(FloatRect(circle->cx()->currentValue()->value(lengthContext) - r, circle->cy()->currentValue()->value(lengthContext) - r, r * 2, r * 2)); } static void updatePathFromEllipseElement(SVGElement* element, Path& path) @@ -49,13 +51,16 @@ static void updatePathFromEllipseElement(SVGElement* element, Path& path) SVGEllipseElement* ellipse = toSVGEllipseElement(element); SVGLengthContext lengthContext(element); - float rx = ellipse->rxCurrentValue().value(lengthContext); - if (rx <= 0) + float rx = ellipse->rx()->currentValue()->value(lengthContext); + if (rx < 0) + return; + float ry = ellipse->ry()->currentValue()->value(lengthContext); + if (ry < 0) return; - float ry = ellipse->ryCurrentValue().value(lengthContext); - if (ry <= 0) + if (!rx && !ry) return; - path.addEllipse(FloatRect(ellipse->cxCurrentValue().value(lengthContext) - rx, ellipse->cyCurrentValue().value(lengthContext) - ry, rx * 2, ry * 2)); + + path.addEllipse(FloatRect(ellipse->cx()->currentValue()->value(lengthContext) - rx, ellipse->cy()->currentValue()->value(lengthContext) - ry, rx * 2, ry * 2)); } static void updatePathFromLineElement(SVGElement* element, Path& path) @@ -63,8 +68,8 @@ static void updatePathFromLineElement(SVGElement* element, Path& path) SVGLineElement* line = toSVGLineElement(element); SVGLengthContext lengthContext(element); - path.moveTo(FloatPoint(line->x1CurrentValue().value(lengthContext), line->y1CurrentValue().value(lengthContext))); - path.addLineTo(FloatPoint(line->x2CurrentValue().value(lengthContext), line->y2CurrentValue().value(lengthContext))); + path.moveTo(FloatPoint(line->x1()->currentValue()->value(lengthContext), line->y1()->currentValue()->value(lengthContext))); + path.addLineTo(FloatPoint(line->x2()->currentValue()->value(lengthContext), line->y2()->currentValue()->value(lengthContext))); } static void updatePathFromPathElement(SVGElement* element, Path& path) @@ -72,32 +77,26 @@ static void updatePathFromPathElement(SVGElement* element, Path& path) buildPathFromByteStream(toSVGPathElement(element)->pathByteStream(), path); } -static void updatePathFromPolygonElement(SVGElement* element, Path& path) +static void updatePathFromPolylineElement(SVGElement* element, Path& path) { - SVGPointList& points = toSVGPolygonElement(element)->pointsCurrentValue(); - if (points.isEmpty()) + RefPtr<SVGPointList> points = toSVGPolyElement(element)->points()->currentValue(); + if (points->isEmpty()) return; - path.moveTo(points.first()); - - unsigned size = points.size(); - for (unsigned i = 1; i < size; ++i) - path.addLineTo(points.at(i)); + SVGPointList::ConstIterator it = points->begin(); + SVGPointList::ConstIterator itEnd = points->end(); + ASSERT(it != itEnd); + path.moveTo(it->value()); + ++it; - path.closeSubpath(); + for (; it != itEnd; ++it) + path.addLineTo(it->value()); } -static void updatePathFromPolylineElement(SVGElement* element, Path& path) +static void updatePathFromPolygonElement(SVGElement* element, Path& path) { - SVGPointList& points = toSVGPolylineElement(element)->pointsCurrentValue(); - if (points.isEmpty()) - return; - - path.moveTo(points.first()); - - unsigned size = points.size(); - for (unsigned i = 1; i < size; ++i) - path.addLineTo(points.at(i)); + updatePathFromPolylineElement(element, path); + path.closeSubpath(); } static void updatePathFromRectElement(SVGElement* element, Path& path) @@ -105,19 +104,21 @@ static void updatePathFromRectElement(SVGElement* element, Path& path) SVGRectElement* rect = toSVGRectElement(element); SVGLengthContext lengthContext(element); - float width = rect->widthCurrentValue().value(lengthContext); - if (width <= 0) + float width = rect->width()->currentValue()->value(lengthContext); + if (width < 0) + return; + float height = rect->height()->currentValue()->value(lengthContext); + if (height < 0) return; - float height = rect->heightCurrentValue().value(lengthContext); - if (height <= 0) + if (!width && !height) return; - float x = rect->xCurrentValue().value(lengthContext); - float y = rect->yCurrentValue().value(lengthContext); - bool hasRx = rect->rxCurrentValue().value(lengthContext) > 0; - bool hasRy = rect->ryCurrentValue().value(lengthContext) > 0; + float x = rect->x()->currentValue()->value(lengthContext); + float y = rect->y()->currentValue()->value(lengthContext); + float rx = rect->rx()->currentValue()->value(lengthContext); + float ry = rect->ry()->currentValue()->value(lengthContext); + bool hasRx = rx > 0; + bool hasRy = ry > 0; if (hasRx || hasRy) { - float rx = rect->rxCurrentValue().value(lengthContext); - float ry = rect->ryCurrentValue().value(lengthContext); if (!hasRx) rx = ry; else if (!hasRy) @@ -139,13 +140,13 @@ void updatePathFromGraphicsElement(SVGElement* element, Path& path) static HashMap<StringImpl*, PathUpdateFunction>* map = 0; if (!map) { map = new HashMap<StringImpl*, PathUpdateFunction>; - map->set(SVGNames::circleTag.localName().impl(), updatePathFromCircleElement); - map->set(SVGNames::ellipseTag.localName().impl(), updatePathFromEllipseElement); - map->set(SVGNames::lineTag.localName().impl(), updatePathFromLineElement); - map->set(SVGNames::pathTag.localName().impl(), updatePathFromPathElement); - map->set(SVGNames::polygonTag.localName().impl(), updatePathFromPolygonElement); - map->set(SVGNames::polylineTag.localName().impl(), updatePathFromPolylineElement); - map->set(SVGNames::rectTag.localName().impl(), updatePathFromRectElement); + map->set(circleTag.localName().impl(), updatePathFromCircleElement); + map->set(ellipseTag.localName().impl(), updatePathFromEllipseElement); + map->set(lineTag.localName().impl(), updatePathFromLineElement); + map->set(pathTag.localName().impl(), updatePathFromPathElement); + map->set(polygonTag.localName().impl(), updatePathFromPolygonElement); + map->set(polylineTag.localName().impl(), updatePathFromPolylineElement); + map->set(rectTag.localName().impl(), updatePathFromRectElement); } if (PathUpdateFunction pathUpdateFunction = map->get(element->localName().impl())) diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRenderSupport.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRenderSupport.cpp index cfc4a641f7f..56c9e2cffdd 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRenderSupport.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRenderSupport.cpp @@ -23,9 +23,9 @@ */ #include "config.h" - #include "core/rendering/svg/SVGRenderSupport.h" +#include "core/rendering/PaintInfo.h" #include "core/rendering/RenderGeometryMap.h" #include "core/rendering/RenderLayer.h" #include "core/rendering/SubtreeLayoutScope.h" @@ -51,8 +51,8 @@ LayoutRect SVGRenderSupport::clippedOverflowRectForRepaint(const RenderObject* o // Pass our local paint rect to computeRectForRepaint() which will // map to parent coords and recurse up the parent chain. - FloatRect repaintRect = object->repaintRectInLocalCoordinates(); - object->computeFloatRectForRepaint(repaintContainer, repaintRect); + FloatRect repaintRect = object->paintInvalidationRectInLocalCoordinates(); + object->computeFloatRectForPaintInvalidation(repaintContainer, repaintRect); return enclosingLayoutRect(repaintRect); } @@ -60,9 +60,9 @@ void SVGRenderSupport::computeFloatRectForRepaint(const RenderObject* object, co { repaintRect.inflate(object->style()->outlineWidth()); - // Translate to coords in our parent renderer, and then call computeFloatRectForRepaint() on our parent. + // Translate to coords in our parent renderer, and then call computeFloatRectForPaintInvalidation() on our parent. repaintRect = object->localToParentTransform().mapRect(repaintRect); - object->parent()->computeFloatRectForRepaint(repaintContainer, repaintRect, fixed); + object->parent()->computeFloatRectForPaintInvalidation(repaintContainer, repaintRect, fixed); } void SVGRenderSupport::mapLocalToContainer(const RenderObject* object, const RenderLayerModelObject* repaintContainer, TransformState& transformState, bool* wasFixed) @@ -100,18 +100,24 @@ const RenderObject* SVGRenderSupport::pushMappingToContainer(const RenderObject* return parent; } -bool SVGRenderSupport::checkForSVGRepaintDuringLayout(RenderObject* object) +bool SVGRenderSupport::parentTransformDidChange(RenderObject* object) { - if (!object->checkForRepaintDuringLayout()) - return false; // When a parent container is transformed in SVG, all children will be painted automatically // so we are able to skip redundant repaint checks. RenderObject* parent = object->parent(); return !(parent && parent->isSVGContainer() && toRenderSVGContainer(parent)->didTransformToRootUpdate()); } +bool SVGRenderSupport::checkForSVGRepaintDuringLayout(RenderObject* object) +{ + if (!object->checkForPaintInvalidationDuringLayout()) + return false; + + return parentTransformDidChange(object); +} + // Update a bounding box taking into account the validity of the other bounding box. -static inline void updateObjectBoundingBox(FloatRect& objectBoundingBox, bool& objectBoundingBoxValid, RenderObject* other, FloatRect otherBoundingBox) +inline void SVGRenderSupport::updateObjectBoundingBox(FloatRect& objectBoundingBox, bool& objectBoundingBoxValid, RenderObject* other, FloatRect otherBoundingBox) { bool otherValid = other->isSVGContainer() ? toRenderSVGContainer(other)->isObjectBoundingBoxValid() : true; if (!otherValid) @@ -135,18 +141,14 @@ void SVGRenderSupport::computeContainerBoundingBoxes(const RenderObject* contain // When computing the strokeBoundingBox, we use the repaintRects of the container's children so that the container's stroke includes // the resources applied to the children (such as clips and filters). This allows filters applied to containers to correctly bound // the children, and also improves inlining of SVG content, as the stroke bound is used in that situation also. - for (RenderObject* current = container->firstChild(); current; current = current->nextSibling()) { + for (RenderObject* current = container->slowFirstChild(); current; current = current->nextSibling()) { if (current->isSVGHiddenContainer()) continue; const AffineTransform& transform = current->localToParentTransform(); - if (transform.isIdentity()) { - updateObjectBoundingBox(objectBoundingBox, objectBoundingBoxValid, current, current->objectBoundingBox()); - strokeBoundingBox.unite(current->repaintRectInLocalCoordinates()); - } else { - updateObjectBoundingBox(objectBoundingBox, objectBoundingBoxValid, current, transform.mapRect(current->objectBoundingBox())); - strokeBoundingBox.unite(transform.mapRect(current->repaintRectInLocalCoordinates())); - } + updateObjectBoundingBox(objectBoundingBox, objectBoundingBoxValid, current, + transform.mapRect(current->objectBoundingBox())); + strokeBoundingBox.unite(transform.mapRect(current->paintInvalidationRectInLocalCoordinates())); } repaintBoundingBox = strokeBoundingBox; @@ -154,9 +156,6 @@ void SVGRenderSupport::computeContainerBoundingBoxes(const RenderObject* contain bool SVGRenderSupport::paintInfoIntersectsRepaintRect(const FloatRect& localRepaintRect, const AffineTransform& localTransform, const PaintInfo& paintInfo) { - if (localTransform.isIdentity()) - return localRepaintRect.intersects(paintInfo.rect); - return localTransform.mapRect(localRepaintRect).intersects(paintInfo.rect); } @@ -170,17 +169,17 @@ const RenderSVGRoot* SVGRenderSupport::findTreeRootObject(const RenderObject* st return toRenderSVGRoot(start); } -static inline void invalidateResourcesOfChildren(RenderObject* start) +inline void SVGRenderSupport::invalidateResourcesOfChildren(RenderObject* start) { ASSERT(!start->needsLayout()); if (SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(start)) resources->removeClientFromCache(start, false); - for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) + for (RenderObject* child = start->slowFirstChild(); child; child = child->nextSibling()) invalidateResourcesOfChildren(child); } -static inline bool layoutSizeOfNearestViewportChanged(const RenderObject* start) +inline bool SVGRenderSupport::layoutSizeOfNearestViewportChanged(const RenderObject* start) { while (start && !start->isSVGRoot() && !start->isSVGViewportContainer()) start = start->parent(); @@ -212,7 +211,7 @@ void SVGRenderSupport::layoutChildren(RenderObject* start, bool selfNeedsLayout) bool transformChanged = transformToRootChanged(start); HashSet<RenderObject*> notlayoutedObjects; - for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) { + for (RenderObject* child = start->slowFirstChild(); child; child = child->nextSibling()) { bool needsLayout = selfNeedsLayout; bool childEverHadLayout = child->everHadLayout(); @@ -228,9 +227,9 @@ void SVGRenderSupport::layoutChildren(RenderObject* start, bool selfNeedsLayout) if (SVGElement* element = child->node()->isSVGElement() ? toSVGElement(child->node()) : 0) { if (element->hasRelativeLengths()) { // When the layout size changed and when using relative values tell the RenderSVGShape to update its shape object - if (child->isSVGShape()) + if (child->isSVGShape()) { toRenderSVGShape(child)->setNeedsShapeUpdate(); - else if (child->isSVGText()) { + } else if (child->isSVGText()) { toRenderSVGText(child)->setNeedsTextMetricsUpdate(); toRenderSVGText(child)->setNeedsPositioningValuesUpdate(); } @@ -240,7 +239,7 @@ void SVGRenderSupport::layoutChildren(RenderObject* start, bool selfNeedsLayout) } } - SubtreeLayoutScope layoutScope(child); + SubtreeLayoutScope layoutScope(*child); // Resource containers are nasty: they can invalidate clients outside the current SubtreeLayoutScope. // Since they only care about viewport size changes (to resolve their relative lengths), we trigger // their invalidation directly from SVGSVGElement::svgAttributeChange() or at a higher @@ -257,9 +256,10 @@ void SVGRenderSupport::layoutChildren(RenderObject* start, bool selfNeedsLayout) // We could handle this in the individual objects, but for now it's easier to have // parent containers call repaint(). (RenderBlock::layout* has similar logic.) if (!childEverHadLayout && !RuntimeEnabledFeatures::repaintAfterLayoutEnabled()) - child->repaint(); - } else if (layoutSizeChanged) + child->paintInvalidationForWholeRenderer(); + } else if (layoutSizeChanged) { notlayoutedObjects.add(child); + } } if (!layoutSizeChanged) { @@ -284,23 +284,16 @@ void SVGRenderSupport::layoutResourcesIfNeeded(const RenderObject* object) bool SVGRenderSupport::isOverflowHidden(const RenderObject* object) { - // SVG doesn't support independent x/y overflow - ASSERT(object->style()->overflowX() == object->style()->overflowY()); - - // OSCROLL is never set for SVG - see StyleResolver::adjustRenderStyle - ASSERT(object->style()->overflowX() != OSCROLL); - // RenderSVGRoot should never query for overflow state - it should always clip itself to the initial viewport size. - ASSERT(!object->isRoot()); + ASSERT(!object->isDocumentElement()); - return object->style()->overflowX() == OHIDDEN; + return object->style()->overflowX() == OHIDDEN || object->style()->overflowX() == OSCROLL; } -void SVGRenderSupport::intersectRepaintRectWithResources(const RenderObject* object, FloatRect& repaintRect) +void SVGRenderSupport::intersectRepaintRectWithResources(const RenderObject* renderer, FloatRect& repaintRect) { - ASSERT(object); + ASSERT(renderer); - RenderObject* renderer = const_cast<RenderObject*>(object); SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(renderer); if (!resources) return; @@ -357,21 +350,22 @@ void SVGRenderSupport::applyStrokeStyleToContext(GraphicsContext* context, const ASSERT(svgStyle); SVGLengthContext lengthContext(toSVGElement(object->node())); - context->setStrokeThickness(svgStyle->strokeWidth().value(lengthContext)); + context->setStrokeThickness(svgStyle->strokeWidth()->value(lengthContext)); context->setLineCap(svgStyle->capStyle()); context->setLineJoin(svgStyle->joinStyle()); context->setMiterLimit(svgStyle->strokeMiterLimit()); - const Vector<SVGLength>& dashes = svgStyle->strokeDashArray(); - if (dashes.isEmpty()) + RefPtr<SVGLengthList> dashes = svgStyle->strokeDashArray(); + if (dashes->isEmpty()) return; DashArray dashArray; - const Vector<SVGLength>::const_iterator end = dashes.end(); - for (Vector<SVGLength>::const_iterator it = dashes.begin(); it != end; ++it) - dashArray.append((*it).value(lengthContext)); + SVGLengthList::ConstIterator it = dashes->begin(); + SVGLengthList::ConstIterator itEnd = dashes->end(); + for (; it != itEnd; ++it) + dashArray.append(it->value(lengthContext)); - context->setLineDash(dashArray, svgStyle->strokeDashOffset().value(lengthContext)); + context->setLineDash(dashArray, svgStyle->strokeDashOffset()->value(lengthContext)); } void SVGRenderSupport::applyStrokeStyleToStrokeData(StrokeData* strokeData, const RenderStyle* style, const RenderObject* object) @@ -386,29 +380,28 @@ void SVGRenderSupport::applyStrokeStyleToStrokeData(StrokeData* strokeData, cons ASSERT(svgStyle); SVGLengthContext lengthContext(toSVGElement(object->node())); - strokeData->setThickness(svgStyle->strokeWidth().value(lengthContext)); + strokeData->setThickness(svgStyle->strokeWidth()->value(lengthContext)); strokeData->setLineCap(svgStyle->capStyle()); strokeData->setLineJoin(svgStyle->joinStyle()); strokeData->setMiterLimit(svgStyle->strokeMiterLimit()); - const Vector<SVGLength>& dashes = svgStyle->strokeDashArray(); - if (dashes.isEmpty()) + RefPtr<SVGLengthList> dashes = svgStyle->strokeDashArray(); + if (dashes->isEmpty()) return; DashArray dashArray; - const Vector<SVGLength>::const_iterator end = dashes.end(); - for (Vector<SVGLength>::const_iterator it = dashes.begin(); it != end; ++it) - dashArray.append((*it).value(lengthContext)); + size_t length = dashes->length(); + for (size_t i = 0; i < length; ++i) + dashArray.append(dashes->at(i)->value(lengthContext)); - strokeData->setLineDash(dashArray, svgStyle->strokeDashOffset().value(lengthContext)); + strokeData->setLineDash(dashArray, svgStyle->strokeDashOffset()->value(lengthContext)); } -bool SVGRenderSupport::isEmptySVGInlineText(const RenderObject* object) +bool SVGRenderSupport::isRenderableTextNode(const RenderObject* object) { - // RenderSVGInlineText performs whitespace filtering in order to support xml:space - // (http://www.w3.org/TR/SVG/struct.html#LangSpaceAttrs), and can end up with an empty string - // even when its original constructor argument is non-empty. - return object->isSVGInlineText() && toRenderSVGInlineText(object)->hasEmptyText(); + ASSERT(object->isText()); + // <br> is marked as text, but is not handled by the SVG rendering code-path. + return object->isSVGInlineText() && !toRenderSVGInlineText(object)->hasEmptyText(); } } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRenderSupport.h b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRenderSupport.h index 4265f64c780..087dcfbbd44 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRenderSupport.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRenderSupport.h @@ -24,23 +24,22 @@ #ifndef SVGRenderSupport_h #define SVGRenderSupport_h -#include "core/rendering/PaintInfo.h" - namespace WebCore { +class AffineTransform; class FloatPoint; class FloatRect; -class ImageBuffer; +class GraphicsContext; class LayoutRect; -class RenderBoxModelObject; +struct PaintInfo; class RenderGeometryMap; class RenderLayerModelObject; class RenderObject; class RenderStyle; class RenderSVGRoot; +class StrokeData; class TransformState; -// SVGRendererSupport is a helper class sharing code between all SVG renderers. class SVGRenderSupport { public: // Shares child layouting code between RenderSVGRoot/RenderSVG(Hidden)Container @@ -62,8 +61,11 @@ public: static bool pointInClippingArea(RenderObject*, const FloatPoint&); static void computeContainerBoundingBoxes(const RenderObject* container, FloatRect& objectBoundingBox, bool& objectBoundingBoxValid, FloatRect& strokeBoundingBox, FloatRect& repaintBoundingBox); + static bool paintInfoIntersectsRepaintRect(const FloatRect& localRepaintRect, const AffineTransform& localTransform, const PaintInfo&); + static bool parentTransformDidChange(RenderObject*); + // Important functions used by nearly all SVG renderers centralizing coordinate transformations / repaint rect calculations static LayoutRect clippedOverflowRectForRepaint(const RenderObject*, const RenderLayerModelObject* repaintContainer); static void computeFloatRectForRepaint(const RenderObject*, const RenderLayerModelObject* repaintContainer, FloatRect&, bool fixed); @@ -81,13 +83,14 @@ public: // FIXME: These methods do not belong here. static const RenderSVGRoot* findTreeRootObject(const RenderObject*); - // Helper method for determining whether an RenderSVGInlineText object has zero length text. - static bool isEmptySVGInlineText(const RenderObject*); + // Helper method for determining if a RenderObject marked as text (isText()== true) + // can/will be rendered as part of a <text>. + static bool isRenderableTextNode(const RenderObject*); private: - // This class is not constructable. - SVGRenderSupport(); - ~SVGRenderSupport(); + static void updateObjectBoundingBox(FloatRect& objectBoundingBox, bool& objectBoundingBoxValid, RenderObject* other, FloatRect otherBoundingBox); + static void invalidateResourcesOfChildren(RenderObject* start); + static bool layoutSizeOfNearestViewportChanged(const RenderObject* start); }; } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRenderTreeAsText.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRenderTreeAsText.cpp index b92e9b99833..15726cb9c37 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRenderTreeAsText.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRenderTreeAsText.cpp @@ -30,7 +30,6 @@ #include "core/rendering/svg/SVGRenderTreeAsText.h" -#include "SVGNames.h" #include "core/rendering/InlineTextBox.h" #include "core/rendering/RenderTreeAsText.h" #include "core/rendering/svg/RenderSVGGradientStop.h" @@ -64,6 +63,7 @@ #include "core/svg/SVGRadialGradientElement.h" #include "core/svg/SVGRectElement.h" #include "core/svg/SVGStopElement.h" +#include "platform/graphics/DashArray.h" #include "platform/graphics/GraphicsTypes.h" #include <math.h> @@ -154,15 +154,35 @@ static TextStream& operator<<(TextStream& ts, const WindRule rule) return ts; } +namespace { + +template<typename Enum> +String SVGEnumerationToString(Enum value) +{ + const SVGEnumerationStringEntries& entries = getStaticStringEntries<Enum>(); + + SVGEnumerationStringEntries::const_iterator it = entries.begin(); + SVGEnumerationStringEntries::const_iterator itEnd = entries.end(); + for (; it != itEnd; ++it) { + if (value == it->first) + return it->second; + } + + ASSERT_NOT_REACHED(); + return String(); +} + +} + static TextStream& operator<<(TextStream& ts, const SVGUnitTypes::SVGUnitType& unitType) { - ts << SVGPropertyTraits<SVGUnitTypes::SVGUnitType>::toString(unitType); + ts << SVGEnumerationToString<SVGUnitTypes::SVGUnitType>(unitType); return ts; } static TextStream& operator<<(TextStream& ts, const SVGMarkerUnitsType& markerUnit) { - ts << SVGPropertyTraits<SVGMarkerUnitsType>::toString(markerUnit); + ts << SVGEnumerationToString<SVGMarkerUnitsType>(markerUnit); return ts; } @@ -221,7 +241,7 @@ static TextStream& operator<<(TextStream& ts, LineJoin style) static TextStream& operator<<(TextStream& ts, const SVGSpreadMethodType& type) { - ts << SVGPropertyTraits<SVGSpreadMethodType>::toString(type).upper(); + ts << SVGEnumerationToString<SVGSpreadMethodType>(type).upper(); return ts; } @@ -260,21 +280,22 @@ static void writeStyle(TextStream& ts, const RenderObject& object) const RenderSVGShape& shape = static_cast<const RenderSVGShape&>(object); ASSERT(shape.element()); - Color fallbackColor; - if (RenderSVGResource* strokePaintingResource = RenderSVGResource::strokePaintingResource(const_cast<RenderSVGShape*>(&shape), shape.style(), fallbackColor)) { + bool hasFallback; + if (RenderSVGResource* strokePaintingResource = RenderSVGResource::strokePaintingResource(const_cast<RenderSVGShape*>(&shape), shape.style(), hasFallback)) { TextStreamSeparator s(" "); ts << " [stroke={" << s; writeSVGPaintingResource(ts, strokePaintingResource); SVGLengthContext lengthContext(shape.element()); - double dashOffset = svgStyle->strokeDashOffset().value(lengthContext); - double strokeWidth = svgStyle->strokeWidth().value(lengthContext); - const Vector<SVGLength>& dashes = svgStyle->strokeDashArray(); + double dashOffset = svgStyle->strokeDashOffset()->value(lengthContext); + double strokeWidth = svgStyle->strokeWidth()->value(lengthContext); + RefPtr<SVGLengthList> dashes = svgStyle->strokeDashArray(); DashArray dashArray; - const Vector<SVGLength>::const_iterator end = dashes.end(); - for (Vector<SVGLength>::const_iterator it = dashes.begin(); it != end; ++it) - dashArray.append((*it).value(lengthContext)); + SVGLengthList::ConstIterator it = dashes->begin(); + SVGLengthList::ConstIterator itEnd = dashes->end(); + for (; it != itEnd; ++it) + dashArray.append(it->value(lengthContext)); writeIfNotDefault(ts, "opacity", svgStyle->strokeOpacity(), 1.0f); writeIfNotDefault(ts, "stroke width", strokeWidth, 1.0); @@ -288,7 +309,7 @@ static void writeStyle(TextStream& ts, const RenderObject& object) ts << "}]"; } - if (RenderSVGResource* fillPaintingResource = RenderSVGResource::fillPaintingResource(const_cast<RenderSVGShape*>(&shape), shape.style(), fallbackColor)) { + if (RenderSVGResource* fillPaintingResource = RenderSVGResource::fillPaintingResource(const_cast<RenderSVGShape*>(&shape), shape.style(), hasFallback)) { TextStreamSeparator s(" "); ts << " [fill={" << s; writeSVGPaintingResource(ts, fillPaintingResource); @@ -317,37 +338,38 @@ static TextStream& operator<<(TextStream& ts, const RenderSVGShape& shape) writePositionAndStyle(ts, shape); SVGElement* svgElement = shape.element(); + ASSERT(svgElement); SVGLengthContext lengthContext(svgElement); - if (svgElement->hasTagName(SVGNames::rectTag)) { - SVGRectElement* element = toSVGRectElement(svgElement); - writeNameValuePair(ts, "x", element->xCurrentValue().value(lengthContext)); - writeNameValuePair(ts, "y", element->yCurrentValue().value(lengthContext)); - writeNameValuePair(ts, "width", element->widthCurrentValue().value(lengthContext)); - writeNameValuePair(ts, "height", element->heightCurrentValue().value(lengthContext)); - } else if (svgElement->hasTagName(SVGNames::lineTag)) { - SVGLineElement* element = toSVGLineElement(svgElement); - writeNameValuePair(ts, "x1", element->x1CurrentValue().value(lengthContext)); - writeNameValuePair(ts, "y1", element->y1CurrentValue().value(lengthContext)); - writeNameValuePair(ts, "x2", element->x2CurrentValue().value(lengthContext)); - writeNameValuePair(ts, "y2", element->y2CurrentValue().value(lengthContext)); - } else if (svgElement->hasTagName(SVGNames::ellipseTag)) { - SVGEllipseElement* element = toSVGEllipseElement(svgElement); - writeNameValuePair(ts, "cx", element->cxCurrentValue().value(lengthContext)); - writeNameValuePair(ts, "cy", element->cyCurrentValue().value(lengthContext)); - writeNameValuePair(ts, "rx", element->rxCurrentValue().value(lengthContext)); - writeNameValuePair(ts, "ry", element->ryCurrentValue().value(lengthContext)); - } else if (svgElement->hasTagName(SVGNames::circleTag)) { - SVGCircleElement* element = toSVGCircleElement(svgElement); - writeNameValuePair(ts, "cx", element->cxCurrentValue().value(lengthContext)); - writeNameValuePair(ts, "cy", element->cyCurrentValue().value(lengthContext)); - writeNameValuePair(ts, "r", element->rCurrentValue().value(lengthContext)); - } else if (svgElement->hasTagName(SVGNames::polygonTag) || svgElement->hasTagName(SVGNames::polylineTag)) { - writeNameAndQuotedValue(ts, "points", toSVGPolyElement(svgElement)->pointsCurrentValue().valueAsString()); - } else if (svgElement->hasTagName(SVGNames::pathTag)) { + if (isSVGRectElement(*svgElement)) { + SVGRectElement& element = toSVGRectElement(*svgElement); + writeNameValuePair(ts, "x", element.x()->currentValue()->value(lengthContext)); + writeNameValuePair(ts, "y", element.y()->currentValue()->value(lengthContext)); + writeNameValuePair(ts, "width", element.width()->currentValue()->value(lengthContext)); + writeNameValuePair(ts, "height", element.height()->currentValue()->value(lengthContext)); + } else if (isSVGLineElement(*svgElement)) { + SVGLineElement& element = toSVGLineElement(*svgElement); + writeNameValuePair(ts, "x1", element.x1()->currentValue()->value(lengthContext)); + writeNameValuePair(ts, "y1", element.y1()->currentValue()->value(lengthContext)); + writeNameValuePair(ts, "x2", element.x2()->currentValue()->value(lengthContext)); + writeNameValuePair(ts, "y2", element.y2()->currentValue()->value(lengthContext)); + } else if (isSVGEllipseElement(*svgElement)) { + SVGEllipseElement& element = toSVGEllipseElement(*svgElement); + writeNameValuePair(ts, "cx", element.cx()->currentValue()->value(lengthContext)); + writeNameValuePair(ts, "cy", element.cy()->currentValue()->value(lengthContext)); + writeNameValuePair(ts, "rx", element.rx()->currentValue()->value(lengthContext)); + writeNameValuePair(ts, "ry", element.ry()->currentValue()->value(lengthContext)); + } else if (isSVGCircleElement(*svgElement)) { + SVGCircleElement& element = toSVGCircleElement(*svgElement); + writeNameValuePair(ts, "cx", element.cx()->currentValue()->value(lengthContext)); + writeNameValuePair(ts, "cy", element.cy()->currentValue()->value(lengthContext)); + writeNameValuePair(ts, "r", element.r()->currentValue()->value(lengthContext)); + } else if (isSVGPolyElement(*svgElement)) { + writeNameAndQuotedValue(ts, "points", toSVGPolyElement(*svgElement).points()->currentValue()->valueAsString()); + } else if (isSVGPathElement(*svgElement)) { String pathString; // FIXME: We should switch to UnalteredParsing here - this will affect the path dumping output of dozens of tests. - buildStringFromByteStream(toSVGPathElement(svgElement)->pathByteStream(), pathString, NormalizedParsing); + buildStringFromByteStream(toSVGPathElement(*svgElement).pathByteStream(), pathString, NormalizedParsing); writeNameAndQuotedValue(ts, "data", pathString); } else ASSERT_NOT_REACHED(); @@ -380,11 +402,10 @@ static inline void writeSVGInlineTextBox(TextStream& ts, SVGInlineTextBox* textB if (fragments.isEmpty()) return; - RenderSVGInlineText* textRenderer = toRenderSVGInlineText(textBox->textRenderer()); - ASSERT(textRenderer); + RenderSVGInlineText& textRenderer = toRenderSVGInlineText(textBox->textRenderer()); - const SVGRenderStyle* svgStyle = textRenderer->style()->svgStyle(); - String text = textBox->textRenderer()->text(); + const SVGRenderStyle* svgStyle = textRenderer.style()->svgStyle(); + String text = textBox->textRenderer().text(); unsigned fragmentsSize = fragments.size(); for (unsigned i = 0; i < fragmentsSize; ++i) { @@ -452,7 +473,7 @@ static void writeStandardPrefix(TextStream& ts, const RenderObject& object, int static void writeChildren(TextStream& ts, const RenderObject& object, int indent) { - for (RenderObject* child = object.firstChild(); child; child = child->nextSibling()) + for (RenderObject* child = object.slowFirstChild(); child; child = child->nextSibling()) write(ts, *child, indent + 1); } @@ -490,7 +511,8 @@ void writeSVGResourceContainer(TextStream& ts, const RenderObject& object, int i ts << "\n"; // Creating a placeholder filter which is passed to the builder. FloatRect dummyRect; - RefPtr<SVGFilter> dummyFilter = SVGFilter::create(AffineTransform(), dummyRect, dummyRect, dummyRect, true); + IntRect dummyIntRect; + RefPtr<SVGFilter> dummyFilter = SVGFilter::create(AffineTransform(), dummyIntRect, dummyRect, dummyRect, true); if (RefPtr<SVGFilterBuilder> builder = filter->buildPrimitives(dummyFilter.get())) { if (FilterEffect* lastEffect = builder->lastEffect()) lastEffect->externalRepresentation(ts, indent + 1); @@ -614,7 +636,7 @@ void writeSVGGradientStop(TextStream& ts, const RenderSVGGradientStop& stop, int if (!style) return; - ts << " [offset=" << stopElement->offsetCurrentValue() << "] [color=" << stopElement->stopColorIncludingOpacity() << "]\n"; + ts << " [offset=" << stopElement->offset()->currentValue()->value() << "] [color=" << stopElement->stopColorIncludingOpacity() << "]\n"; } void writeResources(TextStream& ts, const RenderObject& object, int indent) diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRenderTreeAsText.h b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRenderTreeAsText.h index 055c587df57..63f26442a6d 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRenderTreeAsText.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRenderTreeAsText.h @@ -31,10 +31,6 @@ namespace WebCore { class Color; -class FloatRect; -class FloatSize; -class Node; -class RenderImage; class RenderObject; class RenderSVGGradientStop; class RenderSVGImage; @@ -43,7 +39,6 @@ class RenderSVGShape; class RenderSVGRoot; class RenderSVGText; class AffineTransform; -class SVGUnitTypes; // functions used by the main RenderTreeAsText code void write(TextStream&, const RenderSVGShape&, int indent); diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRenderingContext.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRenderingContext.cpp index 55545097c0f..23766e3a505 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRenderingContext.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRenderingContext.cpp @@ -26,9 +26,10 @@ #include "core/rendering/svg/SVGRenderingContext.h" -#include "core/frame/Frame.h" +#include "core/frame/FrameHost.h" #include "core/frame/FrameView.h" -#include "core/page/Page.h" +#include "core/frame/LocalFrame.h" +#include "core/frame/Settings.h" #include "core/rendering/RenderLayer.h" #include "core/rendering/svg/RenderSVGImage.h" #include "core/rendering/svg/RenderSVGResource.h" @@ -113,23 +114,28 @@ void SVGRenderingContext::prepareToRenderSVGContent(RenderObject* object, PaintI // Setup transparency layers before setting up SVG resources! bool isRenderingMask = isRenderingMaskImage(m_object); - float opacity = isRenderingMask ? 1 : style->opacity(); - blink::WebBlendMode blendMode = isRenderingMask ? blink::WebBlendModeNormal : style->blendMode(); - if (opacity < 1 || blendMode != blink::WebBlendModeNormal) { - FloatRect repaintRect = m_object->repaintRectInLocalCoordinates(); - - if (opacity < 1 || blendMode != blink::WebBlendModeNormal) { - m_paintInfo->context->clip(repaintRect); - if (blendMode != blink::WebBlendModeNormal) { - if (!(m_renderingFlags & RestoreGraphicsContext)) { - m_paintInfo->context->save(); - m_renderingFlags |= RestoreGraphicsContext; - } - m_paintInfo->context->setCompositeOperation(CompositeSourceOver, blendMode); + // RenderLayer takes care of root opacity. + float opacity = (object->isSVGRoot() || isRenderingMask) ? 1 : style->opacity(); + bool hasBlendMode = style->hasBlendMode() && !isRenderingMask; + + if (opacity < 1 || hasBlendMode || style->hasIsolation()) { + FloatRect repaintRect = m_object->paintInvalidationRectInLocalCoordinates(); + m_paintInfo->context->clip(repaintRect); + + if (hasBlendMode) { + if (!(m_renderingFlags & RestoreGraphicsContext)) { + m_paintInfo->context->save(); + m_renderingFlags |= RestoreGraphicsContext; } - m_paintInfo->context->beginTransparencyLayer(opacity); - m_renderingFlags |= EndOpacityLayer; + m_paintInfo->context->setCompositeOperation(CompositeSourceOver, style->blendMode()); } + + m_paintInfo->context->beginTransparencyLayer(opacity); + + if (hasBlendMode) + m_paintInfo->context->setCompositeOperation(CompositeSourceOver, blink::WebBlendModeNormal); + + m_renderingFlags |= EndOpacityLayer; } ClipPathOperation* clipPathOperation = style->clipPath(); @@ -197,20 +203,23 @@ float SVGRenderingContext::calculateScreenFontSizeScalingFactor(const RenderObje ASSERT(renderer); AffineTransform ctm; - calculateTransformationToOutermostCoordinateSystem(renderer, ctm); + // FIXME: calculateDeviceSpaceTransformation() queries layer compositing state - which is not + // supported during layout. Hence, the result may not include all CSS transforms. + calculateDeviceSpaceTransformation(renderer, ctm); return narrowPrecisionToFloat(sqrt((pow(ctm.xScale(), 2) + pow(ctm.yScale(), 2)) / 2)); } -void SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(const RenderObject* renderer, AffineTransform& absoluteTransform) +void SVGRenderingContext::calculateDeviceSpaceTransformation(const RenderObject* renderer, AffineTransform& absoluteTransform) { - ASSERT(renderer); - absoluteTransform = currentContentTransformation(); + // FIXME: trying to compute a device space transform at record time is wrong. All clients + // should be updated to avoid relying on this information, and the method should be removed. - float deviceScaleFactor = 1; - if (Page* page = renderer->document().page()) - deviceScaleFactor = page->deviceScaleFactor(); + ASSERT(renderer); + // We're about to possibly clear renderer, so save the deviceScaleFactor now. + float deviceScaleFactor = renderer->document().frameHost()->deviceScaleFactor(); // Walk up the render tree, accumulating SVG transforms. + absoluteTransform = currentContentTransformation(); while (renderer) { absoluteTransform = renderer->localToParentTransform() * absoluteTransform; if (renderer->isSVGRoot()) @@ -220,23 +229,22 @@ void SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(con // Continue walking up the layer tree, accumulating CSS transforms. RenderLayer* layer = renderer ? renderer->enclosingLayer() : 0; - while (layer) { - if (TransformationMatrix* layerTransform = layer->transform()) - absoluteTransform = layerTransform->toAffineTransform() * absoluteTransform; - + while (layer && layer->isAllowedToQueryCompositingState()) { // We can stop at compositing layers, to match the backing resolution. // FIXME: should we be computing the transform to the nearest composited layer, // or the nearest composited layer that does not paint into its ancestor? // I think this is the nearest composited ancestor since we will inherit its // transforms in the composited layer tree. - if (layer->hasCompositedLayerMapping()) + if (layer->compositingState() != NotComposited) break; + if (TransformationMatrix* layerTransform = layer->transform()) + absoluteTransform = layerTransform->toAffineTransform() * absoluteTransform; + layer = layer->parent(); } - if (deviceScaleFactor != 1) - absoluteTransform.scale(deviceScaleFactor); + absoluteTransform.scale(deviceScaleFactor); } void SVGRenderingContext::renderSubtree(GraphicsContext* context, RenderObject* item, const AffineTransform& subtreeContentTransformation) @@ -278,7 +286,7 @@ bool SVGRenderingContext::bufferForeground(OwnPtr<ImageBuffer>& imageBuffer) // Invalidate an existing buffer if the scale is not correct. if (imageBuffer) { - AffineTransform transform = m_paintInfo->context->getCTM(GraphicsContext::DefinitelyIncludeDeviceScale); + AffineTransform transform = m_paintInfo->context->getCTM(); IntSize expandedBoundingBox = expandedIntSize(boundingBox.size()); IntSize bufferSize(static_cast<int>(ceil(expandedBoundingBox.width() * transform.xScale())), static_cast<int>(ceil(expandedBoundingBox.height() * transform.yScale()))); if (bufferSize != imageBuffer->size()) diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRenderingContext.h b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRenderingContext.h index 742e0a09997..3fcda0ae099 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRenderingContext.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRenderingContext.h @@ -79,7 +79,7 @@ public: static void renderSubtree(GraphicsContext*, RenderObject*, const AffineTransform&); static float calculateScreenFontSizeScalingFactor(const RenderObject*); - static void calculateTransformationToOutermostCoordinateSystem(const RenderObject*, AffineTransform& absoluteTransform); + static void calculateDeviceSpaceTransformation(const RenderObject*, AffineTransform& absoluteTransform); static FloatRect clampedAbsoluteTargetRect(const FloatRect& absoluteTargetRect); static void clear2DRotation(AffineTransform&); diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGResources.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGResources.cpp index 5c42dbcef69..dcb5113bff7 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGResources.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGResources.cpp @@ -20,7 +20,7 @@ #include "config.h" #include "core/rendering/svg/SVGResources.h" -#include "SVGNames.h" +#include "core/SVGNames.h" #include "core/rendering/style/SVGRenderStyle.h" #include "core/rendering/svg/RenderSVGResourceClipper.h" #include "core/rendering/svg/RenderSVGResourceFilter.h" @@ -38,6 +38,8 @@ namespace WebCore { +using namespace SVGNames; + SVGResources::SVGResources() : m_linkedResource(0) { @@ -49,39 +51,45 @@ static HashSet<AtomicString>& clipperFilterMaskerTags() if (s_tagList.isEmpty()) { // "container elements": http://www.w3.org/TR/SVG11/intro.html#TermContainerElement // "graphics elements" : http://www.w3.org/TR/SVG11/intro.html#TermGraphicsElement - s_tagList.add(SVGNames::aTag.localName()); - s_tagList.add(SVGNames::circleTag.localName()); - s_tagList.add(SVGNames::ellipseTag.localName()); - s_tagList.add(SVGNames::glyphTag.localName()); - s_tagList.add(SVGNames::gTag.localName()); - s_tagList.add(SVGNames::imageTag.localName()); - s_tagList.add(SVGNames::lineTag.localName()); - s_tagList.add(SVGNames::markerTag.localName()); - s_tagList.add(SVGNames::maskTag.localName()); - s_tagList.add(SVGNames::missing_glyphTag.localName()); - s_tagList.add(SVGNames::pathTag.localName()); - s_tagList.add(SVGNames::polygonTag.localName()); - s_tagList.add(SVGNames::polylineTag.localName()); - s_tagList.add(SVGNames::rectTag.localName()); - s_tagList.add(SVGNames::svgTag.localName()); - s_tagList.add(SVGNames::textTag.localName()); - s_tagList.add(SVGNames::useTag.localName()); + s_tagList.add(aTag.localName()); + s_tagList.add(circleTag.localName()); + s_tagList.add(ellipseTag.localName()); +#if ENABLE(SVG_FONTS) + s_tagList.add(glyphTag.localName()); +#endif + s_tagList.add(gTag.localName()); + s_tagList.add(imageTag.localName()); + s_tagList.add(lineTag.localName()); + s_tagList.add(markerTag.localName()); + s_tagList.add(maskTag.localName()); +#if ENABLE(SVG_FONTS) + s_tagList.add(missing_glyphTag.localName()); +#endif + s_tagList.add(pathTag.localName()); + s_tagList.add(polygonTag.localName()); + s_tagList.add(polylineTag.localName()); + s_tagList.add(rectTag.localName()); + s_tagList.add(svgTag.localName()); + s_tagList.add(textTag.localName()); + s_tagList.add(useTag.localName()); // Not listed in the definitions is the clipPath element, the SVG spec says though: // The "clipPath" element or any of its children can specify property "clip-path". // So we have to add clipPathTag here, otherwhise clip-path on clipPath will fail. // (Already mailed SVG WG, waiting for a solution) - s_tagList.add(SVGNames::clipPathTag.localName()); + s_tagList.add(clipPathTag.localName()); // Not listed in the definitions are the text content elements, though filter/clipper/masker on tspan/text/.. is allowed. // (Already mailed SVG WG, waiting for a solution) - s_tagList.add(SVGNames::altGlyphTag.localName()); - s_tagList.add(SVGNames::textPathTag.localName()); - s_tagList.add(SVGNames::tspanTag.localName()); +#if ENABLE(SVG_FONTS) + s_tagList.add(altGlyphTag.localName()); +#endif + s_tagList.add(textPathTag.localName()); + s_tagList.add(tspanTag.localName()); // Not listed in the definitions is the foreignObject element, but clip-path // is a supported attribute. - s_tagList.add(SVGNames::foreignObjectTag.localName()); + s_tagList.add(foreignObjectTag.localName()); // Elements that we ignore, as it doesn't make any sense. // defs, pattern, switch (FIXME: Mail SVG WG about these) @@ -91,34 +99,36 @@ static HashSet<AtomicString>& clipperFilterMaskerTags() return s_tagList; } -static HashSet<AtomicString>& markerTags() +bool SVGResources::supportsMarkers(const SVGElement& element) { DEFINE_STATIC_LOCAL(HashSet<AtomicString>, s_tagList, ()); if (s_tagList.isEmpty()) { - s_tagList.add(SVGNames::lineTag.localName()); - s_tagList.add(SVGNames::pathTag.localName()); - s_tagList.add(SVGNames::polygonTag.localName()); - s_tagList.add(SVGNames::polylineTag.localName()); + s_tagList.add(lineTag.localName()); + s_tagList.add(pathTag.localName()); + s_tagList.add(polygonTag.localName()); + s_tagList.add(polylineTag.localName()); } - return s_tagList; + return s_tagList.contains(element.localName()); } static HashSet<AtomicString>& fillAndStrokeTags() { DEFINE_STATIC_LOCAL(HashSet<AtomicString>, s_tagList, ()); if (s_tagList.isEmpty()) { - s_tagList.add(SVGNames::altGlyphTag.localName()); - s_tagList.add(SVGNames::circleTag.localName()); - s_tagList.add(SVGNames::ellipseTag.localName()); - s_tagList.add(SVGNames::lineTag.localName()); - s_tagList.add(SVGNames::pathTag.localName()); - s_tagList.add(SVGNames::polygonTag.localName()); - s_tagList.add(SVGNames::polylineTag.localName()); - s_tagList.add(SVGNames::rectTag.localName()); - s_tagList.add(SVGNames::textTag.localName()); - s_tagList.add(SVGNames::textPathTag.localName()); - s_tagList.add(SVGNames::tspanTag.localName()); +#if ENABLE(SVG_FONTS) + s_tagList.add(altGlyphTag.localName()); +#endif + s_tagList.add(circleTag.localName()); + s_tagList.add(ellipseTag.localName()); + s_tagList.add(lineTag.localName()); + s_tagList.add(pathTag.localName()); + s_tagList.add(polygonTag.localName()); + s_tagList.add(polylineTag.localName()); + s_tagList.add(rectTag.localName()); + s_tagList.add(textTag.localName()); + s_tagList.add(textPathTag.localName()); + s_tagList.add(tspanTag.localName()); } return s_tagList; @@ -128,37 +138,52 @@ static HashSet<AtomicString>& chainableResourceTags() { DEFINE_STATIC_LOCAL(HashSet<AtomicString>, s_tagList, ()); if (s_tagList.isEmpty()) { - s_tagList.add(SVGNames::linearGradientTag.localName()); - s_tagList.add(SVGNames::filterTag.localName()); - s_tagList.add(SVGNames::patternTag.localName()); - s_tagList.add(SVGNames::radialGradientTag.localName()); + s_tagList.add(linearGradientTag.localName()); + s_tagList.add(filterTag.localName()); + s_tagList.add(patternTag.localName()); + s_tagList.add(radialGradientTag.localName()); } return s_tagList; } -static inline String targetReferenceFromResource(SVGElement* element) +static inline AtomicString targetReferenceFromResource(SVGElement& element) { String target; - if (element->hasTagName(SVGNames::patternTag)) - target = toSVGPatternElement(element)->hrefCurrentValue(); - else if (element->hasTagName(SVGNames::linearGradientTag) || element->hasTagName(SVGNames::radialGradientTag)) - target = toSVGGradientElement(element)->hrefCurrentValue(); - else if (element->hasTagName(SVGNames::filterTag)) - target = toSVGFilterElement(element)->hrefCurrentValue(); + if (isSVGPatternElement(element)) + target = toSVGPatternElement(element).href()->currentValue()->value(); + else if (isSVGGradientElement(element)) + target = toSVGGradientElement(element).href()->currentValue()->value(); + else if (isSVGFilterElement(element)) + target = toSVGFilterElement(element).href()->currentValue()->value(); else ASSERT_NOT_REACHED(); - return SVGURIReference::fragmentIdentifierFromIRIString(target, element->document()); + return SVGURIReference::fragmentIdentifierFromIRIString(target, element.treeScope()); +} + +static inline bool svgPaintTypeHasURL(SVGPaint::SVGPaintType paintType) +{ + switch (paintType) { + case SVGPaint::SVG_PAINTTYPE_URI_NONE: + case SVGPaint::SVG_PAINTTYPE_URI_CURRENTCOLOR: + case SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR: + case SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR_ICCCOLOR: + case SVGPaint::SVG_PAINTTYPE_URI: + return true; + default: + break; + } + return false; } -static inline RenderSVGResourceContainer* paintingResourceFromSVGPaint(Document& document, const SVGPaint::SVGPaintType& paintType, const String& paintUri, AtomicString& id, bool& hasPendingResource) +static inline RenderSVGResourceContainer* paintingResourceFromSVGPaint(TreeScope& treeScope, const SVGPaint::SVGPaintType& paintType, const String& paintUri, AtomicString& id, bool& hasPendingResource) { - if (paintType != SVGPaint::SVG_PAINTTYPE_URI && paintType != SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR) + if (!svgPaintTypeHasURL(paintType)) return 0; - id = SVGURIReference::fragmentIdentifierFromIRIString(paintUri, document); - RenderSVGResourceContainer* container = getRenderSVGResourceContainerById(document, id); + id = SVGURIReference::fragmentIdentifierFromIRIString(paintUri, treeScope); + RenderSVGResourceContainer* container = getRenderSVGResourceContainerById(treeScope, id); if (!container) { hasPendingResource = true; return 0; @@ -171,10 +196,10 @@ static inline RenderSVGResourceContainer* paintingResourceFromSVGPaint(Document& return container; } -static inline void registerPendingResource(SVGDocumentExtensions* extensions, const AtomicString& id, SVGElement* element) +static inline void registerPendingResource(SVGDocumentExtensions& extensions, const AtomicString& id, SVGElement* element) { ASSERT(element); - extensions->addPendingResource(id, element); + extensions.addPendingResource(id, element); } bool SVGResources::hasResourceData() const @@ -206,10 +231,9 @@ PassOwnPtr<SVGResources> SVGResources::buildResources(const RenderObject* object if (!element) return nullptr; - Document& document = object->document(); + TreeScope& treeScope = element->treeScope(); - SVGDocumentExtensions* extensions = document.accessSVGExtensions(); - ASSERT(extensions); + SVGDocumentExtensions& extensions = object->document().accessSVGExtensions(); const AtomicString& tagName = element->localName(); if (tagName.isNull()) @@ -218,35 +242,35 @@ PassOwnPtr<SVGResources> SVGResources::buildResources(const RenderObject* object OwnPtr<SVGResources> resources; if (clipperFilterMaskerTags().contains(tagName)) { if (style->hasClipper()) { - AtomicString id(style->clipperResource()); - if (!ensureResources(resources)->setClipper(getRenderSVGResourceById<RenderSVGResourceClipper>(document, id))) + AtomicString id = style->clipperResource(); + if (!ensureResources(resources)->setClipper(getRenderSVGResourceById<RenderSVGResourceClipper>(treeScope, id))) registerPendingResource(extensions, id, element); } if (style->hasFilter()) { - AtomicString id(style->filterResource()); - if (!ensureResources(resources)->setFilter(getRenderSVGResourceById<RenderSVGResourceFilter>(document, id))) + AtomicString id = style->filterResource(); + if (!ensureResources(resources)->setFilter(getRenderSVGResourceById<RenderSVGResourceFilter>(treeScope, id))) registerPendingResource(extensions, id, element); } if (style->hasMasker()) { - AtomicString id(style->maskerResource()); - if (!ensureResources(resources)->setMasker(getRenderSVGResourceById<RenderSVGResourceMasker>(document, id))) + AtomicString id = style->maskerResource(); + if (!ensureResources(resources)->setMasker(getRenderSVGResourceById<RenderSVGResourceMasker>(treeScope, id))) registerPendingResource(extensions, id, element); } } - if (markerTags().contains(tagName) && style->hasMarkers()) { - AtomicString markerStartId(style->markerStartResource()); - if (!ensureResources(resources)->setMarkerStart(getRenderSVGResourceById<RenderSVGResourceMarker>(document, markerStartId))) + if (style->hasMarkers() && supportsMarkers(*element)) { + const AtomicString& markerStartId = style->markerStartResource(); + if (!ensureResources(resources)->setMarkerStart(getRenderSVGResourceById<RenderSVGResourceMarker>(treeScope, markerStartId))) registerPendingResource(extensions, markerStartId, element); - AtomicString markerMidId(style->markerMidResource()); - if (!ensureResources(resources)->setMarkerMid(getRenderSVGResourceById<RenderSVGResourceMarker>(document, markerMidId))) + const AtomicString& markerMidId = style->markerMidResource(); + if (!ensureResources(resources)->setMarkerMid(getRenderSVGResourceById<RenderSVGResourceMarker>(treeScope, markerMidId))) registerPendingResource(extensions, markerMidId, element); - AtomicString markerEndId(style->markerEndResource()); - if (!ensureResources(resources)->setMarkerEnd(getRenderSVGResourceById<RenderSVGResourceMarker>(document, markerEndId))) + const AtomicString& markerEndId = style->markerEndResource(); + if (!ensureResources(resources)->setMarkerEnd(getRenderSVGResourceById<RenderSVGResourceMarker>(treeScope, style->markerEndResource()))) registerPendingResource(extensions, markerEndId, element); } @@ -254,7 +278,7 @@ PassOwnPtr<SVGResources> SVGResources::buildResources(const RenderObject* object if (style->hasFill()) { bool hasPendingResource = false; AtomicString id; - RenderSVGResourceContainer* resource = paintingResourceFromSVGPaint(document, style->fillPaintType(), style->fillPaintUri(), id, hasPendingResource); + RenderSVGResourceContainer* resource = paintingResourceFromSVGPaint(treeScope, style->fillPaintType(), style->fillPaintUri(), id, hasPendingResource); if (!ensureResources(resources)->setFill(resource) && hasPendingResource) { registerPendingResource(extensions, id, element); } @@ -263,7 +287,7 @@ PassOwnPtr<SVGResources> SVGResources::buildResources(const RenderObject* object if (style->hasStroke()) { bool hasPendingResource = false; AtomicString id; - RenderSVGResourceContainer* resource = paintingResourceFromSVGPaint(document, style->strokePaintType(), style->strokePaintUri(), id, hasPendingResource); + RenderSVGResourceContainer* resource = paintingResourceFromSVGPaint(treeScope, style->strokePaintType(), style->strokePaintUri(), id, hasPendingResource); if (!ensureResources(resources)->setStroke(resource) && hasPendingResource) { registerPendingResource(extensions, id, element); } @@ -271,8 +295,8 @@ PassOwnPtr<SVGResources> SVGResources::buildResources(const RenderObject* object } if (chainableResourceTags().contains(tagName)) { - AtomicString id(targetReferenceFromResource(element)); - if (!ensureResources(resources)->setLinkedResource(getRenderSVGResourceContainerById(document, id))) + AtomicString id = targetReferenceFromResource(*element); + if (!ensureResources(resources)->setLinkedResource(getRenderSVGResourceContainerById(treeScope, id))) registerPendingResource(extensions, id, element); } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGResources.h b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGResources.h index 8eb10adcb4e..41cdf2569d8 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGResources.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGResources.h @@ -20,6 +20,7 @@ #ifndef SVGResources_h #define SVGResources_h +#include "wtf/FastAllocBase.h" #include "wtf/HashSet.h" #include "wtf/Noncopyable.h" #include "wtf/OwnPtr.h" @@ -27,13 +28,13 @@ namespace WebCore { -class Document; class RenderObject; class RenderSVGResourceClipper; class RenderSVGResourceContainer; class RenderSVGResourceFilter; class RenderSVGResourceMarker; class RenderSVGResourceMasker; +class SVGElement; class SVGRenderStyle; // Holds a set of resources associated with a RenderObject @@ -45,6 +46,8 @@ public: static PassOwnPtr<SVGResources> buildResources(const RenderObject*, const SVGRenderStyle*); void layoutIfNeeded(); + static bool supportsMarkers(const SVGElement&); + // Ordinary resources RenderSVGResourceClipper* clipper() const { return m_clipperFilterMaskerData ? m_clipperFilterMaskerData->clipper : 0; } RenderSVGResourceMarker* markerStart() const { return m_markerData ? m_markerData->markerStart : 0; } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGResourcesCache.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGResourcesCache.cpp index 7a8ed18b4d8..b8ba7101ded 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGResourcesCache.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGResourcesCache.cpp @@ -20,7 +20,7 @@ #include "config.h" #include "core/rendering/svg/SVGResourcesCache.h" -#include "HTMLNames.h" +#include "core/HTMLNames.h" #include "core/rendering/svg/RenderSVGResourceContainer.h" #include "core/rendering/svg/SVGResources.h" #include "core/rendering/svg/SVGResourcesCycleSolver.h" @@ -51,7 +51,7 @@ void SVGResourcesCache::addResourcesFromRenderObject(RenderObject* object, const return; // Put object in cache. - SVGResources* resources = m_cache.set(object, newResources.release()).iterator->value.get(); + SVGResources* resources = m_cache.set(object, newResources.release()).storedValue->value.get(); // Run cycle-detection _afterwards_, so self-references can be caught as well. SVGResourcesCycleSolver solver(object, resources); @@ -85,10 +85,8 @@ static inline SVGResourcesCache* resourcesCacheFromRenderObject(const RenderObje { Document& document = renderer->document(); - SVGDocumentExtensions* extensions = document.accessSVGExtensions(); - ASSERT(extensions); - - SVGResourcesCache* cache = extensions->resourcesCache(); + SVGDocumentExtensions& extensions = document.accessSVGExtensions(); + SVGResourcesCache* cache = extensions.resourcesCache(); ASSERT(cache); return cache; @@ -124,11 +122,11 @@ void SVGResourcesCache::clientStyleChanged(RenderObject* renderer, StyleDifferen ASSERT(renderer->node()); ASSERT(renderer->node()->isSVGElement()); - if (diff == StyleDifferenceEqual || !renderer->parent()) + if (diff.hasNoChange() || !renderer->parent()) return; // In this case the proper SVGFE*Element will decide whether the modified CSS properties require a relayout or repaint. - if (renderer->isSVGResourceFilterPrimitive() && (diff == StyleDifferenceRepaint || diff == StyleDifferenceRepaintIfTextOrColorChange)) + if (renderer->isSVGResourceFilterPrimitive() && !diff.needsLayout()) return; // Dynamic changes of CSS properties like 'clip-path' may require us to recompute the associated resources for a renderer. @@ -194,9 +192,9 @@ void SVGResourcesCache::resourceDestroyed(RenderSVGResourceContainer* resource) // Mark users of destroyed resources as pending resolution based on the id of the old resource. Element* resourceElement = resource->element(); Element* clientElement = toElement(it->key->node()); - SVGDocumentExtensions* extensions = clientElement->document().accessSVGExtensions(); + SVGDocumentExtensions& extensions = clientElement->document().accessSVGExtensions(); - extensions->addPendingResource(resourceElement->fastGetAttribute(HTMLNames::idAttr), clientElement); + extensions.addPendingResource(resourceElement->fastGetAttribute(HTMLNames::idAttr), clientElement); } } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGResourcesCache.h b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGResourcesCache.h index ff5e9f903af..7bf878e7237 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGResourcesCache.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGResourcesCache.h @@ -20,7 +20,8 @@ #ifndef SVGResourcesCache_h #define SVGResourcesCache_h -#include "core/rendering/style/RenderStyleConstants.h" +#include "core/rendering/style/StyleDifference.h" +#include "wtf/FastAllocBase.h" #include "wtf/HashMap.h" #include "wtf/Noncopyable.h" #include "wtf/OwnPtr.h" diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGResourcesCycleSolver.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGResourcesCycleSolver.cpp index efa1b933394..ae7e954fb04 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGResourcesCycleSolver.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGResourcesCycleSolver.cpp @@ -47,117 +47,83 @@ SVGResourcesCycleSolver::~SVGResourcesCycleSolver() { } -bool SVGResourcesCycleSolver::resourceContainsCycles(RenderObject* renderer) const -{ - ASSERT(renderer); - - // First operate on the resources of the given renderer. - // <marker id="a"> <path marker-start="url(#b)"/> ... - // <marker id="b" marker-start="url(#a)"/> - if (SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(renderer)) { - HashSet<RenderSVGResourceContainer*> resourceSet; - resources->buildSetOfResources(resourceSet); - - // Walk all resources and check wheter they reference any resource contained in the resources set. - HashSet<RenderSVGResourceContainer*>::iterator end = resourceSet.end(); - for (HashSet<RenderSVGResourceContainer*>::iterator it = resourceSet.begin(); it != end; ++it) { - if (m_allResources.contains(*it)) - return true; - } - } +struct ActiveFrame { + typedef SVGResourcesCycleSolver::ResourceSet ResourceSet; - // Then operate on the child resources of the given renderer. - // <marker id="a"> <path marker-start="url(#b)"/> ... - // <marker id="b"> <path marker-start="url(#a)"/> ... - for (RenderObject* child = renderer->firstChild(); child; child = child->nextSibling()) { - SVGResources* childResources = SVGResourcesCache::cachedResourcesForRenderObject(child); - if (!childResources) - continue; + ActiveFrame(ResourceSet& activeSet, RenderSVGResourceContainer* resource) + : m_activeSet(activeSet) + , m_resource(resource) + { + m_activeSet.add(m_resource); + } + ~ActiveFrame() + { + m_activeSet.remove(m_resource); + } - // A child of the given 'resource' contains resources. - HashSet<RenderSVGResourceContainer*> childSet; - childResources->buildSetOfResources(childSet); + ResourceSet& m_activeSet; + RenderSVGResourceContainer* m_resource; +}; - // Walk all child resources and check wheter they reference any resource contained in the resources set. - HashSet<RenderSVGResourceContainer*>::iterator end = childSet.end(); - for (HashSet<RenderSVGResourceContainer*>::iterator it = childSet.begin(); it != end; ++it) { - if (m_allResources.contains(*it)) - return true; +bool SVGResourcesCycleSolver::resourceContainsCycles(RenderSVGResourceContainer* resource) +{ + // If we've traversed this sub-graph before and no cycles were observed, then + // reuse that result. + if (m_dagCache.contains(resource)) + return false; + + ActiveFrame frame(m_activeResources, resource); + + RenderObject* node = resource; + while (node) { + // Skip subtrees which are themselves resources. (They will be + // processed - if needed - when they are actually referenced.) + if (node != resource && node->isSVGResourceContainer()) { + node = node->nextInPreOrderAfterChildren(resource); + continue; } - - // Walk children recursively, stop immediately if we found a cycle - if (resourceContainsCycles(child)) - return true; + if (SVGResources* nodeResources = SVGResourcesCache::cachedResourcesForRenderObject(node)) { + // Fetch all the resources referenced by |node|. + ResourceSet nodeSet; + nodeResources->buildSetOfResources(nodeSet); + + // Iterate resources referenced by |node|. + ResourceSet::iterator end = nodeSet.end(); + for (ResourceSet::iterator it = nodeSet.begin(); it != end; ++it) { + if (m_activeResources.contains(*it) || resourceContainsCycles(*it)) + return true; + } + } + node = node->nextInPreOrder(resource); } + // No cycles found in (or from) this resource. Add it to the "DAG cache". + m_dagCache.add(resource); return false; } void SVGResourcesCycleSolver::resolveCycles() { - ASSERT(m_allResources.isEmpty()); - -#if DEBUG_CYCLE_DETECTION > 0 - fprintf(stderr, "\nBefore cycle detection:\n"); - m_resources->dump(m_renderer); -#endif - - // Stash all resources into a HashSet for the ease of traversing. - HashSet<RenderSVGResourceContainer*> localResources; - m_resources->buildSetOfResources(localResources); - ASSERT(!localResources.isEmpty()); - - // Add all parent resource containers to the HashSet. - HashSet<RenderSVGResourceContainer*> parentResources; - RenderObject* parent = m_renderer->parent(); - while (parent) { - if (parent->isSVGResourceContainer()) - parentResources.add(toRenderSVGResourceContainer(parent)); - parent = parent->parent(); - } + ASSERT(m_activeResources.isEmpty()); -#if DEBUG_CYCLE_DETECTION > 0 - fprintf(stderr, "\nDetecting wheter any resources references any of following objects:\n"); - { - fprintf(stderr, "Local resources:\n"); - HashSet<RenderSVGResourceContainer*>::iterator end = localResources.end(); - for (HashSet<RenderSVGResourceContainer*>::iterator it = localResources.begin(); it != end; ++it) - fprintf(stderr, "|> %s: object=%p (node=%p)\n", (*it)->renderName(), *it, (*it)->node()); - - fprintf(stderr, "Parent resources:\n"); - end = parentResources.end(); - for (HashSet<RenderSVGResourceContainer*>::iterator it = parentResources.begin(); it != end; ++it) - fprintf(stderr, "|> %s: object=%p (node=%p)\n", (*it)->renderName(), *it, (*it)->node()); - } -#endif - - // Build combined set of local and parent resources. - m_allResources = localResources; - HashSet<RenderSVGResourceContainer*>::iterator end = parentResources.end(); - for (HashSet<RenderSVGResourceContainer*>::iterator it = parentResources.begin(); it != end; ++it) - m_allResources.add(*it); - - // If we're a resource, add ourselves to the HashSet. + // If the starting RenderObject is a resource container itself, then add it + // to the active set (to break direct self-references.) if (m_renderer->isSVGResourceContainer()) - m_allResources.add(toRenderSVGResourceContainer(m_renderer)); + m_activeResources.add(toRenderSVGResourceContainer(m_renderer)); - ASSERT(!m_allResources.isEmpty()); + ResourceSet localResources; + m_resources->buildSetOfResources(localResources); - // The job of this function is to determine wheter any of the 'resources' associated with the given 'renderer' - // references us (or wheter any of its kids references us) -> that's a cycle, we need to find and break it. - end = localResources.end(); - for (HashSet<RenderSVGResourceContainer*>::iterator it = localResources.begin(); it != end; ++it) { - RenderSVGResourceContainer* resource = *it; - if (parentResources.contains(resource) || resourceContainsCycles(resource)) - breakCycle(resource); + // This performs a depth-first search for a back-edge in all the + // (potentially disjoint) graphs formed by the resources referenced by + // |m_renderer|. + ResourceSet::iterator end = localResources.end(); + for (ResourceSet::iterator it = localResources.begin(); it != end; ++it) { + if (m_activeResources.contains(*it) || resourceContainsCycles(*it)) + breakCycle(*it); } -#if DEBUG_CYCLE_DETECTION > 0 - fprintf(stderr, "\nAfter cycle detection:\n"); - m_resources->dump(m_renderer); -#endif - - m_allResources.clear(); + m_activeResources.clear(); } void SVGResourcesCycleSolver::breakCycle(RenderSVGResourceContainer* resourceLeadingToCycle) diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGResourcesCycleSolver.h b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGResourcesCycleSolver.h index cadaa5a311e..aadd9f6fa54 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGResourcesCycleSolver.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGResourcesCycleSolver.h @@ -37,13 +37,17 @@ public: void resolveCycles(); + typedef HashSet<RenderSVGResourceContainer*> ResourceSet; + private: - bool resourceContainsCycles(RenderObject*) const; + bool resourceContainsCycles(RenderSVGResourceContainer*); void breakCycle(RenderSVGResourceContainer*); RenderObject* m_renderer; SVGResources* m_resources; - HashSet<RenderSVGResourceContainer*> m_allResources; + + ResourceSet m_activeResources; + ResourceSet m_dagCache; }; } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRootInlineBox.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRootInlineBox.cpp index ec9a953d1b3..4cd80101e37 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRootInlineBox.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRootInlineBox.cpp @@ -24,7 +24,6 @@ #include "config.h" #include "core/rendering/svg/SVGRootInlineBox.h" -#include "SVGNames.h" #include "core/rendering/svg/RenderSVGInlineText.h" #include "core/rendering/svg/RenderSVGText.h" #include "core/rendering/svg/SVGInlineFlowBox.h" @@ -33,15 +32,12 @@ namespace WebCore { -void SVGRootInlineBox::paint(PaintInfo& paintInfo, const LayoutPoint&, LayoutUnit, LayoutUnit) +void SVGRootInlineBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit, LayoutUnit) { ASSERT(paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection); ASSERT(!paintInfo.context->paintingDisabled()); - RenderObject* boxRenderer = renderer(); - ASSERT(boxRenderer); - - bool isPrinting = renderer()->document().printing(); + bool isPrinting = renderer().document().printing(); bool hasSelection = !isPrinting && selectionState() != RenderObject::SelectionNone; PaintInfo childPaintInfo(paintInfo); @@ -54,35 +50,29 @@ void SVGRootInlineBox::paint(PaintInfo& paintInfo, const LayoutPoint&, LayoutUni } } - SVGRenderingContext renderingContext(boxRenderer, paintInfo, SVGRenderingContext::SaveGraphicsContext); + SVGRenderingContext renderingContext(&renderer(), paintInfo, SVGRenderingContext::SaveGraphicsContext); if (renderingContext.isRenderingPrepared()) { - for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) { - if (child->isSVGInlineTextBox()) - SVGInlineFlowBox::computeTextMatchMarkerRectForRenderer(toRenderSVGInlineText(toSVGInlineTextBox(child)->textRenderer())); - - child->paint(paintInfo, LayoutPoint(), 0, 0); - } + for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) + child->paint(paintInfo, paintOffset, 0, 0); } } -void SVGRootInlineBox::markDirty(bool dirty) +void SVGRootInlineBox::markDirty() { - if (dirty) - for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) - child->markDirty(true); - RootInlineBox::markDirty(dirty); + for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) + child->markDirty(); + RootInlineBox::markDirty(); } void SVGRootInlineBox::computePerCharacterLayoutInformation() { - RenderSVGText* textRoot = toRenderSVGText(block()); - ASSERT(textRoot); + RenderSVGText& textRoot = toRenderSVGText(block()); - Vector<SVGTextLayoutAttributes*>& layoutAttributes = textRoot->layoutAttributes(); + Vector<SVGTextLayoutAttributes*>& layoutAttributes = textRoot.layoutAttributes(); if (layoutAttributes.isEmpty()) return; - if (textRoot->needsReordering()) + if (textRoot.needsReordering()) reorderValueLists(layoutAttributes); // Perform SVG text layout phase two (see SVGTextLayoutEngine for details). @@ -103,24 +93,23 @@ void SVGRootInlineBox::layoutCharactersInTextBoxes(InlineFlowBox* start, SVGText { for (InlineBox* child = start->firstChild(); child; child = child->nextOnLine()) { if (child->isSVGInlineTextBox()) { - ASSERT(child->renderer()); - ASSERT(child->renderer()->isSVGInlineText()); + ASSERT(child->renderer().isSVGInlineText()); characterLayout.layoutInlineTextBox(toSVGInlineTextBox(child)); } else { // Skip generated content. - Node* node = child->renderer()->node(); + Node* node = child->renderer().node(); if (!node) continue; SVGInlineFlowBox* flowBox = toSVGInlineFlowBox(child); - bool isTextPath = node->hasTagName(SVGNames::textPathTag); + bool isTextPath = isSVGTextPathElement(*node); if (isTextPath) { // Build text chunks for all <textPath> children, using the line layout algorithm. // This is needeed as text-anchor is just an additional startOffset for text paths. SVGTextLayoutEngine lineLayout(characterLayout.layoutAttributes()); layoutCharactersInTextBoxes(flowBox, lineLayout); - characterLayout.beginTextPathLayout(child->renderer(), lineLayout); + characterLayout.beginTextPathLayout(&child->renderer(), lineLayout); } layoutCharactersInTextBoxes(flowBox, characterLayout); @@ -136,8 +125,7 @@ void SVGRootInlineBox::layoutChildBoxes(InlineFlowBox* start, FloatRect* childRe for (InlineBox* child = start->firstChild(); child; child = child->nextOnLine()) { FloatRect boxRect; if (child->isSVGInlineTextBox()) { - ASSERT(child->renderer()); - ASSERT(child->renderer()->isSVGInlineText()); + ASSERT(child->renderer().isSVGInlineText()); SVGInlineTextBox* textBox = toSVGInlineTextBox(child); boxRect = textBox->calculateBoundaries(); @@ -147,7 +135,7 @@ void SVGRootInlineBox::layoutChildBoxes(InlineFlowBox* start, FloatRect* childRe textBox->setLogicalHeight(boxRect.height()); } else { // Skip generated content. - if (!child->renderer()->node()) + if (!child->renderer().node()) continue; SVGInlineFlowBox* flowBox = toSVGInlineFlowBox(child); @@ -166,18 +154,17 @@ void SVGRootInlineBox::layoutChildBoxes(InlineFlowBox* start, FloatRect* childRe void SVGRootInlineBox::layoutRootBox(const FloatRect& childRect) { - RenderBlockFlow* parentBlock = block(); - ASSERT(parentBlock); + RenderBlockFlow& parentBlock = block(); // Finally, assign the root block position, now that all content is laid out. LayoutRect boundingRect = enclosingLayoutRect(childRect); - parentBlock->setLocation(boundingRect.location()); - parentBlock->setSize(boundingRect.size()); + parentBlock.setLocation(boundingRect.location()); + parentBlock.setSize(boundingRect.size()); // Position all children relative to the parent block. for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) { // Skip generated content. - if (!child->renderer()->node()) + if (!child->renderer().node()) continue; child->adjustPosition(-childRect.x(), -childRect.y()); } @@ -221,21 +208,11 @@ static inline void swapItemsInLayoutAttributes(SVGTextLayoutAttributes* firstAtt SVGCharacterDataMap::iterator itLast = lastAttributes->characterDataMap().find(lastPosition + 1); bool firstPresent = itFirst != firstAttributes->characterDataMap().end(); bool lastPresent = itLast != lastAttributes->characterDataMap().end(); - if (!firstPresent && !lastPresent) + // We only want to perform the swap if both inline boxes are absolutely + // positioned. + if (!firstPresent || !lastPresent) return; - - if (firstPresent && lastPresent) { - std::swap(itFirst->value, itLast->value); - return; - } - - if (firstPresent && !lastPresent) { - lastAttributes->characterDataMap().set(lastPosition + 1, itFirst->value); - return; - } - - // !firstPresent && lastPresent - firstAttributes->characterDataMap().set(firstPosition + 1, itLast->value); + std::swap(itFirst->value, itLast->value); } static inline void findFirstAndLastAttributesInVector(Vector<SVGTextLayoutAttributes*>& attributes, RenderSVGInlineText* firstContext, RenderSVGInlineText* lastContext, @@ -282,12 +259,12 @@ static inline void reverseInlineBoxRangeAndValueListsIfNeeded(void* userData, Ve // Reordering is only necessary for BiDi text that is _absolutely_ positioned. if (firstTextBox->len() == 1 && firstTextBox->len() == lastTextBox->len()) { - RenderSVGInlineText* firstContext = toRenderSVGInlineText(firstTextBox->textRenderer()); - RenderSVGInlineText* lastContext = toRenderSVGInlineText(lastTextBox->textRenderer()); + RenderSVGInlineText& firstContext = toRenderSVGInlineText(firstTextBox->textRenderer()); + RenderSVGInlineText& lastContext = toRenderSVGInlineText(lastTextBox->textRenderer()); SVGTextLayoutAttributes* firstAttributes = 0; SVGTextLayoutAttributes* lastAttributes = 0; - findFirstAndLastAttributesInVector(attributes, firstContext, lastContext, firstAttributes, lastAttributes); + findFirstAndLastAttributesInVector(attributes, &firstContext, &lastContext, firstAttributes, lastAttributes); swapItemsInLayoutAttributes(firstAttributes, lastAttributes, firstTextBox->start(), lastTextBox->start()); } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRootInlineBox.h b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRootInlineBox.h index efbe2f6b79b..862c9b24a4e 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRootInlineBox.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGRootInlineBox.h @@ -29,24 +29,22 @@ namespace WebCore { -class SVGInlineTextBox; - class SVGRootInlineBox FINAL : public RootInlineBox { public: - SVGRootInlineBox(RenderBlockFlow* block) + SVGRootInlineBox(RenderBlockFlow& block) : RootInlineBox(block) , m_logicalHeight(0) { } - virtual bool isSVGRootInlineBox() const OVERRIDE FINAL { return true; } + virtual bool isSVGRootInlineBox() const OVERRIDE { return true; } - virtual float virtualLogicalHeight() const OVERRIDE FINAL { return m_logicalHeight; } + virtual float virtualLogicalHeight() const OVERRIDE { return m_logicalHeight; } void setLogicalHeight(float height) { m_logicalHeight = height; } - virtual void paint(PaintInfo&, const LayoutPoint&, LayoutUnit lineTop, LayoutUnit lineBottom) OVERRIDE FINAL; + virtual void paint(PaintInfo&, const LayoutPoint&, LayoutUnit lineTop, LayoutUnit lineBottom) OVERRIDE; - virtual void markDirty(bool dirty = true) OVERRIDE FINAL; + virtual void markDirty() OVERRIDE; void computePerCharacterLayoutInformation(); diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextChunkBuilder.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextChunkBuilder.cpp index d26d868fff1..488fbd4bddd 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextChunkBuilder.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextChunkBuilder.cpp @@ -91,10 +91,9 @@ void SVGTextChunkBuilder::addTextChunk(Vector<SVGInlineTextBox*>& lineLayoutBoxe SVGInlineTextBox* textBox = lineLayoutBoxes[boxStart]; ASSERT(textBox); - RenderSVGInlineText* textRenderer = toRenderSVGInlineText(textBox->textRenderer()); - ASSERT(textRenderer); + RenderSVGInlineText& textRenderer = toRenderSVGInlineText(textBox->textRenderer()); - const RenderStyle* style = textRenderer->style(); + const RenderStyle* style = toRenderSVGInlineText(textBox->textRenderer()).style(); ASSERT(style); const SVGRenderStyle* svgStyle = style->svgStyle(); @@ -125,11 +124,14 @@ void SVGTextChunkBuilder::addTextChunk(Vector<SVGInlineTextBox*>& lineLayoutBoxe // Handle 'lengthAdjust' property. float desiredTextLength = 0; - if (SVGTextContentElement* textContentElement = SVGTextContentElement::elementFromRenderer(textRenderer->parent())) { + if (SVGTextContentElement* textContentElement = SVGTextContentElement::elementFromRenderer(textRenderer.parent())) { SVGLengthContext lengthContext(textContentElement); - desiredTextLength = textContentElement->specifiedTextLength().value(lengthContext); + if (textContentElement->textLengthIsSpecifiedByUser()) + desiredTextLength = textContentElement->textLength()->currentValue()->value(lengthContext); + else + desiredTextLength = 0; - switch (textContentElement->lengthAdjustCurrentValue()) { + switch (textContentElement->lengthAdjust()->currentValue()->enumValue()) { case SVGLengthAdjustUnknown: break; case SVGLengthAdjustSpacing: diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutAttributesBuilder.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutAttributesBuilder.cpp index 7c65a7e55e6..cbf018dc87a 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutAttributesBuilder.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutAttributesBuilder.cpp @@ -23,6 +23,7 @@ #include "core/rendering/svg/RenderSVGInlineText.h" #include "core/rendering/svg/RenderSVGText.h" +#include "core/rendering/svg/SVGTextMetricsBuilder.h" #include "core/svg/SVGTextPositioningElement.h" namespace WebCore { @@ -53,7 +54,7 @@ void SVGTextLayoutAttributesBuilder::buildLayoutAttributesForTextRenderer(Render buildCharacterDataMap(textRoot); } - m_metricsBuilder.buildMetricsAndLayoutAttributes(textRoot, text, m_characterDataMap); + SVGTextMetricsBuilder::buildMetricsAndLayoutAttributes(textRoot, text, m_characterDataMap); } bool SVGTextLayoutAttributesBuilder::buildLayoutAttributesForForSubtree(RenderSVGText* textRoot) @@ -72,14 +73,14 @@ bool SVGTextLayoutAttributesBuilder::buildLayoutAttributesForForSubtree(RenderSV return false; buildCharacterDataMap(textRoot); - m_metricsBuilder.buildMetricsAndLayoutAttributes(textRoot, 0, m_characterDataMap); + SVGTextMetricsBuilder::buildMetricsAndLayoutAttributes(textRoot, 0, m_characterDataMap); return true; } void SVGTextLayoutAttributesBuilder::rebuildMetricsForTextRenderer(RenderSVGInlineText* text) { ASSERT(text); - m_metricsBuilder.measureTextRenderer(text); + SVGTextMetricsBuilder::measureTextRenderer(text); } static inline void processRenderSVGInlineText(RenderSVGInlineText* text, unsigned& atCharacter, UChar& lastCharacter) @@ -104,7 +105,7 @@ void SVGTextLayoutAttributesBuilder::collectTextPositioningElements(RenderObject { ASSERT(!start->isSVGText() || m_textPositions.isEmpty()); - for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) { + for (RenderObject* child = start->slowFirstChild(); child; child = child->nextSibling()) { if (child->isSVGInlineText()) { processRenderSVGInlineText(toRenderSVGInlineText(child), m_textLength, lastCharacter); continue; @@ -163,43 +164,43 @@ void SVGTextLayoutAttributesBuilder::buildCharacterDataMap(RenderSVGText* textRo static inline void updateCharacterData(unsigned i, float& lastRotation, SVGCharacterData& data, const SVGLengthContext& lengthContext, const SVGLengthList* xList, const SVGLengthList* yList, const SVGLengthList* dxList, const SVGLengthList* dyList, const SVGNumberList* rotateList) { if (xList) - data.x = xList->at(i).value(lengthContext); + data.x = xList->at(i)->value(lengthContext); if (yList) - data.y = yList->at(i).value(lengthContext); + data.y = yList->at(i)->value(lengthContext); if (dxList) - data.dx = dxList->at(i).value(lengthContext); + data.dx = dxList->at(i)->value(lengthContext); if (dyList) - data.dy = dyList->at(i).value(lengthContext); + data.dy = dyList->at(i)->value(lengthContext); if (rotateList) { - data.rotate = rotateList->at(i).value(); + data.rotate = rotateList->at(i)->value(); lastRotation = data.rotate; } } void SVGTextLayoutAttributesBuilder::fillCharacterDataMap(const TextPosition& position) { - const SVGLengthList& xList = position.element->xCurrentValue(); - const SVGLengthList& yList = position.element->yCurrentValue(); - const SVGLengthList& dxList = position.element->dxCurrentValue(); - const SVGLengthList& dyList = position.element->dyCurrentValue(); - const SVGNumberList& rotateList = position.element->rotateCurrentValue(); - - unsigned xListSize = xList.size(); - unsigned yListSize = yList.size(); - unsigned dxListSize = dxList.size(); - unsigned dyListSize = dyList.size(); - unsigned rotateListSize = rotateList.size(); + RefPtr<SVGLengthList> xList = position.element->x()->currentValue(); + RefPtr<SVGLengthList> yList = position.element->y()->currentValue(); + RefPtr<SVGLengthList> dxList = position.element->dx()->currentValue(); + RefPtr<SVGLengthList> dyList = position.element->dy()->currentValue(); + RefPtr<SVGNumberList> rotateList = position.element->rotate()->currentValue(); + + unsigned xListSize = xList->length(); + unsigned yListSize = yList->length(); + unsigned dxListSize = dxList->length(); + unsigned dyListSize = dyList->length(); + unsigned rotateListSize = rotateList->length(); if (!xListSize && !yListSize && !dxListSize && !dyListSize && !rotateListSize) return; float lastRotation = SVGTextLayoutAttributes::emptyValue(); SVGLengthContext lengthContext(position.element); for (unsigned i = 0; i < position.length; ++i) { - const SVGLengthList* xListPtr = i < xListSize ? &xList : 0; - const SVGLengthList* yListPtr = i < yListSize ? &yList : 0; - const SVGLengthList* dxListPtr = i < dxListSize ? &dxList : 0; - const SVGLengthList* dyListPtr = i < dyListSize ? &dyList : 0; - const SVGNumberList* rotateListPtr = i < rotateListSize ? &rotateList : 0; + const SVGLengthList* xListPtr = i < xListSize ? xList.get() : 0; + const SVGLengthList* yListPtr = i < yListSize ? yList.get() : 0; + const SVGLengthList* dxListPtr = i < dxListSize ? dxList.get() : 0; + const SVGLengthList* dyListPtr = i < dyListSize ? dyList.get() : 0; + const SVGNumberList* rotateListPtr = i < rotateListSize ? rotateList.get() : 0; if (!xListPtr && !yListPtr && !dxListPtr && !dyListPtr && !rotateListPtr) break; @@ -218,7 +219,7 @@ void SVGTextLayoutAttributesBuilder::fillCharacterDataMap(const TextPosition& po if (lastRotation == SVGTextLayoutAttributes::emptyValue()) return; - for (unsigned i = rotateList.size(); i < position.length; ++i) { + for (unsigned i = rotateList->length(); i < position.length; ++i) { SVGCharacterDataMap::iterator it = m_characterDataMap.find(position.start + i + 1); if (it == m_characterDataMap.end()) { SVGCharacterData data; diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutAttributesBuilder.h b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutAttributesBuilder.h index d92c125f47f..82d2d064660 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutAttributesBuilder.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutAttributesBuilder.h @@ -20,7 +20,7 @@ #ifndef SVGTextLayoutAttributesBuilder_h #define SVGTextLayoutAttributesBuilder_h -#include "core/rendering/svg/SVGTextMetricsBuilder.h" +#include "core/rendering/svg/SVGTextLayoutAttributes.h" #include "wtf/Vector.h" namespace WebCore { @@ -73,7 +73,6 @@ private: unsigned m_textLength; Vector<TextPosition> m_textPositions; SVGCharacterDataMap m_characterDataMap; - SVGTextMetricsBuilder m_metricsBuilder; }; } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutEngine.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutEngine.cpp index 0ade353f4a7..fc5dc792329 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutEngine.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutEngine.cpp @@ -47,6 +47,7 @@ SVGTextLayoutEngine::SVGTextLayoutEngine(Vector<SVGTextLayoutAttributes*>& layou , m_dy(0) , m_isVerticalText(false) , m_inPathLayout(false) + , m_textPathCalculator(0) , m_textPathLength(0) , m_textPathCurrentOffset(0) , m_textPathSpacing(0) @@ -148,7 +149,7 @@ bool SVGTextLayoutEngine::parentDefinesTextLength(RenderObject* parent) const while (currentParent) { if (SVGTextContentElement* textContentElement = SVGTextContentElement::elementFromRenderer(currentParent)) { SVGLengthContext lengthContext(textContentElement); - if (textContentElement->lengthAdjustCurrentValue() == SVGLengthAdjustSpacing && textContentElement->specifiedTextLength().value(lengthContext) > 0) + if (textContentElement->lengthAdjust()->currentValue()->enumValue() == SVGLengthAdjustSpacing && textContentElement->textLengthIsSpecifiedByUser()) return true; } @@ -169,11 +170,12 @@ void SVGTextLayoutEngine::beginTextPathLayout(RenderObject* object, SVGTextLayou m_inPathLayout = true; RenderSVGTextPath* textPath = toRenderSVGTextPath(object); - m_textPath = textPath->layoutPath(); - if (m_textPath.isEmpty()) + Path path = textPath->layoutPath(); + if (path.isEmpty()) return; + m_textPathCalculator = new Path::PositionCalculator(path); m_textPathStartOffset = textPath->startOffset(); - m_textPathLength = m_textPath.length(); + m_textPathLength = path.length(); if (m_textPathStartOffset > 0 && m_textPathStartOffset <= 1) m_textPathStartOffset *= m_textPathLength; @@ -206,8 +208,11 @@ void SVGTextLayoutEngine::beginTextPathLayout(RenderObject* object, SVGTextLayou if (SVGTextContentElement* textContentElement = SVGTextContentElement::elementFromRenderer(textPath)) { SVGLengthContext lengthContext(textContentElement); - lengthAdjust = textContentElement->lengthAdjustCurrentValue(); - desiredTextLength = textContentElement->specifiedTextLength().value(lengthContext); + lengthAdjust = textContentElement->lengthAdjust()->currentValue()->enumValue(); + if (textContentElement->textLengthIsSpecifiedByUser()) + desiredTextLength = textContentElement->textLength()->currentValue()->value(lengthContext); + else + desiredTextLength = 0; } if (!desiredTextLength) @@ -222,7 +227,8 @@ void SVGTextLayoutEngine::beginTextPathLayout(RenderObject* object, SVGTextLayou void SVGTextLayoutEngine::endTextPathLayout() { m_inPathLayout = false; - m_textPath = Path(); + delete m_textPathCalculator; + m_textPathCalculator = 0; m_textPathLength = 0; m_textPathStartOffset = 0; m_textPathCurrentOffset = 0; @@ -234,18 +240,17 @@ void SVGTextLayoutEngine::layoutInlineTextBox(SVGInlineTextBox* textBox) { ASSERT(textBox); - RenderSVGInlineText* text = toRenderSVGInlineText(textBox->textRenderer()); - ASSERT(text); - ASSERT(text->parent()); - ASSERT(text->parent()->node()); - ASSERT(text->parent()->node()->isSVGElement()); + RenderSVGInlineText& text = toRenderSVGInlineText(textBox->textRenderer()); + ASSERT(text.parent()); + ASSERT(text.parent()->node()); + ASSERT(text.parent()->node()->isSVGElement()); - const RenderStyle* style = text->style(); + const RenderStyle* style = text.style(); ASSERT(style); textBox->clearTextFragments(); m_isVerticalText = style->svgStyle()->isVerticalWritingMode(); - layoutTextOnLineOrPath(textBox, text, style); + layoutTextOnLineOrPath(textBox, &text, style); if (m_inPathLayout) { m_pathLayoutBoxes.append(textBox); @@ -421,7 +426,7 @@ void SVGTextLayoutEngine::advanceToNextVisualCharacter(const SVGTextMetrics& vis void SVGTextLayoutEngine::layoutTextOnLineOrPath(SVGInlineTextBox* textBox, RenderSVGInlineText* text, const RenderStyle* style) { - if (m_inPathLayout && m_textPath.isEmpty()) + if (m_inPathLayout && !m_textPathCalculator) return; SVGElement* lengthContext = toSVGElement(text->parent()->node()); @@ -440,7 +445,7 @@ void SVGTextLayoutEngine::layoutTextOnLineOrPath(SVGInlineTextBox* textBox, Rend const Font& font = style->font(); - SVGTextLayoutEngineSpacing spacingLayout(font); + SVGTextLayoutEngineSpacing spacingLayout(font, style->effectiveZoom()); SVGTextLayoutEngineBaseline baselineLayout(font); bool didStartTextFragment = false; @@ -505,8 +510,8 @@ void SVGTextLayoutEngine::layoutTextOnLineOrPath(SVGInlineTextBox* textBox, Rend // Calculate SVG Fonts kerning, if needed. float kerning = spacingLayout.calculateSVGKerning(m_isVerticalText, visualMetrics.glyph()); - // Calculate CSS 'kerning', 'letter-spacing' and 'word-spacing' for next character, if needed. - float spacing = spacingLayout.calculateCSSKerningAndSpacing(svgStyle, lengthContext, currentCharacter); + // Calculate CSS 'letter-spacing' and 'word-spacing' for next character, if needed. + float spacing = spacingLayout.calculateCSSSpacing(currentCharacter); float textPathOffset = 0; if (m_inPathLayout) { @@ -552,14 +557,11 @@ void SVGTextLayoutEngine::layoutTextOnLineOrPath(SVGInlineTextBox* textBox, Rend if (textPathOffset > m_textPathLength) break; - bool ok = false; - FloatPoint point = m_textPath.pointAtLength(textPathOffset, ok); - ASSERT(ok); - + FloatPoint point; + bool ok = m_textPathCalculator->pointAndNormalAtLength(textPathOffset, point, angle); + ASSERT_UNUSED(ok, ok); x = point.x(); y = point.y(); - angle = m_textPath.normalAngleAtLength(textPathOffset, ok); - ASSERT(ok); // For vertical text on path, the actual angle has to be rotated 90 degrees anti-clockwise, not the orientation angle! if (m_isVerticalText) diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutEngine.h b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutEngine.h index 3ae5fa09087..b3c91a445b2 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutEngine.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutEngine.h @@ -32,9 +32,7 @@ namespace WebCore { class RenderObject; class RenderStyle; class RenderSVGInlineText; -class SVGElement; class SVGInlineTextBox; -class SVGRenderStyle; // SVGTextLayoutEngine performs the second layout phase for SVG text. // @@ -96,7 +94,7 @@ private: bool m_inPathLayout; // Text on path layout - Path m_textPath; + Path::PositionCalculator* m_textPathCalculator; float m_textPathLength; float m_textPathStartOffset; float m_textPathCurrentOffset; diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutEngineBaseline.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutEngineBaseline.cpp index 3825b4b1220..95c3beb137c 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutEngineBaseline.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutEngineBaseline.cpp @@ -38,12 +38,12 @@ SVGTextLayoutEngineBaseline::SVGTextLayoutEngineBaseline(const Font& font) float SVGTextLayoutEngineBaseline::calculateBaselineShift(const SVGRenderStyle* style, SVGElement* contextElement) const { if (style->baselineShift() == BS_LENGTH) { - SVGLength baselineShiftValueLength = style->baselineShiftValue(); - if (baselineShiftValueLength.unitType() == LengthTypePercentage) - return baselineShiftValueLength.valueAsPercentage() * m_font.pixelSize(); + RefPtr<SVGLength> baselineShiftValueLength = style->baselineShiftValue(); + if (baselineShiftValueLength->unitType() == LengthTypePercentage) + return baselineShiftValueLength->valueAsPercentage() * m_font.fontDescription().computedPixelSize(); SVGLengthContext lengthContext(contextElement); - return baselineShiftValueLength.value(lengthContext); + return baselineShiftValueLength->value(lengthContext); } switch (style->baselineShift()) { @@ -160,7 +160,7 @@ float SVGTextLayoutEngineBaseline::calculateGlyphOrientationAngle(bool isVertica case GO_AUTO: { // Spec: Fullwidth ideographic and fullwidth Latin text will be set with a glyph-orientation of 0-degrees. // Text which is not fullwidth will be set with a glyph-orientation of 90-degrees. - unsigned int unicodeRange = findCharUnicodeRange(character); + unsigned unicodeRange = findCharUnicodeRange(character); if (unicodeRange == cRangeSetLatin || unicodeRange == cRangeArabic) return 90; diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutEngineSpacing.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutEngineSpacing.cpp index 6f68e475f1e..e93bb48b41a 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutEngineSpacing.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutEngineSpacing.cpp @@ -21,8 +21,8 @@ #include "core/rendering/svg/SVGTextLayoutEngineSpacing.h" -#include "core/rendering/style/SVGRenderStyle.h" #include "core/svg/SVGLengthContext.h" +#include "platform/fonts/Character.h" #include "platform/fonts/Font.h" #if ENABLE(SVG_FONTS) @@ -33,18 +33,23 @@ namespace WebCore { -SVGTextLayoutEngineSpacing::SVGTextLayoutEngineSpacing(const Font& font) +SVGTextLayoutEngineSpacing::SVGTextLayoutEngineSpacing(const Font& font, float effectiveZoom) : m_font(font) , m_lastCharacter(0) + , m_effectiveZoom(effectiveZoom) +#if ENABLE(SVG_FONTS) + , m_lastGlyph(0) +#endif { + ASSERT(m_effectiveZoom); } -float SVGTextLayoutEngineSpacing::calculateSVGKerning(bool isVerticalText, const SVGTextMetrics::Glyph& currentGlyph) +float SVGTextLayoutEngineSpacing::calculateSVGKerning(bool isVerticalText, Glyph currentGlyph) { #if ENABLE(SVG_FONTS) const SimpleFontData* fontData = m_font.primaryFont(); if (!fontData->isSVGFont()) { - m_lastGlyph.isValid = false; + m_lastGlyph = 0; return 0; } @@ -58,50 +63,44 @@ float SVGTextLayoutEngineSpacing::calculateSVGKerning(bool isVerticalText, const SVGFontElement* svgFont = svgFontFace->associatedFontElement(); if (!svgFont) { - m_lastGlyph.isValid = false; + m_lastGlyph = 0; return 0; } float kerning = 0; - if (m_lastGlyph.isValid) { + if (m_lastGlyph) { if (isVerticalText) - kerning = svgFont->verticalKerningForPairOfStringsAndGlyphs(m_lastGlyph.unicodeString, m_lastGlyph.name, currentGlyph.unicodeString, currentGlyph.name); + kerning = svgFont->verticalKerningForPairOfGlyphs(m_lastGlyph, currentGlyph); else - kerning = svgFont->horizontalKerningForPairOfStringsAndGlyphs(m_lastGlyph.unicodeString, m_lastGlyph.name, currentGlyph.unicodeString, currentGlyph.name); + kerning = svgFont->horizontalKerningForPairOfGlyphs(m_lastGlyph, currentGlyph); + + kerning *= m_font.fontDescription().computedSize() / m_font.fontMetrics().unitsPerEm(); } m_lastGlyph = currentGlyph; - m_lastGlyph.isValid = true; - kerning *= m_font.size() / m_font.fontMetrics().unitsPerEm(); return kerning; #else - return false; + return 0; #endif } -float SVGTextLayoutEngineSpacing::calculateCSSKerningAndSpacing(const SVGRenderStyle* style, SVGElement* contextElement, UChar currentCharacter) +float SVGTextLayoutEngineSpacing::calculateCSSSpacing(UChar currentCharacter) { - float kerning = 0; - SVGLength kerningLength = style->kerning(); - if (kerningLength.unitType() == LengthTypePercentage) - kerning = kerningLength.valueAsPercentage() * m_font.pixelSize(); - else { - SVGLengthContext lengthContext(contextElement); - kerning = kerningLength.value(lengthContext); - } - UChar lastCharacter = m_lastCharacter; m_lastCharacter = currentCharacter; - if (!kerning && !m_font.letterSpacing() && !m_font.wordSpacing()) + if (!m_font.fontDescription().letterSpacing() && !m_font.fontDescription().wordSpacing()) return 0; - float spacing = m_font.letterSpacing() + kerning; - if (currentCharacter && lastCharacter && m_font.wordSpacing()) { - if (Font::treatAsSpace(currentCharacter) && !Font::treatAsSpace(lastCharacter)) - spacing += m_font.wordSpacing(); + float spacing = m_font.fontDescription().letterSpacing(); + if (currentCharacter && lastCharacter && m_font.fontDescription().wordSpacing()) { + if (Character::treatAsSpace(currentCharacter) && !Character::treatAsSpace(lastCharacter)) + spacing += m_font.fontDescription().wordSpacing(); } + if (m_effectiveZoom != 1) + spacing = spacing / m_effectiveZoom; + return spacing; } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutEngineSpacing.h b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutEngineSpacing.h index 5cc8bec5533..8618e246dd4 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutEngineSpacing.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextLayoutEngineSpacing.h @@ -25,24 +25,23 @@ namespace WebCore { class Font; -class SVGRenderStyle; -class SVGElement; -// Helper class used by SVGTextLayoutEngine to handle 'kerning' / 'letter-spacing' and 'word-spacing'. +// Helper class used by SVGTextLayoutEngine to handle 'letter-spacing' and 'word-spacing'. class SVGTextLayoutEngineSpacing { WTF_MAKE_NONCOPYABLE(SVGTextLayoutEngineSpacing); public: - SVGTextLayoutEngineSpacing(const Font&); + SVGTextLayoutEngineSpacing(const Font&, float effectiveZoom); - float calculateSVGKerning(bool isVerticalText, const SVGTextMetrics::Glyph& currentGlyph); - float calculateCSSKerningAndSpacing(const SVGRenderStyle*, SVGElement* lengthContext, UChar currentCharacter); + float calculateSVGKerning(bool isVerticalText, Glyph currentGlyph); + float calculateCSSSpacing(UChar currentCharacter); private: const Font& m_font; UChar m_lastCharacter; + float m_effectiveZoom; #if ENABLE(SVG_FONTS) - SVGTextMetrics::Glyph m_lastGlyph; + Glyph m_lastGlyph; #endif }; diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextMetrics.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextMetrics.cpp index 26c82dbec27..3ab52797f77 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextMetrics.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextMetrics.cpp @@ -30,6 +30,7 @@ SVGTextMetrics::SVGTextMetrics() : m_width(0) , m_height(0) , m_length(0) + , m_glyph(0) { } @@ -37,6 +38,7 @@ SVGTextMetrics::SVGTextMetrics(SVGTextMetrics::MetricsType) : m_width(0) , m_height(0) , m_length(1) + , m_glyph(0) { } @@ -51,18 +53,21 @@ SVGTextMetrics::SVGTextMetrics(RenderSVGInlineText* textRenderer, const TextRun& int length = 0; // Calculate width/height using the scaled font, divide this result by the scalingFactor afterwards. - m_width = scaledFont.width(run, length, m_glyph.name) / scalingFactor; + m_width = scaledFont.width(run, length, m_glyph) / scalingFactor; m_height = scaledFont.fontMetrics().floatHeight() / scalingFactor; - m_glyph.unicodeString = run.is8Bit() ? String(run.characters8(), length) : String(run.characters16(), length); - m_glyph.isValid = true; - ASSERT(length >= 0); m_length = static_cast<unsigned>(length); } TextRun SVGTextMetrics::constructTextRun(RenderSVGInlineText* text, unsigned position, unsigned length) { + ASSERT(text->style()); + return constructTextRun(text, position, length, text->style()->direction()); +} + +TextRun SVGTextMetrics::constructTextRun(RenderSVGInlineText* text, unsigned position, unsigned length, TextDirection textDirection) +{ RenderStyle* style = text->style(); ASSERT(style); @@ -71,7 +76,7 @@ TextRun SVGTextMetrics::constructTextRun(RenderSVGInlineText* text, unsigned pos , 0 // xPos, only relevant with allowTabs=true , 0 // padding, only relevant for justified text, not relevant for SVG , TextRun::AllowTrailingExpansion - , style->direction() + , textDirection , isOverride(style->unicodeBidi()) /* directionalOverride */); if (length) { @@ -95,13 +100,19 @@ TextRun SVGTextMetrics::constructTextRun(RenderSVGInlineText* text, unsigned pos return run; } +SVGTextMetrics SVGTextMetrics::measureCharacterRange(RenderSVGInlineText* text, unsigned position, unsigned length, TextDirection textDirection) +{ + ASSERT(text); + return SVGTextMetrics(text, constructTextRun(text, position, length, textDirection)); +} + SVGTextMetrics SVGTextMetrics::measureCharacterRange(RenderSVGInlineText* text, unsigned position, unsigned length) { ASSERT(text); return SVGTextMetrics(text, constructTextRun(text, position, length)); } -SVGTextMetrics::SVGTextMetrics(RenderSVGInlineText* text, unsigned position, unsigned length, float width, const String& glyphName) +SVGTextMetrics::SVGTextMetrics(RenderSVGInlineText* text, unsigned position, unsigned length, float width, Glyph glyphNameGlyphId) { ASSERT(text); @@ -111,11 +122,7 @@ SVGTextMetrics::SVGTextMetrics(RenderSVGInlineText* text, unsigned position, uns m_width = width / scalingFactor; m_height = text->scaledFont().fontMetrics().floatHeight() / scalingFactor; - if (needsContext) { - m_glyph.isValid = true; - m_glyph.unicodeString = text->substring(position, length); - m_glyph.name = glyphName; - } + m_glyph = needsContext ? glyphNameGlyphId : 0; m_length = length; } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextMetrics.h b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextMetrics.h index 362933997ed..3c04901e2cf 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextMetrics.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextMetrics.h @@ -20,12 +20,13 @@ #ifndef SVGTextMetrics_h #define SVGTextMetrics_h +#include "platform/fonts/Glyph.h" +#include "platform/text/TextDirection.h" #include "wtf/text/WTFString.h" namespace WebCore { class RenderSVGInlineText; -class SVGTextLayoutAttributes; class TextRun; class SVGTextMetrics { @@ -36,12 +37,16 @@ public: SVGTextMetrics(); SVGTextMetrics(MetricsType); - SVGTextMetrics(RenderSVGInlineText*, unsigned position, unsigned length, float width, const String& glyphName); + SVGTextMetrics(RenderSVGInlineText*, unsigned position, unsigned length, float width, Glyph glyphNameGlyphId); + // FIXME: Migrate away from these to the two below. static SVGTextMetrics measureCharacterRange(RenderSVGInlineText*, unsigned position, unsigned length); static TextRun constructTextRun(RenderSVGInlineText*, unsigned position, unsigned length); - bool isEmpty() const { return !m_width && !m_height && !m_glyph.isValid && m_length == 1; } + static SVGTextMetrics measureCharacterRange(RenderSVGInlineText*, unsigned position, unsigned length, TextDirection); + static TextRun constructTextRun(RenderSVGInlineText*, unsigned position, unsigned length, TextDirection); + + bool isEmpty() const { return !m_width && !m_height && m_length <= 1; } float width() const { return m_width; } void setWidth(float width) { m_width = width; } @@ -49,19 +54,8 @@ public: float height() const { return m_height; } unsigned length() const { return m_length; } - struct Glyph { - Glyph() - : isValid(false) - { - } - - bool isValid; - String name; - String unicodeString; - }; - // Only useful when measuring individual characters, to lookup ligatures. - const Glyph& glyph() const { return m_glyph; } + Glyph glyph() const { return m_glyph; } private: SVGTextMetrics(RenderSVGInlineText*, const TextRun&); diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextMetricsBuilder.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextMetricsBuilder.cpp index 46a27979e9d..eaaa9361d19 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextMetricsBuilder.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextMetricsBuilder.cpp @@ -21,186 +21,238 @@ #include "core/rendering/svg/SVGTextMetricsBuilder.h" +#include "core/rendering/svg/RenderSVGInline.h" #include "core/rendering/svg/RenderSVGInlineText.h" #include "core/rendering/svg/RenderSVGText.h" +#include "core/rendering/svg/SVGTextMetrics.h" +#include "platform/fonts/GlyphBuffer.h" +#include "platform/fonts/WidthIterator.h" +#include "platform/text/BidiCharacterRun.h" +#include "platform/text/BidiResolver.h" +#include "platform/text/TextDirection.h" +#include "platform/text/TextPath.h" +#include "platform/text/TextRun.h" +#include "platform/text/TextRunIterator.h" +#include "wtf/Vector.h" namespace WebCore { -SVGTextMetricsBuilder::SVGTextMetricsBuilder() - : m_text(0) - , m_run(static_cast<const UChar*>(0), 0) - , m_textPosition(0) +class SVGTextMetricsCalculator { +public: + SVGTextMetricsCalculator(RenderSVGInlineText*); + ~SVGTextMetricsCalculator(); + + SVGTextMetrics computeMetricsForCharacter(unsigned textPosition); + unsigned textLength() const { return static_cast<unsigned>(m_run.charactersLength()); } + + bool characterStartsSurrogatePair(unsigned textPosition) const + { + return U16_IS_LEAD(m_run[textPosition]) && textPosition + 1 < textLength() && U16_IS_TRAIL(m_run[textPosition + 1]); + } + bool characterIsWhiteSpace(unsigned textPosition) const + { + return m_run[textPosition] == ' '; + } + +private: + void setupBidiRuns(); + SVGTextMetrics computeMetricsForCharacterSimple(unsigned textPosition); + SVGTextMetrics computeMetricsForCharacterComplex(unsigned textPosition); + + RenderSVGInlineText* m_text; + BidiCharacterRun* m_bidiRun; + TextRun m_run; + BidiResolver<TextRunIterator, BidiCharacterRun> m_bidiResolver; + bool m_isComplexText; + float m_totalWidth; + TextDirection m_textDirection; + + // Simple text only. + OwnPtr<WidthIterator> m_simpleWidthIterator; +}; + +SVGTextMetricsCalculator::SVGTextMetricsCalculator(RenderSVGInlineText* text) + : m_text(text) + , m_bidiRun(0) + , m_run(SVGTextMetrics::constructTextRun(text, 0, text->textLength())) , m_isComplexText(false) , m_totalWidth(0) { + const Font& scaledFont = text->scaledFont(); + CodePath codePath = scaledFont.codePath(m_run); + m_isComplexText = codePath == ComplexPath; + m_run.setCharacterScanForCodePath(!m_isComplexText); + + if (!m_isComplexText) + m_simpleWidthIterator = adoptPtr(new WidthIterator(&scaledFont, m_run)); + else + setupBidiRuns(); } -inline bool SVGTextMetricsBuilder::currentCharacterStartsSurrogatePair() const +SVGTextMetricsCalculator::~SVGTextMetricsCalculator() { - return U16_IS_LEAD(m_run[m_textPosition]) && int(m_textPosition + 1) < m_run.charactersLength() && U16_IS_TRAIL(m_run[m_textPosition + 1]); + if (m_bidiRun) + m_bidiResolver.runs().deleteRuns(); } -bool SVGTextMetricsBuilder::advance() +void SVGTextMetricsCalculator::setupBidiRuns() { - m_textPosition += m_currentMetrics.length(); - if (int(m_textPosition) >= m_run.charactersLength()) - return false; - - if (m_isComplexText) - advanceComplexText(); - else - advanceSimpleText(); + RenderStyle* style = m_text->style(); + m_textDirection = style->direction(); + if (isOverride(style->unicodeBidi())) + return; - return m_currentMetrics.length() > 0; + BidiStatus status(LTR, false); + status.last = status.lastStrong = WTF::Unicode::OtherNeutral; + m_bidiResolver.setStatus(status); + m_bidiResolver.setPositionIgnoringNestedIsolates(TextRunIterator(&m_run, 0)); + const bool hardLineBreak = false; + const bool reorderRuns = false; + m_bidiResolver.createBidiRunsForLine(TextRunIterator(&m_run, m_run.length()), NoVisualOverride, hardLineBreak, reorderRuns); + BidiRunList<BidiCharacterRun>& bidiRuns = m_bidiResolver.runs(); + m_bidiRun = bidiRuns.firstRun(); } -void SVGTextMetricsBuilder::advanceSimpleText() +SVGTextMetrics SVGTextMetricsCalculator::computeMetricsForCharacterSimple(unsigned textPosition) { GlyphBuffer glyphBuffer; - unsigned metricsLength = m_simpleWidthIterator->advance(m_textPosition + 1, &glyphBuffer); - if (!metricsLength) { - m_currentMetrics = SVGTextMetrics(); - return; - } + unsigned metricsLength = m_simpleWidthIterator->advance(textPosition + 1, &glyphBuffer); + if (!metricsLength) + return SVGTextMetrics(); float currentWidth = m_simpleWidthIterator->runWidthSoFar() - m_totalWidth; m_totalWidth = m_simpleWidthIterator->runWidthSoFar(); -#if ENABLE(SVG_FONTS) - m_currentMetrics = SVGTextMetrics(m_text, m_textPosition, metricsLength, currentWidth, m_simpleWidthIterator->lastGlyphName()); -#else - m_currentMetrics = SVGTextMetrics(m_text, m_textPosition, metricsLength, currentWidth, emptyString()); -#endif + Glyph glyphId = glyphBuffer.glyphAt(0); + return SVGTextMetrics(m_text, textPosition, metricsLength, currentWidth, glyphId); } -void SVGTextMetricsBuilder::advanceComplexText() +SVGTextMetrics SVGTextMetricsCalculator::computeMetricsForCharacterComplex(unsigned textPosition) { - unsigned metricsLength = currentCharacterStartsSurrogatePair() ? 2 : 1; - m_currentMetrics = SVGTextMetrics::measureCharacterRange(m_text, m_textPosition, metricsLength); - m_complexStartToCurrentMetrics = SVGTextMetrics::measureCharacterRange(m_text, 0, m_textPosition + metricsLength); - ASSERT(m_currentMetrics.length() == metricsLength); + unsigned metricsLength = characterStartsSurrogatePair(textPosition) ? 2 : 1; + SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(m_text, textPosition, metricsLength, m_textDirection); + ASSERT(metrics.length() == metricsLength); + unsigned startPosition = m_bidiRun ? m_bidiRun->start() : 0; + ASSERT(startPosition <= textPosition); + SVGTextMetrics complexStartToCurrentMetrics = SVGTextMetrics::measureCharacterRange(m_text, startPosition, textPosition - startPosition + metricsLength, m_textDirection); // Frequent case for Arabic text: when measuring a single character the arabic isolated form is taken // when rendering the glyph "in context" (with it's surrounding characters) it changes due to shaping. // So whenever currentWidth != currentMetrics.width(), we are processing a text run whose length is // not equal to the sum of the individual lengths of the glyphs, when measuring them isolated. - float currentWidth = m_complexStartToCurrentMetrics.width() - m_totalWidth; - if (currentWidth != m_currentMetrics.width()) - m_currentMetrics.setWidth(currentWidth); + float currentWidth = complexStartToCurrentMetrics.width() - m_totalWidth; + if (currentWidth != metrics.width()) + metrics.setWidth(currentWidth); - m_totalWidth = m_complexStartToCurrentMetrics.width(); + m_totalWidth = complexStartToCurrentMetrics.width(); + return metrics; } -void SVGTextMetricsBuilder::initializeMeasurementWithTextRenderer(RenderSVGInlineText* text) +SVGTextMetrics SVGTextMetricsCalculator::computeMetricsForCharacter(unsigned textPosition) { - m_text = text; - m_textPosition = 0; - m_currentMetrics = SVGTextMetrics(); - m_complexStartToCurrentMetrics = SVGTextMetrics(); - m_totalWidth = 0; - - const Font& scaledFont = text->scaledFont(); - m_run = SVGTextMetrics::constructTextRun(text, 0, text->textLength()); - m_isComplexText = scaledFont.codePath(m_run) == Font::Complex; + if (m_bidiRun) { + if (textPosition >= static_cast<unsigned>(m_bidiRun->stop())) { + m_bidiRun = m_bidiRun->next(); + // New BiDi run means new reference position for measurements, so reset |m_totalWidth|. + m_totalWidth = 0; + } + ASSERT(m_bidiRun); + ASSERT(static_cast<int>(textPosition) < m_bidiRun->stop()); + m_textDirection = m_bidiRun->direction(); + } if (m_isComplexText) - m_simpleWidthIterator.clear(); - else - m_simpleWidthIterator = adoptPtr(new WidthIterator(&scaledFont, m_run)); + return computeMetricsForCharacterComplex(textPosition); + + return computeMetricsForCharacterSimple(textPosition); } struct MeasureTextData { MeasureTextData(SVGCharacterDataMap* characterDataMap) : allCharactersMap(characterDataMap) - , hasLastCharacter(false) - , lastCharacter(0) - , processRenderer(false) + , lastCharacterWasWhiteSpace(true) , valueListPosition(0) - , skippedCharacters(0) { } SVGCharacterDataMap* allCharactersMap; - bool hasLastCharacter; - UChar lastCharacter; - bool processRenderer; + bool lastCharacterWasWhiteSpace; unsigned valueListPosition; - unsigned skippedCharacters; }; -void SVGTextMetricsBuilder::measureTextRenderer(RenderSVGInlineText* text, MeasureTextData* data) +static void measureTextRenderer(RenderSVGInlineText* text, MeasureTextData* data, bool processRenderer) { ASSERT(text); SVGTextLayoutAttributes* attributes = text->layoutAttributes(); Vector<SVGTextMetrics>* textMetricsValues = &attributes->textMetricsValues(); - if (data->processRenderer) { + if (processRenderer) { if (data->allCharactersMap) attributes->clear(); else textMetricsValues->clear(); } - initializeMeasurementWithTextRenderer(text); + SVGTextMetricsCalculator calculator(text); bool preserveWhiteSpace = text->style()->whiteSpace() == PRE; - int surrogatePairCharacters = 0; - - while (advance()) { - UChar currentCharacter = m_run[m_textPosition]; - if (currentCharacter == ' ' && !preserveWhiteSpace && (!data->hasLastCharacter || data->lastCharacter == ' ')) { - if (data->processRenderer) + unsigned surrogatePairCharacters = 0; + unsigned skippedCharacters = 0; + unsigned textPosition = 0; + unsigned textLength = calculator.textLength(); + + SVGTextMetrics currentMetrics; + for (; textPosition < textLength; textPosition += currentMetrics.length()) { + currentMetrics = calculator.computeMetricsForCharacter(textPosition); + if (!currentMetrics.length()) + break; + + bool characterIsWhiteSpace = calculator.characterIsWhiteSpace(textPosition); + if (characterIsWhiteSpace && !preserveWhiteSpace && data->lastCharacterWasWhiteSpace) { + if (processRenderer) textMetricsValues->append(SVGTextMetrics(SVGTextMetrics::SkippedSpaceMetrics)); if (data->allCharactersMap) - data->skippedCharacters += m_currentMetrics.length(); + skippedCharacters += currentMetrics.length(); continue; } - if (data->processRenderer) { + if (processRenderer) { if (data->allCharactersMap) { - const SVGCharacterDataMap::const_iterator it = data->allCharactersMap->find(data->valueListPosition + m_textPosition - data->skippedCharacters - surrogatePairCharacters + 1); + const SVGCharacterDataMap::const_iterator it = data->allCharactersMap->find(data->valueListPosition + textPosition - skippedCharacters - surrogatePairCharacters + 1); if (it != data->allCharactersMap->end()) - attributes->characterDataMap().set(m_textPosition + 1, it->value); + attributes->characterDataMap().set(textPosition + 1, it->value); } - textMetricsValues->append(m_currentMetrics); + textMetricsValues->append(currentMetrics); } - if (data->allCharactersMap && currentCharacterStartsSurrogatePair()) + if (data->allCharactersMap && calculator.characterStartsSurrogatePair(textPosition)) surrogatePairCharacters++; - data->hasLastCharacter = true; - data->lastCharacter = currentCharacter; + data->lastCharacterWasWhiteSpace = characterIsWhiteSpace; } if (!data->allCharactersMap) return; - data->valueListPosition += m_textPosition - data->skippedCharacters; - data->skippedCharacters = 0; + data->valueListPosition += textPosition - skippedCharacters; } -void SVGTextMetricsBuilder::walkTree(RenderObject* start, RenderSVGInlineText* stopAtLeaf, MeasureTextData* data) +static void walkTree(RenderSVGText* start, RenderSVGInlineText* stopAtLeaf, MeasureTextData* data) { - for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) { + RenderObject* child = start->firstChild(); + while (child) { if (child->isSVGInlineText()) { RenderSVGInlineText* text = toRenderSVGInlineText(child); - if (stopAtLeaf && stopAtLeaf != text) { - data->processRenderer = false; - measureTextRenderer(text, data); + measureTextRenderer(text, data, !stopAtLeaf || stopAtLeaf == text); + if (stopAtLeaf && stopAtLeaf == text) + return; + } else if (child->isSVGInline()) { + // Visit children of text content elements. + if (RenderObject* inlineChild = toRenderSVGInline(child)->firstChild()) { + child = inlineChild; continue; } - - data->processRenderer = true; - measureTextRenderer(text, data); - if (stopAtLeaf) - return; - - continue; } - - if (!child->isSVGInline()) - continue; - - walkTree(child, stopAtLeaf, data); + child = child->nextInPreOrderAfterChildren(start); } } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextMetricsBuilder.h b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextMetricsBuilder.h index 076b052283a..bf0c5c77095 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextMetricsBuilder.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextMetricsBuilder.h @@ -21,48 +21,18 @@ #define SVGTextMetricsBuilder_h #include "core/rendering/svg/SVGTextLayoutAttributes.h" -#include "core/rendering/svg/SVGTextMetrics.h" -#include "platform/fonts/WidthIterator.h" -#include "platform/text/TextRun.h" -#include "wtf/Vector.h" namespace WebCore { -class RenderObject; class RenderSVGInlineText; class RenderSVGText; -struct MeasureTextData; -class SVGTextMetricsBuilder { - WTF_MAKE_NONCOPYABLE(SVGTextMetricsBuilder); -public: - SVGTextMetricsBuilder(); - void measureTextRenderer(RenderSVGInlineText*); - void buildMetricsAndLayoutAttributes(RenderSVGText*, RenderSVGInlineText* stopAtLeaf, SVGCharacterDataMap& allCharactersMap); +namespace SVGTextMetricsBuilder { -private: - bool advance(); - void advanceSimpleText(); - void advanceComplexText(); - bool currentCharacterStartsSurrogatePair() const; +void measureTextRenderer(RenderSVGInlineText*); +void buildMetricsAndLayoutAttributes(RenderSVGText*, RenderSVGInlineText* stopAtLeaf, SVGCharacterDataMap& allCharactersMap); - void initializeMeasurementWithTextRenderer(RenderSVGInlineText*); - void walkTree(RenderObject*, RenderSVGInlineText* stopAtLeaf, MeasureTextData*); - void measureTextRenderer(RenderSVGInlineText*, MeasureTextData*); - - RenderSVGInlineText* m_text; - TextRun m_run; - unsigned m_textPosition; - bool m_isComplexText; - SVGTextMetrics m_currentMetrics; - float m_totalWidth; - - // Simple text only. - OwnPtr<WidthIterator> m_simpleWidthIterator; - - // Complex text only. - SVGTextMetrics m_complexStartToCurrentMetrics; -}; +} // namespace SVGTextMetricsBuilder } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextQuery.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextQuery.cpp index 4bf2a3c3da7..f5ead0d4366 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextQuery.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextQuery.cpp @@ -90,7 +90,7 @@ void SVGTextQuery::collectTextBoxesInFlowBox(InlineFlowBox* flowBox) for (InlineBox* child = flowBox->firstChild(); child; child = child->nextOnLine()) { if (child->isInlineFlowBox()) { // Skip generated content. - if (!child->renderer()->node()) + if (!child->renderer().node()) continue; collectTextBoxesInFlowBox(toInlineFlowBox(child)); @@ -112,8 +112,7 @@ bool SVGTextQuery::executeQuery(Data* queryData, ProcessTextFragmentCallback fra // Loop over all text boxes for (unsigned textBoxPosition = 0; textBoxPosition < textBoxCount; ++textBoxPosition) { queryData->textBox = m_textBoxes.at(textBoxPosition); - queryData->textRenderer = toRenderSVGInlineText(queryData->textBox->textRenderer()); - ASSERT(queryData->textRenderer); + queryData->textRenderer = &toRenderSVGInlineText(queryData->textBox->textRenderer()); ASSERT(queryData->textRenderer->style()); ASSERT(queryData->textRenderer->style()->svgStyle()); @@ -142,7 +141,9 @@ bool SVGTextQuery::mapStartEndPositionsIntoFragmentCoordinates(Data* queryData, startPosition -= queryData->processedCharacters; endPosition -= queryData->processedCharacters; - if (startPosition >= endPosition || startPosition < 0 || endPosition < 0) + startPosition = max(0, startPosition); + + if (startPosition >= endPosition) return false; modifyStartEndPositionsRespectingLigatures(queryData, startPosition, endPosition); @@ -215,15 +216,11 @@ void SVGTextQuery::modifyStartEndPositionsRespectingLigatures(Data* queryData, i return; if (lastPositionOffset != -1 && lastPositionOffset - positionOffset > 1) { - if (alterStartPosition && startPosition > lastPositionOffset && startPosition < static_cast<int>(positionOffset)) { + if (alterStartPosition && startPosition > lastPositionOffset && startPosition < static_cast<int>(positionOffset)) startPosition = lastPositionOffset; - alterStartPosition = false; - } - if (alterEndPosition && endPosition > lastPositionOffset && endPosition < static_cast<int>(positionOffset)) { + if (alterEndPosition && endPosition > lastPositionOffset && endPosition < static_cast<int>(positionOffset)) endPosition = positionOffset; - alterEndPosition = false; - } } } @@ -480,8 +477,6 @@ static inline void calculateGlyphBoundaries(SVGTextQuery::Data* queryData, const AffineTransform fragmentTransform; fragment.buildFragmentTransform(fragmentTransform, SVGTextFragment::TransformIgnoringTextLength); - if (fragmentTransform.isIdentity()) - return; extent = fragmentTransform.mapRect(extent); } @@ -499,10 +494,10 @@ bool SVGTextQuery::extentOfCharacterCallback(Data* queryData, const SVGTextFragm return true; } -SVGRect SVGTextQuery::extentOfCharacter(unsigned position) const +FloatRect SVGTextQuery::extentOfCharacter(unsigned position) const { if (m_textBoxes.isEmpty()) - return SVGRect(); + return FloatRect(); ExtentOfCharacterData data(position); executeQuery(&data, &SVGTextQuery::extentOfCharacterCallback); @@ -540,7 +535,7 @@ bool SVGTextQuery::characterNumberAtPositionCallback(Data* queryData, const SVGT return false; } -int SVGTextQuery::characterNumberAtPosition(const SVGPoint& position) const +int SVGTextQuery::characterNumberAtPosition(const FloatPoint& position) const { if (m_textBoxes.isEmpty()) return -1; diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextQuery.h b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextQuery.h index 652d751af70..a5601f74d30 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextQuery.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextQuery.h @@ -21,8 +21,8 @@ #define SVGTextQuery_h #include "core/rendering/svg/SVGTextFragment.h" -#include "core/svg/SVGPoint.h" -#include "core/svg/SVGRect.h" +#include "platform/geometry/FloatPoint.h" +#include "platform/geometry/FloatRect.h" #include "wtf/Vector.h" namespace WebCore { @@ -41,8 +41,8 @@ public: FloatPoint startPositionOfCharacter(unsigned position) const; FloatPoint endPositionOfCharacter(unsigned position) const; float rotationOfCharacter(unsigned position) const; - SVGRect extentOfCharacter(unsigned position) const; - int characterNumberAtPosition(const SVGPoint&) const; + FloatRect extentOfCharacter(unsigned position) const; + int characterNumberAtPosition(const FloatPoint&) const; // Public helper struct. Private classes in SVGTextQuery inherit from it. struct Data; diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextRunRenderingContext.cpp b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextRunRenderingContext.cpp index c48c91e2486..7765117cd28 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextRunRenderingContext.cpp +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextRunRenderingContext.cpp @@ -23,7 +23,6 @@ #if ENABLE(SVG_FONTS) #include "core/rendering/svg/SVGTextRunRenderingContext.h" -#include "SVGNames.h" #include "core/rendering/RenderObject.h" #include "core/rendering/svg/RenderSVGInlineText.h" #include "core/rendering/svg/RenderSVGResourceSolidColor.h" @@ -46,6 +45,10 @@ static inline const SVGFontData* svgFontAndFontFaceElementForFontData(const Simp RefPtr<CustomFontData> customFontData = fontData->customFontData(); const SVGFontData* svgFontData = static_cast<const SVGFontData*>(customFontData.get()); + // FIXME crbug.com/359380 : The current editing impl references the font after the svg font nodes are removed. + if (svgFontData->shouldSkipDrawing()) + return 0; + fontFace = svgFontData->svgFontFaceElement(); ASSERT(fontFace); @@ -73,12 +76,12 @@ static inline RenderSVGResource* activePaintingResourceFromRun(const TextRun& ru return 0; } -float SVGTextRunRenderingContext::floatWidthUsingSVGFont(const Font& font, const TextRun& run, int& charsConsumed, String& glyphName) const +float SVGTextRunRenderingContext::floatWidthUsingSVGFont(const Font& font, const TextRun& run, int& charsConsumed, Glyph& glyphId) const { WidthIterator it(&font, run); GlyphBuffer glyphBuffer; charsConsumed += it.advance(run.length(), &glyphBuffer); - glyphName = it.lastGlyphName(); + glyphId = !glyphBuffer.isEmpty() ? glyphBuffer.glyphAt(0) : 0; return it.runWidthSoFar(); } @@ -119,14 +122,17 @@ void SVGTextRunRenderingContext::drawSVGGlyphs(GraphicsContext* context, const T glyphOrigin.setX(svgFontData->horizontalOriginX() * scale); glyphOrigin.setY(svgFontData->horizontalOriginY() * scale); + unsigned short resourceMode = context->textDrawingMode() == TextModeStroke ? ApplyToStrokeMode : ApplyToFillMode; + // From a resource perspective this ought to be treated as "text mode". + resourceMode |= ApplyToTextMode; + FloatPoint currentPoint = point; - RenderSVGResourceMode resourceMode = context->textDrawingMode() == TextModeStroke ? ApplyToStrokeMode : ApplyToFillMode; for (int i = 0; i < numGlyphs; ++i) { Glyph glyph = glyphBuffer.glyphAt(from + i); if (!glyph) continue; - float advance = glyphBuffer.advanceAt(from + i); + float advance = glyphBuffer.advanceAt(from + i).width(); SVGGlyph svgGlyph = fontElement->svgGlyphForGlyph(glyph); ASSERT(!svgGlyph.isPartOfLigature); ASSERT(svgGlyph.tableEntry == glyph); @@ -198,7 +204,7 @@ GlyphData SVGTextRunRenderingContext::glyphDataForCharacter(const Font& font, co RenderObject* parentRenderObject = renderObject->isText() ? renderObject->parent() : renderObject; ASSERT(parentRenderObject); if (Element* parentRenderObjectElement = toElement(parentRenderObject->node())) { - if (parentRenderObjectElement->hasTagName(SVGNames::altGlyphTag)) + if (isSVGAltGlyphElement(*parentRenderObjectElement)) glyphData.fontData = primaryFont; } } diff --git a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextRunRenderingContext.h b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextRunRenderingContext.h index e71eca2ca29..382c51feb50 100644 --- a/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextRunRenderingContext.h +++ b/chromium/third_party/WebKit/Source/core/rendering/svg/SVGTextRunRenderingContext.h @@ -29,7 +29,7 @@ namespace WebCore { class RenderObject; class RenderSVGResource; -class SVGTextRunRenderingContext : public TextRun::RenderingContext { +class SVGTextRunRenderingContext FINAL : public TextRun::RenderingContext { public: static PassRefPtr<SVGTextRunRenderingContext> create(RenderObject* renderer) { @@ -42,9 +42,13 @@ public: RenderSVGResource* activePaintingResource() const { return m_activePaintingResource; } void setActivePaintingResource(RenderSVGResource* object) { m_activePaintingResource = object; } - virtual GlyphData glyphDataForCharacter(const Font&, const TextRun&, WidthIterator&, UChar32 character, bool mirror, int currentCharacter, unsigned& advanceLength); - virtual void drawSVGGlyphs(GraphicsContext*, const TextRun&, const SimpleFontData*, const GlyphBuffer&, int from, int to, const FloatPoint&) const; - virtual float floatWidthUsingSVGFont(const Font&, const TextRun&, int& charsConsumed, String& glyphName) const; + virtual GlyphData glyphDataForCharacter(const Font&, const TextRun&, WidthIterator&, UChar32 character, bool mirror, int currentCharacter, unsigned& advanceLength) OVERRIDE; + virtual void drawSVGGlyphs(GraphicsContext*, const TextRun&, const SimpleFontData*, const GlyphBuffer&, int from, int to, const FloatPoint&) const OVERRIDE; + virtual float floatWidthUsingSVGFont(const Font&, const TextRun&, int& charsConsumed, Glyph& glyphId) const OVERRIDE; +#else + virtual GlyphData glyphDataForCharacter(const Font&, const TextRun&, WidthIterator&, UChar32 character, bool mirror, int currentCharacter, unsigned& advanceLength) OVERRIDE { return 0; } + virtual void drawSVGGlyphs(GraphicsContext*, const TextRun&, const SimpleFontData*, const GlyphBuffer&, int from, int to, const FloatPoint&) const OVERRIDE { } + virtual float floatWidthUsingSVGFont(const Font&, const TextRun&, int& charsConsumed, Glyph& glyphId) const OVERRIDE { return 0; } #endif private: |