nsresult
nsSVGMarkerFrame::PaintMark(gfxContext& aContext,
                            const gfxMatrix& aToMarkedFrameUserSpace,
                            nsSVGPathGeometryFrame *aMarkedFrame,
                            nsSVGMark *aMark, float aStrokeWidth)
{
  // If the flag is set when we get here, it means this marker frame
  // has already been used painting the current mark, and the document
  // has a marker reference loop.
  if (mInUse)
    return NS_OK;

  AutoMarkerReferencer markerRef(this, aMarkedFrame);

  SVGMarkerElement *marker = static_cast<SVGMarkerElement*>(mContent);
  if (!marker->HasValidDimensions()) {
    return NS_OK;
  }

  const nsSVGViewBoxRect viewBox = marker->GetViewBoxRect();

  if (viewBox.width <= 0.0f || viewBox.height <= 0.0f) {
    // We must disable rendering if the viewBox width or height are zero.
    return NS_OK;
  }

  mStrokeWidth = aStrokeWidth;
  mX = aMark->x;
  mY = aMark->y;
  mAutoAngle = aMark->angle;
  mIsStart = aMark->type == nsSVGMark::eStart;

  Matrix viewBoxTM = marker->GetViewBoxTransform();

  Matrix markerTM = marker->GetMarkerTransform(mStrokeWidth, mX, mY,
                                               mAutoAngle, mIsStart);

  gfxMatrix markTM = ThebesMatrix(viewBoxTM) * ThebesMatrix(markerTM) *
                     aToMarkedFrameUserSpace;

  if (StyleDisplay()->IsScrollableOverflow()) {
    aContext.Save();
    gfxRect clipRect =
      nsSVGUtils::GetClipRectForFrame(this, viewBox.x, viewBox.y,
                                      viewBox.width, viewBox.height);
    nsSVGUtils::SetClipRect(&aContext, markTM, clipRect);
  }


  nsIFrame* kid = GetAnonymousChildFrame(this);
  nsISVGChildFrame* SVGFrame = do_QueryFrame(kid);
  // The CTM of each frame referencing us may be different.
  SVGFrame->NotifySVGChanged(nsISVGChildFrame::TRANSFORM_CHANGED);
  nsSVGUtils::PaintFrameWithEffects(kid, aContext, markTM);

  if (StyleDisplay()->IsScrollableOverflow())
    aContext.Restore();

  return NS_OK;
}
SVGBBox
nsSVGMarkerFrame::GetMarkBBoxContribution(const Matrix &aToBBoxUserspace,
                                          uint32_t aFlags,
                                          nsSVGPathGeometryFrame *aMarkedFrame,
                                          const nsSVGMark *aMark,
                                          float aStrokeWidth)
{
  SVGBBox bbox;

  // If the flag is set when we get here, it means this marker frame
  // has already been used in calculating the current mark bbox, and
  // the document has a marker reference loop.
  if (mInUse)
    return bbox;

  AutoMarkerReferencer markerRef(this, aMarkedFrame);

  SVGMarkerElement *content = static_cast<SVGMarkerElement*>(mContent);
  if (!content->HasValidDimensions()) {
    return bbox;
  }

  const nsSVGViewBoxRect viewBox = content->GetViewBoxRect();

  if (viewBox.width <= 0.0f || viewBox.height <= 0.0f) {
    return bbox;
  }

  mStrokeWidth = aStrokeWidth;
  mX = aMark->x;
  mY = aMark->y;
  mAutoAngle = aMark->angle;
  mIsStart = aMark->type == nsSVGMark::eStart;

  Matrix markerTM =
    content->GetMarkerTransform(mStrokeWidth, mX, mY, mAutoAngle, mIsStart);
  Matrix viewBoxTM = content->GetViewBoxTransform();

  Matrix tm = viewBoxTM * markerTM * aToBBoxUserspace;

  nsISVGChildFrame* child = do_QueryFrame(GetAnonymousChildFrame(this));
  // When we're being called to obtain the invalidation area, we need to
  // pass down all the flags so that stroke is included. However, once DOM
  // getBBox() accepts flags, maybe we should strip some of those here?

  // We need to include zero width/height vertical/horizontal lines, so we have
  // to use UnionEdges.
  bbox.UnionEdges(child->GetBBoxContribution(tm, aFlags));

  return bbox;
}