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>();
}
Example #2
0
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();
}
Example #3
0
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;
}
Example #7
0
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;
}
Example #8
0
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;
    }
}
Example #9
0
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());
}