bug 274698 : Improve nsSVGLength.cpp : r=tor

git-svn-id: svn://10.0.0.236/trunk@169207 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
jwatt%jwatt.org 2005-02-15 19:18:58 +00:00
parent d9094a484b
commit 955b2e06d4

View File

@ -21,6 +21,7 @@
*
* Contributor(s):
* Alex Fritze <alex.fritze@crocodile-clips.com> (original author)
* Jonathan Watt <jonathan.watt@strath.ac.uk>
*
* 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"),
@ -37,12 +38,11 @@
* ***** END LICENSE BLOCK ***** */
#include "nsSVGLength.h"
#include "prdtoa.h"
#include "nsIDOMSVGMatrix.h"
#include "nsSVGAtoms.h"
#include "nsSVGValue.h"
#include "nsReadableUtils.h"
#include "nsTextFormatter.h"
#include "prdtoa.h"
#include "nsCRT.h"
#include "nsSVGCoordCtx.h"
#include "nsIDOMSVGNumber.h"
@ -95,13 +95,9 @@ public:
protected:
// implementation helpers:
float UserUnitsPerPixel();
float mmPerPixel();
float AxisLength();
void GetUnitString(nsAString& unit);
PRUint16 GetUnitTypeForString(const char* unitStr);
PRBool IsValidUnitType(PRUint16 unit);
void MaybeAddAsObserver();
void MaybeRemoveAsObserver();
@ -119,10 +115,10 @@ NS_NewSVGLength(nsISVGLength** result,
float value,
PRUint16 unit)
{
nsSVGLength *pl = new nsSVGLength(value, unit);
NS_ENSURE_TRUE(pl, NS_ERROR_OUT_OF_MEMORY);
NS_ADDREF(pl);
*result = pl;
*result = new nsSVGLength(value, unit);
if (!*result)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(*result);
return NS_OK;
}
@ -132,11 +128,13 @@ NS_NewSVGLength(nsISVGLength** result,
{
*result = nsnull;
nsSVGLength *pl = new nsSVGLength();
NS_ENSURE_TRUE(pl, NS_ERROR_OUT_OF_MEMORY);
if (!pl)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(pl);
if (NS_FAILED(pl->SetValueAsString(value))) {
nsresult rv = pl->SetValueAsString(value);
if (NS_FAILED(rv)) {
NS_RELEASE(pl);
return NS_ERROR_FAILURE;
return rv;
}
*result = pl;
return NS_OK;
@ -148,7 +146,7 @@ nsSVGLength::nsSVGLength(float value,
: mValueInSpecifiedUnits(value),
mSpecifiedUnitType(unit)
{
MaybeAddAsObserver();
// we don't have a context yet, so we don't call MaybeAddAsObserver()
}
nsSVGLength::nsSVGLength()
@ -178,6 +176,7 @@ NS_INTERFACE_MAP_END
//----------------------------------------------------------------------
// nsISVGValue methods:
NS_IMETHODIMP
nsSVGLength::SetValueString(const nsAString& aValue)
{
@ -210,7 +209,7 @@ nsSVGLength::DidModifySVGObservable(nsISVGValue* observable,
}
//----------------------------------------------------------------------
// nsISVGLength methods:
// nsIDOMSVGLength methods:
/* readonly attribute unsigned short unitType; */
NS_IMETHODIMP
@ -224,85 +223,85 @@ nsSVGLength::GetUnitType(PRUint16 *aUnitType)
NS_IMETHODIMP
nsSVGLength::GetValue(float *aValue)
{
nsresult rv = NS_OK;
switch (mSpecifiedUnitType) {
case SVG_LENGTHTYPE_NUMBER:
case SVG_LENGTHTYPE_PX:
*aValue = mValueInSpecifiedUnits;
break;
case SVG_LENGTHTYPE_PX:
*aValue = mValueInSpecifiedUnits * UserUnitsPerPixel();
break;
case SVG_LENGTHTYPE_MM:
*aValue = mValueInSpecifiedUnits / mmPerPixel() * UserUnitsPerPixel();
*aValue = mValueInSpecifiedUnits / mmPerPixel();
break;
case SVG_LENGTHTYPE_CM:
*aValue = mValueInSpecifiedUnits * 10.0f / mmPerPixel() * UserUnitsPerPixel();
*aValue = mValueInSpecifiedUnits * 10.0f / mmPerPixel();
break;
case SVG_LENGTHTYPE_IN:
*aValue = mValueInSpecifiedUnits * 25.4f / mmPerPixel() * UserUnitsPerPixel();
*aValue = mValueInSpecifiedUnits * 25.4f / mmPerPixel();
break;
case SVG_LENGTHTYPE_PT:
*aValue = mValueInSpecifiedUnits * 25.4f/72.0f / mmPerPixel() * UserUnitsPerPixel();
*aValue = mValueInSpecifiedUnits * 25.4f / 72.0f / mmPerPixel();
break;
case SVG_LENGTHTYPE_PC:
*aValue = mValueInSpecifiedUnits * 25.4f*12.0f/72.0f / mmPerPixel() * UserUnitsPerPixel();
*aValue = mValueInSpecifiedUnits * 25.4f * 12.0f / 72.0f / mmPerPixel();
break;
case SVG_LENGTHTYPE_PERCENTAGE:
*aValue = mValueInSpecifiedUnits * AxisLength() / 100.0f;
break;
case SVG_LENGTHTYPE_EMS:
case SVG_LENGTHTYPE_EXS:
//XXX
NS_ASSERTION(PR_FALSE, "unit not implemented yet");
NS_NOTYETIMPLEMENTED("unit not implemented - write me!");
*aValue = 0;
return NS_ERROR_NOT_IMPLEMENTED;
default:
rv = NS_ERROR_FAILURE;
break;
NS_NOTREACHED("Unknown unit type");
*aValue = 0;
return NS_ERROR_UNEXPECTED;
}
return rv;
return NS_OK;
}
NS_IMETHODIMP
nsSVGLength::SetValue(float aValue)
{
nsresult rv = NS_OK;
WillModify();
switch (mSpecifiedUnitType) {
case SVG_LENGTHTYPE_NUMBER:
case SVG_LENGTHTYPE_PX:
mValueInSpecifiedUnits = aValue;
break;
case SVG_LENGTHTYPE_PX:
mValueInSpecifiedUnits = aValue / UserUnitsPerPixel();
break;
case SVG_LENGTHTYPE_MM:
mValueInSpecifiedUnits = aValue / UserUnitsPerPixel() * mmPerPixel();
mValueInSpecifiedUnits = aValue * mmPerPixel();
break;
case SVG_LENGTHTYPE_CM:
mValueInSpecifiedUnits = aValue / UserUnitsPerPixel() * mmPerPixel() / 10.0f;
mValueInSpecifiedUnits = aValue * mmPerPixel() / 10.0f;
break;
case SVG_LENGTHTYPE_IN:
mValueInSpecifiedUnits = aValue / UserUnitsPerPixel() * mmPerPixel() / 25.4f;
mValueInSpecifiedUnits = aValue * mmPerPixel() / 25.4f;
break;
case SVG_LENGTHTYPE_PT:
mValueInSpecifiedUnits = aValue / UserUnitsPerPixel() * mmPerPixel() * 72.0f/25.4f;
mValueInSpecifiedUnits = aValue * mmPerPixel() * 72.0f / 25.4f;
break;
case SVG_LENGTHTYPE_PC:
mValueInSpecifiedUnits = aValue / UserUnitsPerPixel() * mmPerPixel() * 72.0f/24.4f/12.0f;
mValueInSpecifiedUnits = aValue * mmPerPixel() * 72.0f / 24.4f / 12.0f;
break;
case SVG_LENGTHTYPE_PERCENTAGE:
mValueInSpecifiedUnits = aValue * 100.0f / AxisLength();
break;
case SVG_LENGTHTYPE_EMS:
case SVG_LENGTHTYPE_EXS:
//XXX
NS_ASSERTION(PR_FALSE, "unit not implemented yet");
NS_NOTYETIMPLEMENTED("unit not implemented - write me!");
mValueInSpecifiedUnits = 0;
rv = NS_ERROR_NOT_IMPLEMENTED;
break;
default:
rv = NS_ERROR_FAILURE;
NS_NOTREACHED("Unknown unit type");
mValueInSpecifiedUnits = 0;
rv = NS_ERROR_UNEXPECTED;
break;
}
DidModify();
return rv;
}
@ -327,18 +326,53 @@ nsSVGLength::SetValueInSpecifiedUnits(float aValueInSpecifiedUnits)
NS_IMETHODIMP
nsSVGLength::GetValueAsString(nsAString & aValueAsString)
{
aValueAsString.Truncate();
PRUnichar buf[24];
nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(PRUnichar),
NS_LITERAL_STRING("%g").get(),
(double)mValueInSpecifiedUnits);
aValueAsString.Append(buf);
aValueAsString.Assign(buf);
nsIAtom* UnitAtom = nsnull;
switch (mSpecifiedUnitType) {
case SVG_LENGTHTYPE_NUMBER:
return NS_OK;
case SVG_LENGTHTYPE_PX:
UnitAtom = nsSVGAtoms::px;
break;
case SVG_LENGTHTYPE_MM:
UnitAtom = nsSVGAtoms::mm;
break;
case SVG_LENGTHTYPE_CM:
UnitAtom = nsSVGAtoms::cm;
break;
case SVG_LENGTHTYPE_IN:
UnitAtom = nsSVGAtoms::in;
break;
case SVG_LENGTHTYPE_PT:
UnitAtom = nsSVGAtoms::pt;
break;
case SVG_LENGTHTYPE_PC:
UnitAtom = nsSVGAtoms::pc;
break;
case SVG_LENGTHTYPE_EMS:
UnitAtom = nsSVGAtoms::ems;
break;
case SVG_LENGTHTYPE_EXS:
UnitAtom = nsSVGAtoms::exs;
break;
case SVG_LENGTHTYPE_PERCENTAGE:
UnitAtom = nsSVGAtoms::percentage;
break;
default:
NS_NOTREACHED("Unknown unit");
return NS_ERROR_UNEXPECTED;
}
nsAutoString unitString;
GetUnitString(unitString);
UnitAtom->ToString(unitString);
aValueAsString.Append(unitString);
return NS_OK;
}
@ -357,7 +391,32 @@ nsSVGLength::SetValueAsString(const nsAString & aValueAsString)
char *rest;
double value = PR_strtod(number, &rest);
if (rest!=number) {
PRUint16 unitType = GetUnitTypeForString(nsCRT::strtok(rest, "\x20\x9\xD\xA", &rest));
const char* unitStr = nsCRT::strtok(rest, "\x20\x9\xD\xA", &rest);
PRUint16 unitType = SVG_LENGTHTYPE_UNKNOWN;
if (!unitStr || *unitStr=='\0') {
unitType = SVG_LENGTHTYPE_NUMBER;
}
else {
nsCOMPtr<nsIAtom> unitAtom = do_GetAtom(unitStr);
if (unitAtom == nsSVGAtoms::px)
unitType = SVG_LENGTHTYPE_PX;
else if (unitAtom == nsSVGAtoms::mm)
unitType = SVG_LENGTHTYPE_MM;
else if (unitAtom == nsSVGAtoms::cm)
unitType = SVG_LENGTHTYPE_CM;
else if (unitAtom == nsSVGAtoms::in)
unitType = SVG_LENGTHTYPE_IN;
else if (unitAtom == nsSVGAtoms::pt)
unitType = SVG_LENGTHTYPE_PT;
else if (unitAtom == nsSVGAtoms::pc)
unitType = SVG_LENGTHTYPE_PC;
else if (unitAtom == nsSVGAtoms::ems)
unitType = SVG_LENGTHTYPE_EMS;
else if (unitAtom == nsSVGAtoms::exs)
unitType = SVG_LENGTHTYPE_EXS;
else if (unitAtom == nsSVGAtoms::percentage)
unitType = SVG_LENGTHTYPE_PERCENTAGE;
}
if (IsValidUnitType(unitType)){
WillModify();
mValueInSpecifiedUnits = (float)value;
@ -382,13 +441,14 @@ nsSVGLength::SetValueAsString(const nsAString & aValueAsString)
}
/* void newValueSpecifiedUnits (in unsigned short unitType, in float valueInSpecifiedUnits); */
NS_IMETHODIMP
NS_IMETHODIMP
nsSVGLength::NewValueSpecifiedUnits(PRUint16 unitType, float valueInSpecifiedUnits)
{
if (!IsValidUnitType(unitType)) return NS_ERROR_FAILURE;
if (!IsValidUnitType(unitType))
return NS_ERROR_FAILURE;
PRBool observer_change = (unitType != mSpecifiedUnitType);
bool observer_change = (unitType != mSpecifiedUnitType);
WillModify();
if (observer_change)
MaybeRemoveAsObserver();
@ -405,9 +465,10 @@ nsSVGLength::NewValueSpecifiedUnits(PRUint16 unitType, float valueInSpecifiedUni
NS_IMETHODIMP
nsSVGLength::ConvertToSpecifiedUnits(PRUint16 unitType)
{
if (!IsValidUnitType(unitType)) return NS_ERROR_FAILURE;
if (!IsValidUnitType(unitType))
return NS_ERROR_FAILURE;
bool observer_change = (unitType != mSpecifiedUnitType);
PRBool observer_change = (unitType != mSpecifiedUnitType);
WillModify();
if (observer_change)
@ -426,17 +487,15 @@ nsSVGLength::ConvertToSpecifiedUnits(PRUint16 unitType)
/* float getTransformedValue (in nsIDOMSVGMatrix matrix); */
NS_IMETHODIMP
nsSVGLength::GetTransformedValue(nsIDOMSVGMatrix *matrix,
float *_retval)
float *_retval)
{
// XXX we don't have enough information here. is it the length part of
// a coordinate pair (in which case it should transform like a point)
// or is it used like a vector-component (in which case it doesn't
// translate)
NS_NOTYETIMPLEMENTED("write me!");
return NS_ERROR_UNEXPECTED;
return NS_ERROR_NOT_IMPLEMENTED;
}
@ -466,59 +525,9 @@ nsSVGLength::SetContext(nsSVGCoordCtx* context)
}
//----------------------------------------------------------------------
// Implementation helpers:
float nsSVGLength::UserUnitsPerPixel()
{
float UUPerPx = 1.0f;
// SVG CR 20001102: New: A px unit and a user unit are defined to be
// equivalent in SVG. Thus, a length of "5px" is the same as a
// length of "5".
//
// old way of mapping pixels:
// if (!mOwnerElement) return UUPerPx;
// nsCOMPtr<nsIDOMSVGLocatable> locatable;
// locatable = do_QueryInterface(mOwnerElement);
// if (!locatable) return UUPerPx;
// nsCOMPtr<nsIDOMSVGMatrix> matrix;
// locatable->GetCTM( getter_AddRefs(matrix) );
// if (!matrix) return UUPerPx;
// nsCOMPtr<nsIDOMSVGPoint> point, XFormedPoint;
// nsSVGPoint::Create(1.0, 1.0, getter_AddRefs(point));
// point->MatrixTransform(matrix, getter_AddRefs(XFormedPoint));
// switch (mDirection) {
// case eXDirection:
// XFormedPoint->GetX(&UUPerPx);
// break;
// case eYDirection:
// XFormedPoint->GetY(&UUPerPx);
// break;
// case eNoDirection:
// {
// float x,y;
// XFormedPoint->GetX(&x);
// XFormedPoint->GetY(&y);
// UUPerPx = (x==y ? x : (x+y)/2);
// break;
// }
// }
// if (UUPerPx == 0.0f) {
// NS_ASSERTION(PR_FALSE, "invalid uu/pixels");
// UUPerPx = 1e-20f; // some small value
// }
return UUPerPx;
}
float nsSVGLength::mmPerPixel()
{
if (!mContext) {
@ -527,9 +536,9 @@ float nsSVGLength::mmPerPixel()
}
float mmPerPx = mContext->GetMillimeterPerPixel();
if (mmPerPx == 0.0f) {
NS_ASSERTION(PR_FALSE, "invalid mm/pixels");
NS_ASSERTION(mmPerPx != 0.0f, "invalid mm/pixels");
mmPerPx = 1e-4f; // some small value
}
@ -544,92 +553,21 @@ float nsSVGLength::AxisLength()
}
nsCOMPtr<nsIDOMSVGNumber> num = mContext->GetLength();
NS_ASSERTION(num, "null interface");
NS_ASSERTION(num != nsnull, "null interface");
float d;
num->GetValue(&d);
NS_ASSERTION(d!=0.0f, "zero axis length");
if (d == 0.0f)
if (d == 0.0f) {
NS_WARNING("zero axis length");
d = 1e-20f;
return d;
}
void nsSVGLength::GetUnitString(nsAString& unit)
{
nsIAtom* UnitAtom = nsnull;
switch (mSpecifiedUnitType) {
case SVG_LENGTHTYPE_NUMBER:
UnitAtom = nsnull;
break;
case SVG_LENGTHTYPE_PX:
UnitAtom = nsSVGAtoms::px;
break;
case SVG_LENGTHTYPE_MM:
UnitAtom = nsSVGAtoms::mm;
break;
case SVG_LENGTHTYPE_CM:
UnitAtom = nsSVGAtoms::cm;
break;
case SVG_LENGTHTYPE_IN:
UnitAtom = nsSVGAtoms::in;
break;
case SVG_LENGTHTYPE_PT:
UnitAtom = nsSVGAtoms::pt;
break;
case SVG_LENGTHTYPE_PC:
UnitAtom = nsSVGAtoms::pc;
break;
case SVG_LENGTHTYPE_EMS:
UnitAtom = nsSVGAtoms::ems;
break;
case SVG_LENGTHTYPE_EXS:
UnitAtom = nsSVGAtoms::exs;
break;
case SVG_LENGTHTYPE_PERCENTAGE:
UnitAtom = nsSVGAtoms::percentage;
break;
default:
NS_ASSERTION(PR_FALSE, "unknown unit");
break;
}
if (!UnitAtom) return;
UnitAtom->ToString(unit);
}
PRUint16 nsSVGLength::GetUnitTypeForString(const char* unitStr)
{
if (!unitStr || *unitStr=='\0') return SVG_LENGTHTYPE_NUMBER;
nsCOMPtr<nsIAtom> unitAtom = do_GetAtom(unitStr);
if (unitAtom == nsSVGAtoms::px)
return SVG_LENGTHTYPE_PX;
else if (unitAtom == nsSVGAtoms::mm)
return SVG_LENGTHTYPE_MM;
else if (unitAtom == nsSVGAtoms::cm)
return SVG_LENGTHTYPE_CM;
else if (unitAtom == nsSVGAtoms::in)
return SVG_LENGTHTYPE_IN;
else if (unitAtom == nsSVGAtoms::pt)
return SVG_LENGTHTYPE_PT;
else if (unitAtom == nsSVGAtoms::pc)
return SVG_LENGTHTYPE_PC;
else if (unitAtom == nsSVGAtoms::ems)
return SVG_LENGTHTYPE_EMS;
else if (unitAtom == nsSVGAtoms::exs)
return SVG_LENGTHTYPE_EXS;
else if (unitAtom == nsSVGAtoms::percentage)
return SVG_LENGTHTYPE_PERCENTAGE;
return SVG_LENGTHTYPE_UNKNOWN;
return d;
}
PRBool nsSVGLength::IsValidUnitType(PRUint16 unit)
{
if (unit>0 && unit<=10)
if (unit > SVG_LENGTHTYPE_UNKNOWN && unit <= SVG_LENGTHTYPE_PC)
return PR_TRUE;
return PR_FALSE;