fune/content/svg/content/src/nsSVGPointList.cpp
Peter Van der Beken e1c6294f66 Fix for bug 552716 (Remove NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO). r=jst.
--HG--
extra : rebase_source : 8e03b54ff6117dcac27188b296c59dcafbb6db78
2010-03-17 16:09:05 +01:00

364 lines
9.7 KiB
C++

/* -*- 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 <alex.fritze@crocodile-clips.com> (original author)
*
* 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 "nsSVGPointList.h"
#include "nsSVGPoint.h"
#include "nsDOMError.h"
#include "prdtoa.h"
#include "nsReadableUtils.h"
#include "nsTextFormatter.h"
#include "nsCRT.h"
#include "nsCOMArray.h"
#include "nsContentUtils.h"
nsresult
nsSVGPointList::Create(const nsAString& aValue,
nsISVGValue** aResult)
{
*aResult = (nsISVGValue*) new nsSVGPointList();
if(!*aResult) return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(*aResult);
(*aResult)->SetValueString(aValue);
return NS_OK;
}
nsresult
nsSVGPointList::Create(nsIDOMSVGPointList** aResult)
{
*aResult = (nsIDOMSVGPointList*) new nsSVGPointList();
if(!*aResult) return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(*aResult);
return NS_OK;
}
nsSVGPointList::nsSVGPointList()
{
}
nsSVGPointList::~nsSVGPointList()
{
ReleasePoints();
}
void
nsSVGPointList::ReleasePoints()
{
WillModify();
PRUint32 count = mPoints.Length();
for (PRUint32 i = 0; i < count; ++i) {
nsIDOMSVGPoint* point = ElementAt(i);
nsCOMPtr<nsISVGValue> val = do_QueryInterface(point);
if (val)
val->RemoveObserver(this);
NS_RELEASE(point);
}
mPoints.Clear();
DidModify();
}
nsIDOMSVGPoint*
nsSVGPointList::ElementAt(PRInt32 index)
{
return mPoints.ElementAt(index);
}
void
nsSVGPointList::AppendElement(nsIDOMSVGPoint* aElement)
{
WillModify();
NS_ADDREF(aElement);
mPoints.AppendElement(aElement);
nsCOMPtr<nsISVGValue> val = do_QueryInterface(aElement);
if (val)
val->AddObserver(this);
DidModify();
}
void
nsSVGPointList::RemoveElementAt(PRInt32 index)
{
WillModify();
nsIDOMSVGPoint* point = ElementAt(index);
NS_ASSERTION(point, "null point");
nsCOMPtr<nsISVGValue> val = do_QueryInterface(point);
if (val)
val->RemoveObserver(this);
mPoints.RemoveElementAt(index);
NS_RELEASE(point);
DidModify();
}
void
nsSVGPointList::InsertElementAt(nsIDOMSVGPoint* aElement, PRInt32 index)
{
WillModify();
NS_ADDREF(aElement);
mPoints.InsertElementAt(index, aElement);
nsCOMPtr<nsISVGValue> val = do_QueryInterface(aElement);
if (val)
val->AddObserver(this);
DidModify();
}
//----------------------------------------------------------------------
// nsISupports methods:
NS_IMPL_ADDREF(nsSVGPointList)
NS_IMPL_RELEASE(nsSVGPointList)
NS_INTERFACE_MAP_BEGIN(nsSVGPointList)
NS_INTERFACE_MAP_ENTRY(nsISVGValue)
NS_INTERFACE_MAP_ENTRY(nsIDOMSVGPointList)
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
NS_INTERFACE_MAP_ENTRY(nsISVGValueObserver)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGPointList)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISVGValue)
NS_INTERFACE_MAP_END
//----------------------------------------------------------------------
// nsISVGValue methods:
NS_IMETHODIMP
nsSVGPointList::SetValueString(const nsAString& aValue)
{
nsresult rv = NS_OK;
char* str = ToNewCString(aValue);
char* rest = str;
char* token1;
char* token2;
const char* delimiters = ",\x20\x9\xD\xA";
nsCOMArray<nsIDOMSVGPoint> points;
while ( (token1 = nsCRT::strtok(rest, delimiters, &rest)) &&
(token2 = nsCRT::strtok(rest, delimiters, &rest)) ) {
char *end;
float x = float(PR_strtod(token1, &end));
if (*end != '\0' || !NS_FloatIsFinite(x)) {
rv = NS_ERROR_DOM_SYNTAX_ERR;
break; // parse error
}
float y = float(PR_strtod(token2, &end));
if (*end != '\0' || !NS_FloatIsFinite(y)) {
rv = NS_ERROR_DOM_SYNTAX_ERR;
break; // parse error
}
nsCOMPtr<nsIDOMSVGPoint> point;
NS_NewSVGPoint(getter_AddRefs(point), x, y);
if (!point) {
rv = NS_ERROR_OUT_OF_MEMORY;
break;
}
points.AppendObject(point);
}
if (token1 || NS_FAILED(rv)) {
// there was a parse error or we ran out of memory
rv = NS_ERROR_DOM_SYNTAX_ERR;
} else {
WillModify();
ReleasePoints();
PRInt32 count = points.Count();
for (PRInt32 i=0; i<count; ++i) {
AppendElement(points.ObjectAt(i));
}
DidModify();
}
nsMemory::Free(str);
return rv;
}
NS_IMETHODIMP
nsSVGPointList::GetValueString(nsAString& aValue)
{
aValue.Truncate();
PRUint32 count = mPoints.Length();
if (count == 0) return NS_OK;
PRUint32 i = 0;
PRUnichar buf[48];
while (1) {
nsIDOMSVGPoint* point = ElementAt(i);
float x, y;
point->GetX(&x);
point->GetY(&y);
nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(PRUnichar), NS_LITERAL_STRING("%g,%g").get(), (double)x, (double)y);
aValue.Append(buf);
if (++i >= count) break;
aValue.AppendLiteral(" ");
}
return NS_OK;
}
//----------------------------------------------------------------------
// nsIDOMSVGPointList methods:
/* readonly attribute unsigned long numberOfItems; */
NS_IMETHODIMP nsSVGPointList::GetNumberOfItems(PRUint32 *aNumberOfItems)
{
*aNumberOfItems = mPoints.Length();
return NS_OK;
}
/* void clear (); */
NS_IMETHODIMP nsSVGPointList::Clear()
{
WillModify();
ReleasePoints();
DidModify();
return NS_OK;
}
/* nsIDOMSVGPoint initialize (in nsIDOMSVGPoint newItem); */
NS_IMETHODIMP nsSVGPointList::Initialize(nsIDOMSVGPoint *newItem,
nsIDOMSVGPoint **_retval)
{
if (!newItem) {
*_retval = nsnull;
return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
}
Clear();
return AppendItem(newItem, _retval);
}
/* nsIDOMSVGPoint getItem (in unsigned long index); */
NS_IMETHODIMP nsSVGPointList::GetItem(PRUint32 index, nsIDOMSVGPoint **_retval)
{
if (index >= mPoints.Length()) {
*_retval = nsnull;
return NS_ERROR_DOM_INDEX_SIZE_ERR;
}
*_retval = ElementAt(index);
NS_ADDREF(*_retval);
return NS_OK;
}
/* nsIDOMSVGPoint insertItemBefore (in nsIDOMSVGPoint newItem, in unsigned long index); */
NS_IMETHODIMP nsSVGPointList::InsertItemBefore(nsIDOMSVGPoint *newItem,
PRUint32 index,
nsIDOMSVGPoint **_retval)
{
// null check when implementing - this method can be used by scripts!
// if (!newItem)
// return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
NS_NOTYETIMPLEMENTED("write me");
return NS_ERROR_NOT_IMPLEMENTED;
}
/* nsIDOMSVGPoint replaceItem (in nsIDOMSVGPoint newItem, in unsigned long index); */
NS_IMETHODIMP nsSVGPointList::ReplaceItem(nsIDOMSVGPoint *newItem,
PRUint32 index,
nsIDOMSVGPoint **_retval)
{
// null check when implementing - this method can be used by scripts!
// if (!newItem)
// return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
NS_NOTYETIMPLEMENTED("write me");
return NS_ERROR_NOT_IMPLEMENTED;
}
/* nsIDOMSVGPoint removeItem (in unsigned long index); */
NS_IMETHODIMP nsSVGPointList::RemoveItem(PRUint32 index, nsIDOMSVGPoint **_retval)
{
if (index >= mPoints.Length()) {
*_retval = nsnull;
return NS_ERROR_DOM_INDEX_SIZE_ERR;
}
*_retval = ElementAt(index);
NS_ADDREF(*_retval);
WillModify();
RemoveElementAt(index);
DidModify();
return NS_OK;
}
/* nsIDOMSVGPoint appendItem (in nsIDOMSVGPoint newItem); */
NS_IMETHODIMP nsSVGPointList::AppendItem(nsIDOMSVGPoint *newItem,
nsIDOMSVGPoint **_retval)
{
// XXX The SVG specs state that 'if newItem is already in a list, it
// is removed from its previous list before it is inserted into this
// list'. We don't do that. Should we?
*_retval = newItem;
if (!newItem)
return NS_ERROR_DOM_SVG_WRONG_TYPE_ERR;
AppendElement(newItem);
NS_ADDREF(*_retval);
return NS_OK;
}
//----------------------------------------------------------------------
// nsISVGValueObserver methods
NS_IMETHODIMP
nsSVGPointList::WillModifySVGObservable(nsISVGValue* observable,
modificationType aModType)
{
WillModify(aModType);
return NS_OK;
}
NS_IMETHODIMP
nsSVGPointList::DidModifySVGObservable (nsISVGValue* observable,
modificationType aModType)
{
DidModify(aModType);
return NS_OK;
}