| Index: Source/core/paint/SVGShapePainter.cpp
|
| diff --git a/Source/core/paint/SVGShapePainter.cpp b/Source/core/paint/SVGShapePainter.cpp
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..0456a2a8cb44af53492db7145b1858714ef536a7
|
| --- /dev/null
|
| +++ b/Source/core/paint/SVGShapePainter.cpp
|
| @@ -0,0 +1,204 @@
|
| +// Copyright 2014 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "config.h"
|
| +#include "core/paint/SVGShapePainter.h"
|
| +
|
| +#include "core/paint/ObjectPainter.h"
|
| +#include "core/paint/SVGMarkerPainter.h"
|
| +#include "core/rendering/GraphicsContextAnnotator.h"
|
| +#include "core/rendering/PaintInfo.h"
|
| +#include "core/rendering/svg/RenderSVGPath.h"
|
| +#include "core/rendering/svg/RenderSVGShape.h"
|
| +#include "core/rendering/svg/SVGMarkerData.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"
|
| +
|
| +namespace blink {
|
| +
|
| +static bool setupNonScalingStrokeContext(AffineTransform& strokeTransform, GraphicsContextStateSaver& stateSaver)
|
| +{
|
| + if (!strokeTransform.isInvertible())
|
| + return false;
|
| +
|
| + stateSaver.save();
|
| + stateSaver.context()->concatCTM(strokeTransform.inverse());
|
| + return true;
|
| +}
|
| +
|
| +static void useStrokeStyleToFill(GraphicsContext* context)
|
| +{
|
| + if (Gradient* gradient = context->strokeGradient())
|
| + context->setFillGradient(gradient);
|
| + else if (Pattern* pattern = context->strokePattern())
|
| + context->setFillPattern(pattern);
|
| + else
|
| + context->setFillColor(context->strokeColor());
|
| +}
|
| +
|
| +void SVGShapePainter::paint(PaintInfo& paintInfo)
|
| +{
|
| + ANNOTATE_GRAPHICS_CONTEXT(paintInfo, &m_renderSVGShape);
|
| + if (paintInfo.phase != PaintPhaseForeground
|
| + || m_renderSVGShape.style()->visibility() == HIDDEN
|
| + || m_renderSVGShape.isShapeEmpty())
|
| + return;
|
| +
|
| + FloatRect boundingBox = m_renderSVGShape.paintInvalidationRectInLocalCoordinates();
|
| + if (!SVGRenderSupport::paintInfoIntersectsPaintInvalidationRect(boundingBox, m_renderSVGShape.localTransform(), paintInfo))
|
| + return;
|
| +
|
| + PaintInfo childPaintInfo(paintInfo);
|
| +
|
| + GraphicsContextStateSaver stateSaver(*childPaintInfo.context);
|
| + childPaintInfo.applyTransform(m_renderSVGShape.localTransform());
|
| +
|
| + SVGRenderingContext renderingContext(&m_renderSVGShape, childPaintInfo);
|
| +
|
| + if (renderingContext.isRenderingPrepared()) {
|
| + const SVGRenderStyle& svgStyle = m_renderSVGShape.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: {
|
| + GraphicsContextStateSaver stateSaver(*childPaintInfo.context, false);
|
| + if (!SVGRenderSupport::updateGraphicsContext(stateSaver, m_renderSVGShape.style(), m_renderSVGShape, ApplyToFillMode))
|
| + break;
|
| + fillShape(childPaintInfo.context);
|
| + break;
|
| + }
|
| + case PT_STROKE:
|
| + if (svgStyle.hasVisibleStroke()) {
|
| + GraphicsContextStateSaver stateSaver(*childPaintInfo.context, false);
|
| + AffineTransform nonScalingTransform;
|
| + const AffineTransform* additionalPaintServerTransform = 0;
|
| +
|
| + if (m_renderSVGShape.hasNonScalingStroke()) {
|
| + nonScalingTransform = m_renderSVGShape.nonScalingStrokeTransform();
|
| + if (!setupNonScalingStrokeContext(nonScalingTransform, stateSaver))
|
| + return;
|
| +
|
| + // Non-scaling stroke needs to reset the transform back to the host transform.
|
| + additionalPaintServerTransform = &nonScalingTransform;
|
| + }
|
| +
|
| + if (!SVGRenderSupport::updateGraphicsContext(stateSaver, m_renderSVGShape.style(), m_renderSVGShape, ApplyToStrokeMode, additionalPaintServerTransform))
|
| + break;
|
| + strokeShape(childPaintInfo.context);
|
| + }
|
| + break;
|
| + case PT_MARKERS:
|
| + paintMarkers(childPaintInfo);
|
| + break;
|
| + default:
|
| + ASSERT_NOT_REACHED();
|
| + break;
|
| + }
|
| + }
|
| + }
|
| +
|
| + if (m_renderSVGShape.style()->outlineWidth())
|
| + ObjectPainter(m_renderSVGShape).paintOutline(childPaintInfo, IntRect(boundingBox));
|
| +}
|
| +
|
| +void SVGShapePainter::fillShape(GraphicsContext* context)
|
| +{
|
| + switch (m_renderSVGShape.geometryCodePath()) {
|
| + case RectGeometryFastPath:
|
| + context->fillRect(m_renderSVGShape.objectBoundingBox());
|
| + break;
|
| + case EllipseGeometryFastPath:
|
| + context->fillEllipse(m_renderSVGShape.objectBoundingBox());
|
| + break;
|
| + default:
|
| + context->fillPath(m_renderSVGShape.path());
|
| + }
|
| +}
|
| +
|
| +void SVGShapePainter::strokeShape(GraphicsContext* context)
|
| +{
|
| + if (!m_renderSVGShape.style()->svgStyle().hasVisibleStroke())
|
| + return;
|
| +
|
| + switch (m_renderSVGShape.geometryCodePath()) {
|
| + case RectGeometryFastPath:
|
| + context->strokeRect(m_renderSVGShape.objectBoundingBox(), m_renderSVGShape.strokeWidth());
|
| + break;
|
| + case EllipseGeometryFastPath:
|
| + context->strokeEllipse(m_renderSVGShape.objectBoundingBox());
|
| + break;
|
| + default:
|
| + ASSERT(m_renderSVGShape.hasPath());
|
| + Path* usePath = &m_renderSVGShape.path();
|
| + if (m_renderSVGShape.hasNonScalingStroke())
|
| + usePath = m_renderSVGShape.nonScalingStrokePath(usePath, m_renderSVGShape.nonScalingStrokeTransform());
|
| + context->strokePath(*usePath);
|
| + strokeZeroLengthLineCaps(context);
|
| + }
|
| +}
|
| +
|
| +void SVGShapePainter::paintMarkers(PaintInfo& paintInfo)
|
| +{
|
| + const Vector<MarkerPosition>* markerPositions = m_renderSVGShape.markerPositions();
|
| + if (!markerPositions || markerPositions->isEmpty())
|
| + return;
|
| +
|
| + SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(&m_renderSVGShape);
|
| + if (!resources)
|
| + return;
|
| +
|
| + RenderSVGResourceMarker* markerStart = resources->markerStart();
|
| + RenderSVGResourceMarker* markerMid = resources->markerMid();
|
| + RenderSVGResourceMarker* markerEnd = resources->markerEnd();
|
| + if (!markerStart && !markerMid && !markerEnd)
|
| + return;
|
| +
|
| + float strokeWidth = m_renderSVGShape.strokeWidth();
|
| + unsigned size = markerPositions->size();
|
| + for (unsigned i = 0; i < size; ++i) {
|
| + if (RenderSVGResourceMarker* marker = SVGMarkerData::markerForType((*markerPositions)[i].type, markerStart, markerMid, markerEnd))
|
| + SVGMarkerPainter(*marker).paint(paintInfo, (*markerPositions)[i], strokeWidth);
|
| + }
|
| +}
|
| +
|
| +void SVGShapePainter::strokeZeroLengthLineCaps(GraphicsContext* context)
|
| +{
|
| + const Vector<FloatPoint>* zeroLengthLineCaps = m_renderSVGShape.zeroLengthLineCaps();
|
| + if (!zeroLengthLineCaps || zeroLengthLineCaps->isEmpty())
|
| + return;
|
| +
|
| + Path* usePath;
|
| + AffineTransform nonScalingTransform;
|
| +
|
| + if (m_renderSVGShape.hasNonScalingStroke())
|
| + nonScalingTransform = m_renderSVGShape.nonScalingStrokeTransform();
|
| +
|
| + GraphicsContextStateSaver stateSaver(*context, true);
|
| + useStrokeStyleToFill(context);
|
| + for (size_t i = 0; i < zeroLengthLineCaps->size(); ++i) {
|
| + usePath = zeroLengthLinecapPath((*zeroLengthLineCaps)[i]);
|
| + if (m_renderSVGShape.hasNonScalingStroke())
|
| + usePath = m_renderSVGShape.nonScalingStrokePath(usePath, nonScalingTransform);
|
| + context->fillPath(*usePath);
|
| + }
|
| +}
|
| +
|
| +Path* SVGShapePainter::zeroLengthLinecapPath(const FloatPoint& linecapPosition) const
|
| +{
|
| + DEFINE_STATIC_LOCAL(Path, tempPath, ());
|
| +
|
| + tempPath.clear();
|
| + if (m_renderSVGShape.style()->svgStyle().capStyle() == SquareCap)
|
| + tempPath.addRect(RenderSVGPath::zeroLengthSubpathRect(linecapPosition, m_renderSVGShape.strokeWidth()));
|
| + else
|
| + tempPath.addEllipse(RenderSVGPath::zeroLengthSubpathRect(linecapPosition, m_renderSVGShape.strokeWidth()));
|
| +
|
| + return &tempPath;
|
| +}
|
| +
|
| +} // namespace blink
|
|
|