/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Mozilla SVG project. * * The Initial Developer of the Original Code is * Crocodile Clips Ltd.. * Portions created by the Initial Developer are Copyright (C) 2001 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Alex Fritze (original author) * Daniele Nicolodi * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include #include "nsSVGPathGeometryFrame.h" #include "nsIDOMSVGAnimatedPathData.h" #include "nsIDOMSVGPathSegList.h" #include "nsIDOMSVGPathSeg.h" #include "nsIDOMSVGMatrix.h" #include "nsISVGRendererPathBuilder.h" #include "nsISVGMarkable.h" #include "nsSVGMarkerFrame.h" #include "nsISupports.h" #include "nsLayoutAtoms.h" class nsSVGPathFrame : public nsSVGPathGeometryFrame, public nsISVGMarkable { protected: friend nsresult NS_NewSVGPathFrame(nsIPresShell* aPresShell, nsIContent* aContent, nsIFrame** aNewFrame); ~nsSVGPathFrame(); NS_IMETHOD InitSVG(); public: // nsISVGValueObserver interface: NS_IMETHOD DidModifySVGObservable(nsISVGValue* observable, nsISVGValue::modificationType aModType); // nsISVGPathGeometrySource interface: NS_IMETHOD ConstructPath(nsISVGRendererPathBuilder *pathBuilder); // nsISVGMarkable interface void GetMarkPoints(nsVoidArray *aMarks); // nsISupports interface: NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr); /** * Get the "type" of the frame * * @see nsLayoutAtoms::svgPathFrame */ virtual nsIAtom* GetType() const; #ifdef DEBUG NS_IMETHOD GetFrameName(nsAString& aResult) const { return MakeFrameName(NS_LITERAL_STRING("SVGPath"), aResult); } #endif private: NS_IMETHOD_(nsrefcnt) AddRef() { return NS_OK; } NS_IMETHOD_(nsrefcnt) Release() { return NS_OK; } nsCOMPtr mSegments; }; NS_INTERFACE_MAP_BEGIN(nsSVGPathFrame) NS_INTERFACE_MAP_ENTRY(nsISVGMarkable) NS_INTERFACE_MAP_END_INHERITING(nsSVGPathGeometryFrame) //---------------------------------------------------------------------- // Implementation nsresult NS_NewSVGPathFrame(nsIPresShell* aPresShell, nsIContent* aContent, nsIFrame** aNewFrame) { *aNewFrame = nsnull; nsCOMPtr anim_data = do_QueryInterface(aContent); if (!anim_data) { #ifdef DEBUG printf("warning: trying to construct an SVGPathFrame for a content element that doesn't support the right interfaces\n"); #endif return NS_ERROR_FAILURE; } nsSVGPathFrame* it = new (aPresShell) nsSVGPathFrame; if (nsnull == it) return NS_ERROR_OUT_OF_MEMORY; *aNewFrame = it; return NS_OK; } nsSVGPathFrame::~nsSVGPathFrame() { nsCOMPtr value; if (mSegments && (value = do_QueryInterface(mSegments))) value->RemoveObserver(this); } NS_IMETHODIMP nsSVGPathFrame::InitSVG() { nsresult rv = nsSVGPathGeometryFrame::InitSVG(); if (NS_FAILED(rv)) return rv; nsCOMPtr anim_data = do_QueryInterface(mContent); NS_ASSERTION(anim_data,"wrong content element"); anim_data->GetAnimatedPathSegList(getter_AddRefs(mSegments)); NS_ASSERTION(mSegments, "no pathseglist"); if (!mSegments) return NS_ERROR_FAILURE; nsCOMPtr value = do_QueryInterface(mSegments); if (value) value->AddObserver(this); return NS_OK; } //---------------------------------------------------------------------- // nsISVGValueObserver methods: NS_IMETHODIMP nsSVGPathFrame::DidModifySVGObservable(nsISVGValue* observable, nsISVGValue::modificationType aModType) { nsCOMPtr l = do_QueryInterface(observable); if (l && mSegments==l) { UpdateGraphic(nsISVGPathGeometrySource::UPDATEMASK_PATH); return NS_OK; } // else return nsSVGPathGeometryFrame::DidModifySVGObservable(observable, aModType); } //---------------------------------------------------------------------- // nsISVGPathGeometrySource methods: /* void constructPath (in nsISVGRendererPathBuilder pathBuilder); */ NS_IMETHODIMP nsSVGPathFrame::ConstructPath(nsISVGRendererPathBuilder* pathBuilder) { PRUint32 count; mSegments->GetNumberOfItems(&count); if (count == 0) return NS_OK; float cx = 0.0f; // current point float cy = 0.0f; float cx1 = 0.0f; // last controlpoint (for s,S,t,T) float cy1 = 0.0f; PRUint16 lastSegmentType = nsIDOMSVGPathSeg::PATHSEG_UNKNOWN; PRUint32 i; for (i = 0; i < count; ++i) { nsCOMPtr segment; mSegments->GetItem(i, getter_AddRefs(segment)); PRUint16 type = nsIDOMSVGPathSeg::PATHSEG_UNKNOWN; segment->GetPathSegType(&type); PRBool absCoords = PR_FALSE; switch (type) { case nsIDOMSVGPathSeg::PATHSEG_CLOSEPATH: pathBuilder->ClosePath(&cx,&cy); break; case nsIDOMSVGPathSeg::PATHSEG_MOVETO_ABS: absCoords = PR_TRUE; case nsIDOMSVGPathSeg::PATHSEG_MOVETO_REL: { float x, y; if (!absCoords) { nsCOMPtr moveseg = do_QueryInterface(segment); NS_ASSERTION(moveseg, "interface not implemented"); moveseg->GetX(&x); moveseg->GetY(&y); x += cx; y += cy; } else { nsCOMPtr moveseg = do_QueryInterface(segment); NS_ASSERTION(moveseg, "interface not implemented"); moveseg->GetX(&x); moveseg->GetY(&y); } cx = x; cy = y; pathBuilder->Moveto(x,y); } break; case nsIDOMSVGPathSeg::PATHSEG_LINETO_ABS: absCoords = PR_TRUE; case nsIDOMSVGPathSeg::PATHSEG_LINETO_REL: { float x, y; if (!absCoords) { nsCOMPtr lineseg = do_QueryInterface(segment); NS_ASSERTION(lineseg, "interface not implemented"); lineseg->GetX(&x); lineseg->GetY(&y); x += cx; y += cy; } else { nsCOMPtr lineseg = do_QueryInterface(segment); NS_ASSERTION(lineseg, "interface not implemented"); lineseg->GetX(&x); lineseg->GetY(&y); } cx = x; cy = y; pathBuilder->Lineto(x,y); } break; case nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_ABS: absCoords = PR_TRUE; case nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_REL: { float x, y, x1, y1, x2, y2; if (!absCoords) { nsCOMPtr curveseg = do_QueryInterface(segment); NS_ASSERTION(curveseg, "interface not implemented"); curveseg->GetX(&x); curveseg->GetY(&y); curveseg->GetX1(&x1); curveseg->GetY1(&y1); curveseg->GetX2(&x2); curveseg->GetY2(&y2); x += cx; y += cy; x1 += cx; y1 += cy; x2 += cx; y2 += cy; } else { nsCOMPtr curveseg = do_QueryInterface(segment); NS_ASSERTION(curveseg, "interface not implemented"); curveseg->GetX(&x); curveseg->GetY(&y); curveseg->GetX1(&x1); curveseg->GetY1(&y1); curveseg->GetX2(&x2); curveseg->GetY2(&y2); } cx = x; cy = y; cx1 = x2; cy1 = y2; pathBuilder->Curveto(x, y, x1, y1, x2, y2); } break; case nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_ABS: absCoords = PR_TRUE; case nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_REL: { float x, y, x1, y1, x31, y31, x32, y32; if (!absCoords) { nsCOMPtr curveseg = do_QueryInterface(segment); NS_ASSERTION(curveseg, "interface not implemented"); curveseg->GetX(&x); curveseg->GetY(&y); curveseg->GetX1(&x1); curveseg->GetY1(&y1); x += cx; y += cy; x1 += cx; y1 += cy; } else { nsCOMPtr curveseg = do_QueryInterface(segment); NS_ASSERTION(curveseg, "interface not implemented"); curveseg->GetX(&x); curveseg->GetY(&y); curveseg->GetX1(&x1); curveseg->GetY1(&y1); } // conversion of quadratic bezier curve to cubic bezier curve: x31 = cx + (x1 - cx) * 2 / 3; y31 = cy + (y1 - cy) * 2 / 3; x32 = x1 + (x - x1) / 3; y32 = y1 + (y - y1) / 3; cx = x; cy = y; cx1 = x1; cy1 = y1; pathBuilder->Curveto(x, y, x31, y31, x32, y32); } break; case nsIDOMSVGPathSeg::PATHSEG_ARC_ABS: absCoords = PR_TRUE; case nsIDOMSVGPathSeg::PATHSEG_ARC_REL: { float x0, y0, x, y, r1, r2, angle; PRBool largeArcFlag, sweepFlag; x0 = cx; y0 = cy; if (!absCoords) { nsCOMPtr arcseg = do_QueryInterface(segment); NS_ASSERTION(arcseg, "interface not implemented"); arcseg->GetX(&x); arcseg->GetY(&y); arcseg->GetR1(&r1); arcseg->GetR2(&r2); arcseg->GetAngle(&angle); arcseg->GetLargeArcFlag(&largeArcFlag); arcseg->GetSweepFlag(&sweepFlag); x += cx; y += cy; } else { nsCOMPtr arcseg = do_QueryInterface(segment); NS_ASSERTION(arcseg, "interface not implemented"); arcseg->GetX(&x); arcseg->GetY(&y); arcseg->GetR1(&r1); arcseg->GetR2(&r2); arcseg->GetAngle(&angle); arcseg->GetLargeArcFlag(&largeArcFlag); arcseg->GetSweepFlag(&sweepFlag); } cx = x; cy = y; pathBuilder->Arcto(x, y, r1, r2, angle, largeArcFlag, sweepFlag); } break; case nsIDOMSVGPathSeg::PATHSEG_LINETO_HORIZONTAL_ABS: absCoords = PR_TRUE; case nsIDOMSVGPathSeg::PATHSEG_LINETO_HORIZONTAL_REL: { float x; float y = cy; if (!absCoords) { nsCOMPtr lineseg = do_QueryInterface(segment); NS_ASSERTION(lineseg, "interface not implemented"); lineseg->GetX(&x); x += cx; } else { nsCOMPtr lineseg = do_QueryInterface(segment); NS_ASSERTION(lineseg, "interface not implemented"); lineseg->GetX(&x); } cx = x; pathBuilder->Lineto(x,y); } break; case nsIDOMSVGPathSeg::PATHSEG_LINETO_VERTICAL_ABS: absCoords = PR_TRUE; case nsIDOMSVGPathSeg::PATHSEG_LINETO_VERTICAL_REL: { float x = cx; float y; if (!absCoords) { nsCOMPtr lineseg = do_QueryInterface(segment); NS_ASSERTION(lineseg, "interface not implemented"); lineseg->GetY(&y); y += cy; } else { nsCOMPtr lineseg = do_QueryInterface(segment); NS_ASSERTION(lineseg, "interface not implemented"); lineseg->GetY(&y); } cy = y; pathBuilder->Lineto(x,y); } break; case nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_ABS: absCoords = PR_TRUE; case nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_REL: { float x, y, x1, y1, x2, y2; if (lastSegmentType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_REL || lastSegmentType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_ABS || lastSegmentType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_REL || lastSegmentType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_ABS ) { // the first controlpoint is the reflection of the last one about the current point: x1 = 2*cx - cx1; y1 = 2*cy - cy1; } else { // the first controlpoint is equal to the current point: x1 = cx; y1 = cy; } if (!absCoords) { nsCOMPtr curveseg = do_QueryInterface(segment); NS_ASSERTION(curveseg, "interface not implemented"); curveseg->GetX(&x); curveseg->GetY(&y); curveseg->GetX2(&x2); curveseg->GetY2(&y2); x += cx; y += cy; x2 += cx; y2 += cy; } else { nsCOMPtr curveseg = do_QueryInterface(segment); NS_ASSERTION(curveseg, "interface not implemented"); curveseg->GetX(&x); curveseg->GetY(&y); curveseg->GetX2(&x2); curveseg->GetY2(&y2); } cx = x; cy = y; cx1 = x2; cy1 = y2; pathBuilder->Curveto(x, y, x1, y1, x2, y2); } break; case nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS: absCoords = PR_TRUE; case nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL: { float x, y, x1, y1, x31, y31, x32, y32; if (lastSegmentType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_REL || lastSegmentType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_ABS || lastSegmentType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL || lastSegmentType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS ) { // the first controlpoint is the reflection of the last one about the current point: x1 = 2*cx - cx1; y1 = 2*cy - cy1; } else { // the first controlpoint is equal to the current point: x1 = cx; y1 = cy; } if (!absCoords) { nsCOMPtr curveseg = do_QueryInterface(segment); NS_ASSERTION(curveseg, "interface not implemented"); curveseg->GetX(&x); curveseg->GetY(&y); x += cx; y += cy; } else { nsCOMPtr curveseg = do_QueryInterface(segment); NS_ASSERTION(curveseg, "interface not implemented"); curveseg->GetX(&x); curveseg->GetY(&y); } // conversion of quadratic bezier curve to cubic bezier curve: x31 = cx + (x1 - cx) * 2 / 3; y31 = cy + (y1 - cy) * 2 / 3; x32 = x1 + (x - x1) / 3; y32 = y1 + (y - y1) / 3; cx = x; cy = y; cx1 = x1; cy1 = y1; pathBuilder->Curveto(x, y, x31, y31, x32, y32); } break; default: NS_ASSERTION(1==0, "unknown path segment"); break; } lastSegmentType = type; } return NS_OK; } static float calcAngle(float ux, float uy, float vx, float vy) { float ta = atan2(uy, ux); float tb = atan2(vy, vx); if (tb >= ta) return tb-ta; return 2*M_PI - (ta-tb); } //---------------------------------------------------------------------- // nsISVGMarkable methods: void nsSVGPathFrame::GetMarkPoints(nsVoidArray *aMarks) { PRUint32 count; mSegments->GetNumberOfItems(&count); nsCOMPtr segment; float cx = 0.0f; // current point float cy = 0.0f; float cx1 = 0.0f; // last controlpoint (for s,S,t,T) float cy1 = 0.0f; PRUint16 lastSegmentType = nsIDOMSVGPathSeg::PATHSEG_UNKNOWN; float px, py; // subpath initial point float pathAngle, pathIndex; float prevAngle = 0, startAngle, endAngle; PRBool newSegment = PR_FALSE; PRUint32 i; for (i = 0; i < count; ++i) { nsCOMPtr segment; mSegments->GetItem(i, getter_AddRefs(segment)); PRUint16 type = nsIDOMSVGPathSeg::PATHSEG_UNKNOWN; segment->GetPathSegType(&type); float x, y; PRBool absCoords = PR_FALSE; switch (type) { case nsIDOMSVGPathSeg::PATHSEG_CLOSEPATH: { x = px; y = py; startAngle = endAngle = atan2(y - cy, x - cx); } break; case nsIDOMSVGPathSeg::PATHSEG_MOVETO_ABS: absCoords = PR_TRUE; case nsIDOMSVGPathSeg::PATHSEG_MOVETO_REL: { if (!absCoords) { nsCOMPtr moveseg = do_QueryInterface(segment); NS_ASSERTION(moveseg, "interface not implemented"); moveseg->GetX(&x); moveseg->GetY(&y); x += cx; y += cy; } else { nsCOMPtr moveseg = do_QueryInterface(segment); NS_ASSERTION(moveseg, "interface not implemented"); moveseg->GetX(&x); moveseg->GetY(&y); } px = x; py = y; startAngle = endAngle = prevAngle; newSegment = PR_TRUE; } break; case nsIDOMSVGPathSeg::PATHSEG_LINETO_ABS: absCoords = PR_TRUE; case nsIDOMSVGPathSeg::PATHSEG_LINETO_REL: { if (!absCoords) { nsCOMPtr lineseg = do_QueryInterface(segment); NS_ASSERTION(lineseg, "interface not implemented"); lineseg->GetX(&x); lineseg->GetY(&y); x += cx; y += cy; } else { nsCOMPtr lineseg = do_QueryInterface(segment); NS_ASSERTION(lineseg, "interface not implemented"); lineseg->GetX(&x); lineseg->GetY(&y); } startAngle = endAngle = atan2(y - cy, x - cx); } break; case nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_ABS: absCoords = PR_TRUE; case nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_REL: { float x1, y1, x2, y2; if (!absCoords) { nsCOMPtr curveseg = do_QueryInterface(segment); NS_ASSERTION(curveseg, "interface not implemented"); curveseg->GetX(&x); curveseg->GetY(&y); curveseg->GetX1(&x1); curveseg->GetY1(&y1); curveseg->GetX2(&x2); curveseg->GetY2(&y2); x += cx; y += cy; x1 += cx; y1 += cy; x2 += cx; y2 += cy; } else { nsCOMPtr curveseg = do_QueryInterface(segment); NS_ASSERTION(curveseg, "interface not implemented"); curveseg->GetX(&x); curveseg->GetY(&y); curveseg->GetX1(&x1); curveseg->GetY1(&y1); curveseg->GetX2(&x2); curveseg->GetY2(&y2); } cx1 = x2; cy1 = y2; if (x1 == cx && y1 == cy) { x1 = x2; y1 = y2; } if (x2 == x && y2 == y) { x2 = x1; y2 = y1; } startAngle = atan2(y1 - cy, x1 - cx); endAngle = atan2(y - y2, x - x2); } break; case nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_ABS: absCoords = PR_TRUE; case nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_REL: { float x1, y1; if (!absCoords) { nsCOMPtr curveseg = do_QueryInterface(segment); NS_ASSERTION(curveseg, "interface not implemented"); curveseg->GetX(&x); curveseg->GetY(&y); curveseg->GetX1(&x1); curveseg->GetY1(&y1); x += cx; y += cy; x1 += cx; y1 += cy; } else { nsCOMPtr curveseg = do_QueryInterface(segment); NS_ASSERTION(curveseg, "interface not implemented"); curveseg->GetX(&x); curveseg->GetY(&y); curveseg->GetX1(&x1); curveseg->GetY1(&y1); } cx1 = x1; cy1 = y1; startAngle = atan2(y1 - cy, x1 - cx); endAngle = atan2(y - y1, x - x1); } break; case nsIDOMSVGPathSeg::PATHSEG_ARC_ABS: absCoords = PR_TRUE; case nsIDOMSVGPathSeg::PATHSEG_ARC_REL: { float r1, r2, angle; PRBool largeArcFlag, sweepFlag; if (!absCoords) { nsCOMPtr arcseg = do_QueryInterface(segment); NS_ASSERTION(arcseg, "interface not implemented"); arcseg->GetX(&x); arcseg->GetY(&y); arcseg->GetR1(&r1); arcseg->GetR2(&r2); arcseg->GetAngle(&angle); arcseg->GetLargeArcFlag(&largeArcFlag); arcseg->GetSweepFlag(&sweepFlag); x += cx; y += cy; } else { nsCOMPtr arcseg = do_QueryInterface(segment); NS_ASSERTION(arcseg, "interface not implemented"); arcseg->GetX(&x); arcseg->GetY(&y); arcseg->GetR1(&r1); arcseg->GetR2(&r2); arcseg->GetAngle(&angle); arcseg->GetLargeArcFlag(&largeArcFlag); arcseg->GetSweepFlag(&sweepFlag); } /* check for degenerate ellipse */ if (r1 == 0.0 || r2 == 0.0) { startAngle = endAngle = atan2(y - cy, x - cx); break; } r1 = fabs(r1); r2 = fabs(r2); float xp, yp, cxp, cyp; /* slope fun&games ... see SVG spec, section F.6 */ angle = angle*M_PI/180.0; xp = cos(angle)*(cx-x)/2.0 + sin(angle)*(cy-y)/2.0; yp = -sin(angle)*(cx-x)/2.0 + cos(angle)*(cy-y)/2.0; /* make sure radii are large enough */ float root, numerator = r1*r1*r2*r2 - r1*r1*yp*yp - r2*r2*xp*xp; if (numerator < 0.0) { float s = sqrt(1.0 - numerator/(r1*r1*r2*r2)); r1 *= s; r2 *= s; root = 0.0; } else { root = sqrt(numerator/(r1*r1*yp*yp + r2*r2*xp*xp)); if (largeArcFlag == sweepFlag) root = -root; } cxp = root*r1*yp/r2; cyp = -root*r2*xp/r1; float theta, delta; theta = calcAngle(1.0, 0.0, (xp-cxp)/r1, (yp-cyp)/r2); delta = calcAngle((xp-cxp)/r1, (yp-cyp)/r2, (-xp-cxp)/r1, (-yp-cyp)/r2); if (!sweepFlag && delta > 0) delta -= 2.0*M_PI; else if (sweepFlag && delta < 0) delta += 2.0*M_PI; float tx1, ty1, tx2, ty2; tx1 = -cos(angle)*r1*sin(theta) - sin(angle)*r2*cos(theta); ty1 = -sin(angle)*r1*sin(theta) + cos(angle)*r2*cos(theta); tx2 = -cos(angle)*r1*sin(theta+delta) - sin(angle)*r2*cos(theta+delta); ty2 = -sin(angle)*r1*sin(theta+delta) + cos(angle)*r2*cos(theta+delta); if (delta < 0.0f) { tx1 = -tx1; ty1 = -ty1; tx2 = -tx2; ty2 = -ty2; } startAngle = atan2(ty1, tx1); endAngle = atan2(ty2, tx2); } break; case nsIDOMSVGPathSeg::PATHSEG_LINETO_HORIZONTAL_ABS: absCoords = PR_TRUE; case nsIDOMSVGPathSeg::PATHSEG_LINETO_HORIZONTAL_REL: { y = cy; if (!absCoords) { nsCOMPtr lineseg = do_QueryInterface(segment); NS_ASSERTION(lineseg, "interface not implemented"); lineseg->GetX(&x); x += cx; } else { nsCOMPtr lineseg = do_QueryInterface(segment); NS_ASSERTION(lineseg, "interface not implemented"); lineseg->GetX(&x); } startAngle = endAngle = atan2(0, x - cx); } break; case nsIDOMSVGPathSeg::PATHSEG_LINETO_VERTICAL_ABS: absCoords = PR_TRUE; case nsIDOMSVGPathSeg::PATHSEG_LINETO_VERTICAL_REL: { x = cx; if (!absCoords) { nsCOMPtr lineseg = do_QueryInterface(segment); NS_ASSERTION(lineseg, "interface not implemented"); lineseg->GetY(&y); y += cy; } else { nsCOMPtr lineseg = do_QueryInterface(segment); NS_ASSERTION(lineseg, "interface not implemented"); lineseg->GetY(&y); } startAngle = endAngle = atan2(y - cy, 0); } break; case nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_ABS: absCoords = PR_TRUE; case nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_REL: { float x1, y1, x2, y2; if (lastSegmentType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_REL || lastSegmentType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_ABS || lastSegmentType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_REL || lastSegmentType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_ABS ) { // the first controlpoint is the reflection of the last one about the current point: x1 = 2*cx - cx1; y1 = 2*cy - cy1; } else { // the first controlpoint is equal to the current point: x1 = cx; y1 = cy; } if (!absCoords) { nsCOMPtr curveseg = do_QueryInterface(segment); NS_ASSERTION(curveseg, "interface not implemented"); curveseg->GetX(&x); curveseg->GetY(&y); curveseg->GetX2(&x2); curveseg->GetY2(&y2); x += cx; y += cy; x2 += cx; y2 += cy; } else { nsCOMPtr curveseg = do_QueryInterface(segment); NS_ASSERTION(curveseg, "interface not implemented"); curveseg->GetX(&x); curveseg->GetY(&y); curveseg->GetX2(&x2); curveseg->GetY2(&y2); } cx1 = x2; cy1 = y2; if (x1 == cx && y1 == cy) { x1 = x2; y1 = y2; } if (x2 == x && y2 == y) { x2 = x1; y2 = y1; } startAngle = atan2(y1 - cy, x1 - cx); endAngle = atan2(y - y2, x - x2); } break; case nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS: absCoords = PR_TRUE; case nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL: { float x1, y1; if (lastSegmentType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_REL || lastSegmentType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_ABS || lastSegmentType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL || lastSegmentType == nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS ) { // the first controlpoint is the reflection of the last one about the current point: x1 = 2*cx - cx1; y1 = 2*cy - cy1; } else { // the first controlpoint is equal to the current point: x1 = cx; y1 = cy; } if (!absCoords) { nsCOMPtr curveseg = do_QueryInterface(segment); NS_ASSERTION(curveseg, "interface not implemented"); curveseg->GetX(&x); curveseg->GetY(&y); x += cx; y += cy; } else { nsCOMPtr curveseg = do_QueryInterface(segment); NS_ASSERTION(curveseg, "interface not implemented"); curveseg->GetX(&x); curveseg->GetY(&y); } cx1 = x1; cy1 = y1; startAngle = atan2(y1 - cy, x1 - cx); endAngle = atan2(y - y1, x - x1); } break; default: NS_ASSERTION(1==0, "unknown path segment"); break; } lastSegmentType = type; if (newSegment && type != nsIDOMSVGPathSeg::PATHSEG_MOVETO_ABS && type != nsIDOMSVGPathSeg::PATHSEG_MOVETO_REL) { pathIndex = aMarks->Count() - 1; pathAngle = startAngle; ((nsSVGMark *)aMarks->ElementAt(aMarks->Count()-1))->angle = pathAngle; newSegment = PR_FALSE; prevAngle = endAngle; } else if (type == nsIDOMSVGPathSeg::PATHSEG_MOVETO_ABS || type == nsIDOMSVGPathSeg::PATHSEG_MOVETO_REL) { if (aMarks->Count()) ((nsSVGMark *)aMarks->ElementAt(aMarks->Count()-1))->angle = prevAngle; } else { ((nsSVGMark *)aMarks->ElementAt(aMarks->Count()-1))->angle = nsSVGMarkerFrame::bisect(prevAngle, startAngle); prevAngle = endAngle; } nsSVGMark *mark = new nsSVGMark; mark->x = x; mark->y = y; aMarks->AppendElement(mark); if (type == nsIDOMSVGPathSeg::PATHSEG_CLOSEPATH) { prevAngle = nsSVGMarkerFrame::bisect(endAngle, pathAngle); ((nsSVGMark *)aMarks->ElementAt(pathIndex))->angle = prevAngle; } cx = x; cy = y; } if (aMarks->Count()) ((nsSVGMark *)aMarks->ElementAt(aMarks->Count()-1))->angle = prevAngle; } nsIAtom * nsSVGPathFrame::GetType() const { return nsLayoutAtoms::svgPathFrame; }