static v8::Handle<v8::Value> initializeCallback(const v8::Arguments& args) { INC_STATS("DOM.SVGPointList.initialize"); SVGPointList* imp = V8SVGPointList::toNative(args.Holder()); ExceptionCode ec = 0; { bool itemOk; FloatPoint item = V8SVGPODTypeUtil::toSVGPODType<FloatPoint>(&V8SVGPoint::info, args[0], itemOk); if (UNLIKELY(!itemOk)) { ec = TYPE_MISMATCH_ERR; goto fail; } SVGList<RefPtr<SVGPODListItem<FloatPoint> > >* listImp = imp; RefPtr<SVGPODListItem<FloatPoint> > result = listImp->initialize(SVGPODListItem<FloatPoint>::copy(item), ec); if (UNLIKELY(ec)) goto fail; RefPtr<V8SVGPODTypeWrapper<FloatPoint> > wrapper = V8SVGPODTypeWrapperCreatorForList<FloatPoint>::create(result, imp->associatedAttributeName()); SVGElement* context = V8Proxy::svgContext(imp); V8Proxy::setSVGContext(wrapper.get(), context); context->svgAttributeChanged(imp->associatedAttributeName()); return toV8(wrapper.release()); } fail: V8Proxy::setDOMException(ec); return v8::Handle<v8::Value>(); }
void SVGPolyElement::parseAttribute(const QualifiedName& name, const AtomicString& value) { if (!isSupportedAttribute(name)) { SVGGeometryElement::parseAttribute(name, value); return; } if (name == SVGNames::pointsAttr) { SVGPointList newList; if (!pointsListFromSVGData(newList, value)) document().accessSVGExtensions()->reportError("Problem parsing points=\"" + value + "\""); if (SVGAnimatedProperty* wrapper = SVGAnimatedProperty::lookupWrapper<SVGPolyElement, SVGAnimatedPointList>(this, pointsPropertyInfo())) static_cast<SVGAnimatedPointList*>(wrapper)->detachListWrappers(newList.size()); m_points.value = newList; return; } if (SVGLangSpace::parseAttribute(name, value)) return; if (SVGExternalResourcesRequired::parseAttribute(name, value)) return; ASSERT_NOT_REACHED(); }
nsresult SVGPointList::SetValueFromString(const nsAString& aValue) { // The spec says that the list is parsed and accepted up to the first error // encountered, so we must call CopyFrom even if an error occurs. We still // want to throw any error code from setAttribute if there's a problem // though, so we must take care to return any error code. nsresult rv = NS_OK; SVGPointList temp; nsCharSeparatedTokenizerTemplate<IsSVGWhitespace> tokenizer(aValue, ',', nsCharSeparatedTokenizer::SEPARATOR_OPTIONAL); while (tokenizer.hasMoreTokens()) { const nsAString& token = tokenizer.nextToken(); RangedPtr<const PRUnichar> iter = SVGContentUtils::GetStartRangedPtr(token); const RangedPtr<const PRUnichar> end = SVGContentUtils::GetEndRangedPtr(token); float x; if (!SVGContentUtils::ParseNumber(iter, end, x)) { rv = NS_ERROR_DOM_SYNTAX_ERR; break; } float y; if (iter == end) { if (!tokenizer.hasMoreTokens() || !SVGContentUtils::ParseNumber(tokenizer.nextToken(), y)) { rv = NS_ERROR_DOM_SYNTAX_ERR; break; } } else { // It's possible for the token to be 10-30 which has // no separator but needs to be parsed as 10, -30 const nsAString& leftOver = Substring(iter.get(), end.get()); if (leftOver[0] != '-' || !SVGContentUtils::ParseNumber(leftOver, y)) { rv = NS_ERROR_DOM_SYNTAX_ERR; break; } } temp.AppendItem(SVGPoint(x, y)); } if (tokenizer.separatorAfterCurrentToken()) { rv = NS_ERROR_DOM_SYNTAX_ERR; // trailing comma } nsresult rv2 = CopyFrom(temp); if (NS_FAILED(rv2)) { return rv2; // prioritize OOM error code over syntax errors } return rv; }
void SVGPointList::add(SVGPropertyBase* other, SVGElement* contextElement) { SVGPointList* otherList = toSVGPointList(other); if (length() != otherList->length()) return; for (size_t i = 0; i < length(); ++i) at(i)->setValue(at(i)->value() + otherList->at(i)->value()); }
void SVGPointList::calculateAnimatedValue(SVGAnimationElement* animationElement, float percentage, unsigned repeatCount, SVGPropertyBase* fromValue, SVGPropertyBase* toValue, SVGPropertyBase* toAtEndOfDurationValue, SVGElement* contextElement) { SVGPointList* fromList = toSVGPointList(fromValue); SVGPointList* toList = toSVGPointList(toValue); SVGPointList* toAtEndOfDurationList = toSVGPointList(toAtEndOfDurationValue); size_t fromPointListSize = fromList->length(); size_t toPointListSize = toList->length(); size_t toAtEndOfDurationListSize = toAtEndOfDurationList->length(); if (!adjustFromToListValues(fromList, toList, percentage, animationElement->getAnimationMode())) return; for (size_t i = 0; i < toPointListSize; ++i) { float animatedX = at(i)->x(); float animatedY = at(i)->y(); FloatPoint effectiveFrom; if (fromPointListSize) effectiveFrom = fromList->at(i)->value(); FloatPoint effectiveTo = toList->at(i)->value(); FloatPoint effectiveToAtEnd; if (i < toAtEndOfDurationListSize) effectiveToAtEnd = toAtEndOfDurationList->at(i)->value(); animationElement->animateAdditiveNumber(percentage, repeatCount, effectiveFrom.x(), effectiveTo.x(), effectiveToAtEnd.x(), animatedX); animationElement->animateAdditiveNumber(percentage, repeatCount, effectiveFrom.y(), effectiveTo.y(), effectiveToAtEnd.y(), animatedY); at(i)->setValue(FloatPoint(animatedX, animatedY)); } }
nsresult SVGAnimatedPointList::SetBaseValueString(const nsAString& aValue) { SVGPointList newBaseValue; // The spec says that the point data is parsed and accepted up to the first // error encountered, so we don't return early if an error occurs. However, // we do want to throw any error code from setAttribute if there's a problem. nsresult rv = newBaseValue.SetValueFromString(aValue); // We must send these notifications *before* changing mBaseVal! Our baseVal's // DOM wrapper list may have to remove DOM items from itself, and any removed // DOM items need to copy their internal counterpart's values *before* we // change them. See the comments in // DOMSVGPointList::InternalListWillChangeTo(). DOMSVGPointList *baseValWrapper = DOMSVGPointList::GetDOMWrapperIfExists(GetBaseValKey()); if (baseValWrapper) { baseValWrapper->InternalListWillChangeTo(newBaseValue); } DOMSVGPointList* animValWrapper = nullptr; if (!IsAnimating()) { // DOM anim val wraps our base val too! animValWrapper = DOMSVGPointList::GetDOMWrapperIfExists(GetAnimValKey()); if (animValWrapper) { animValWrapper->InternalListWillChangeTo(newBaseValue); } } // Only now may we modify mBaseVal! // We don't need to call DidChange* here - we're only called by // nsSVGElement::ParseAttribute under Element::SetAttr, // which takes care of notifying. nsresult rv2 = mBaseVal.CopyFrom(newBaseValue); if (NS_FAILED(rv2)) { // Attempting to increase mBaseVal's length failed (mBaseVal is left // unmodified). We MUST keep any DOM wrappers in sync: if (baseValWrapper) { baseValWrapper->InternalListWillChangeTo(mBaseVal); } if (animValWrapper) { animValWrapper->InternalListWillChangeTo(mBaseVal); } return rv2; } return rv; }
bool SVGPointList::createAnimated(const SVGPointList& fromList, const SVGPointList& toList, SVGPointList& resultList, float progress) { unsigned itemCount = fromList.size(); if (!itemCount || itemCount != toList.size()) return false; for (unsigned n = 0; n < itemCount; ++n) { const FloatPoint& from = fromList.at(n); const FloatPoint& to = toList.at(n); FloatPoint segment = FloatPoint(adjustAnimatedValue(from.x(), to.x(), progress), adjustAnimatedValue(from.y(), to.y(), progress)); resultList.append(segment); } return true; }
void DOMSVGPointList::InternalListWillChangeTo(const SVGPointList& aNewValue) { // When the number of items in our internal counterpart changes, we MUST stay // in sync. Everything in the scary comment in // DOMSVGLengthList::InternalBaseValListWillChangeTo applies here too! PRUint32 oldLength = mItems.Length(); PRUint32 newLength = aNewValue.Length(); if (newLength > DOMSVGPoint::MaxListIndex()) { // It's safe to get out of sync with our internal list as long as we have // FEWER items than it does. newLength = DOMSVGPoint::MaxListIndex(); } // If our length will decrease, notify the items that will be removed: for (PRUint32 i = newLength; i < oldLength; ++i) { if (mItems[i]) { mItems[i]->RemovingFromList(); } } if (!mItems.SetLength(newLength)) { // We silently ignore SetLength OOM failure since being out of sync is safe // so long as we have *fewer* items than our internal list. mItems.Clear(); return; } // If our length has increased, null out the new pointers: for (PRUint32 i = oldLength; i < newLength; ++i) { mItems[i] = nsnull; } }
bool pointsListFromSVGData(SVGPointList& pointsList, const String& points) { if (points.isEmpty()) return true; const UChar* cur = points.characters(); const UChar* end = cur + points.length(); skipOptionalSVGSpaces(cur, end); bool delimParsed = false; while (cur < end) { delimParsed = false; float xPos = 0.0f; if (!parseNumber(cur, end, xPos)) return false; float yPos = 0.0f; if (!parseNumber(cur, end, yPos, false)) return false; skipOptionalSVGSpaces(cur, end); if (cur < end && *cur == ',') { delimParsed = true; cur++; } skipOptionalSVGSpaces(cur, end); pointsList.append(FloatPoint(xPos, yPos)); } return cur == end && !delimParsed; }
static bool genericParsePointsList(SVGPointList& pointsList, const CharType*& ptr, const CharType* end) { skipOptionalSVGSpaces(ptr, end); bool delimParsed = false; while (ptr < end) { delimParsed = false; float xPos = 0.0f; if (!parseNumber(ptr, end, xPos)) return false; float yPos = 0.0f; if (!parseNumber(ptr, end, yPos, false)) return false; skipOptionalSVGSpaces(ptr, end); if (ptr < end && *ptr == ',') { delimParsed = true; ptr++; } skipOptionalSVGSpaces(ptr, end); pointsList.append(FloatPoint(xPos, yPos)); } return ptr == end && !delimParsed; }
SVGPropertyBase* SVGPointListInterpolationType::appliedSVGValue( const InterpolableValue& interpolableValue, const NonInterpolableValue*) const { SVGPointList* result = SVGPointList::create(); const InterpolableList& list = toInterpolableList(interpolableValue); DCHECK_EQ(list.length() % 2, 0U); for (size_t i = 0; i < list.length(); i += 2) { FloatPoint point = FloatPoint(toInterpolableNumber(list.get(i))->value(), toInterpolableNumber(list.get(i + 1))->value()); result->append(SVGPoint::create(point)); } return result; }
static v8::Handle<v8::Value> clearCallback(const v8::Arguments& args) { INC_STATS("DOM.SVGPointList.clear"); SVGPointList* imp = V8SVGPointList::toNative(args.Holder()); ExceptionCode ec = 0; { imp->clear(ec); if (UNLIKELY(ec)) goto fail; SVGElement* context = V8Proxy::svgContext(imp); context->svgAttributeChanged(imp->associatedAttributeName()); return v8::Handle<v8::Value>(); } fail: V8Proxy::setDOMException(ec); return v8::Handle<v8::Value>(); }
nsresult SVGPointList::CopyFrom(const SVGPointList& rhs) { if (!SetCapacity(rhs.Length())) { // Yes, we do want fallible alloc here return NS_ERROR_OUT_OF_MEMORY; } mItems = rhs.mItems; return NS_OK; }
static v8::Handle<v8::Value> removeItemCallback(const v8::Arguments& args) { INC_STATS("DOM.SVGPointList.removeItem"); SVGPointList* imp = V8SVGPointList::toNative(args.Holder()); ExceptionCode ec = 0; { EXCEPTION_BLOCK(unsigned, index, toUInt32(args[0])); SVGList<RefPtr<SVGPODListItem<FloatPoint> > >* listImp = imp; RefPtr<SVGPODListItem<FloatPoint> > result = listImp->removeItem(index, ec); if (UNLIKELY(ec)) goto fail; RefPtr<V8SVGPODTypeWrapper<FloatPoint> > wrapper = V8SVGPODTypeWrapperCreatorForList<FloatPoint>::create(result, imp->associatedAttributeName()); SVGElement* context = V8Proxy::svgContext(imp); V8Proxy::setSVGContext(wrapper.get(), context); context->svgAttributeChanged(imp->associatedAttributeName()); return toV8(wrapper.release()); } fail: V8Proxy::setDOMException(ec); return v8::Handle<v8::Value>(); }
void SVGPolyElement::parseMappedAttribute(Attribute* attr) { const AtomicString& value = attr->value(); if (attr->name() == SVGNames::pointsAttr) { SVGPointList newList; if (!pointsListFromSVGData(newList, value)) document()->accessSVGExtensions()->reportError("Problem parsing points=\"" + value + "\""); if (SVGAnimatedListPropertyTearOff<SVGPointList>* list = m_animatablePointsList.get()) list->detachListWrappers(newList.size()); m_points.value = newList; } else { if (SVGTests::parseMappedAttribute(attr)) return; if (SVGLangSpace::parseMappedAttribute(attr)) return; if (SVGExternalResourcesRequired::parseMappedAttribute(attr)) return; SVGStyledTransformableElement::parseMappedAttribute(attr); } }
void DOMSVGPointList::InternalListWillChangeTo(const SVGPointList& aNewValue) { // When the number of items in our internal counterpart changes, we MUST stay // in sync. Everything in the scary comment in // DOMSVGLengthList::InternalBaseValListWillChangeTo applies here too! uint32_t oldLength = mItems.Length(); uint32_t newLength = aNewValue.Length(); if (newLength > nsISVGPoint::MaxListIndex()) { // It's safe to get out of sync with our internal list as long as we have // FEWER items than it does. newLength = nsISVGPoint::MaxListIndex(); } RefPtr<DOMSVGPointList> kungFuDeathGrip; if (newLength < oldLength) { // RemovingFromList() might clear last reference to |this|. // Retain a temporary reference to keep from dying before returning. kungFuDeathGrip = this; } // If our length will decrease, notify the items that will be removed: for (uint32_t i = newLength; i < oldLength; ++i) { if (mItems[i]) { mItems[i]->RemovingFromList(); } } if (!mItems.SetLength(newLength, fallible)) { // We silently ignore SetLength OOM failure since being out of sync is safe // so long as we have *fewer* items than our internal list. mItems.Clear(); return; } // If our length has increased, null out the new pointers: for (uint32_t i = oldLength; i < newLength; ++i) { mItems[i] = nullptr; } }
nsresult SVGPointList::SetValueFromString(const nsAString& aValue) { // The spec says that the list is parsed and accepted up to the first error // encountered, so we must call CopyFrom even if an error occurs. We still // want to throw any error code from setAttribute if there's a problem // though, so we must take care to return any error code. nsresult rv = NS_OK; SVGPointList temp; nsCharSeparatedTokenizerTemplate<IsSVGWhitespace> tokenizer(aValue, ',', nsCharSeparatedTokenizer::SEPARATOR_OPTIONAL); nsAutoCString str1, str2; // outside loop to minimize memory churn while (tokenizer.hasMoreTokens()) { CopyUTF16toUTF8(tokenizer.nextToken(), str1); const char *token1 = str1.get(); if (*token1 == '\0') { rv = NS_ERROR_DOM_SYNTAX_ERR; break; } char *end; float x = float(PR_strtod(token1, &end)); if (end == token1 || !NS_finite(x)) { rv = NS_ERROR_DOM_SYNTAX_ERR; break; } const char *token2; if (*end == '-') { // It's possible for the token to be 10-30 which has // no separator but needs to be parsed as 10, -30 token2 = end; } else { if (!tokenizer.hasMoreTokens()) { rv = NS_ERROR_DOM_SYNTAX_ERR; break; } CopyUTF16toUTF8(tokenizer.nextToken(), str2); token2 = str2.get(); if (*token2 == '\0') { rv = NS_ERROR_DOM_SYNTAX_ERR; break; } } float y = float(PR_strtod(token2, &end)); if (*end != '\0' || !NS_finite(y)) { rv = NS_ERROR_DOM_SYNTAX_ERR; break; } temp.AppendItem(SVGPoint(x, y)); } if (tokenizer.lastTokenEndedWithSeparator()) { rv = NS_ERROR_DOM_SYNTAX_ERR; // trailing comma } nsresult rv2 = CopyFrom(temp); if (NS_FAILED(rv2)) { return rv2; // prioritize OOM error code over syntax errors } return rv; }
static v8::Handle<v8::Value> numberOfItemsAttrGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info) { INC_STATS("DOM.SVGPointList.numberOfItems._get"); SVGPointList* imp = V8SVGPointList::toNative(info.Holder()); return v8::Integer::NewFromUnsigned(imp->numberOfItems()); }