blob: 7596e65f652c69fd64fcc31d896689db6e75bd11 [file] [log] [blame]
/*
* Copyright (C) 2013 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_SVG_PROPERTIES_SVG_LIST_PROPERTY_HELPER_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_SVG_PROPERTIES_SVG_LIST_PROPERTY_HELPER_H_
#include "third_party/blink/renderer/core/svg/properties/svg_property_helper.h"
#include "third_party/blink/renderer/core/svg/svg_animation_element.h"
#include "third_party/blink/renderer/platform/bindings/exception_messages.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
namespace blink {
// This is an implementation of the SVG*List property spec:
// http://www.w3.org/TR/SVG/single-page.html#types-InterfaceSVGLengthList
template <typename Derived, typename ItemProperty>
class SVGListPropertyHelper : public SVGPropertyHelper<Derived> {
public:
typedef ItemProperty ItemPropertyType;
SVGListPropertyHelper() = default;
~SVGListPropertyHelper() override = default;
// used from Blink C++ code:
ItemPropertyType* at(uint32_t index) {
DCHECK_LT(index, values_.size());
DCHECK_EQ(values_.at(index)->OwnerList(), this);
return values_.at(index).Get();
}
const ItemPropertyType* at(uint32_t index) const {
return const_cast<SVGListPropertyHelper<Derived, ItemProperty>*>(this)->at(
index);
}
class ConstIterator {
STACK_ALLOCATED();
private:
typedef typename HeapVector<Member<ItemPropertyType>>::const_iterator
WrappedType;
public:
ConstIterator(WrappedType it) : it_(it) {}
ConstIterator& operator++() {
++it_;
return *this;
}
bool operator==(const ConstIterator& o) const { return it_ == o.it_; }
bool operator!=(const ConstIterator& o) const { return it_ != o.it_; }
ItemPropertyType* operator*() { return *it_; }
ItemPropertyType* operator->() { return *it_; }
private:
WrappedType it_;
};
ConstIterator begin() const { return ConstIterator(values_.begin()); }
ConstIterator end() const { return ConstIterator(values_.end()); }
void Append(ItemPropertyType* new_item) {
DCHECK(new_item);
values_.push_back(new_item);
new_item->SetOwnerList(this);
}
bool operator==(const Derived& other) const {
return values_ == other.values_;
}
bool operator!=(const Derived& other) const { return !(*this == other); }
bool IsEmpty() const { return !length(); }
virtual Derived* Clone() {
auto* svg_list = MakeGarbageCollected<Derived>();
svg_list->DeepCopy(static_cast<Derived*>(this));
return svg_list;
}
// SVGList*Property DOM spec:
uint32_t length() const { return values_.size(); }
void Clear();
ItemPropertyType* Initialize(ItemPropertyType*);
ItemPropertyType* GetItem(uint32_t, ExceptionState&);
ItemPropertyType* InsertItemBefore(ItemPropertyType*, uint32_t);
ItemPropertyType* RemoveItem(uint32_t, ExceptionState&);
ItemPropertyType* AppendItem(ItemPropertyType*);
ItemPropertyType* ReplaceItem(ItemPropertyType*, uint32_t, ExceptionState&);
void Trace(blink::Visitor* visitor) override {
visitor->Trace(values_);
SVGPropertyHelper<Derived>::Trace(visitor);
}
protected:
void DeepCopy(Derived*);
bool AdjustFromToListValues(Derived* from_list,
Derived* to_list,
float percentage,
AnimationMode);
String SerializeList() const;
virtual ItemPropertyType* CreatePaddingItem() const {
return MakeGarbageCollected<ItemPropertyType>();
}
private:
inline bool CheckIndexBound(uint32_t, ExceptionState&);
HeapVector<Member<ItemPropertyType>> values_;
};
template <typename Derived, typename ItemProperty>
void SVGListPropertyHelper<Derived, ItemProperty>::Clear() {
// Detach all list items as they are no longer part of this list.
for (auto& value : values_) {
DCHECK_EQ(value->OwnerList(), this);
value->SetOwnerList(nullptr);
}
values_.clear();
}
template <typename Derived, typename ItemProperty>
ItemProperty* SVGListPropertyHelper<Derived, ItemProperty>::Initialize(
ItemProperty* new_item) {
// Spec: Clears all existing current items from the list and re-initializes
// the list to hold the single item specified by the parameter.
Clear();
Append(new_item);
return new_item;
}
template <typename Derived, typename ItemProperty>
ItemProperty* SVGListPropertyHelper<Derived, ItemProperty>::GetItem(
uint32_t index,
ExceptionState& exception_state) {
if (!CheckIndexBound(index, exception_state))
return nullptr;
return at(index);
}
template <typename Derived, typename ItemProperty>
ItemProperty* SVGListPropertyHelper<Derived, ItemProperty>::InsertItemBefore(
ItemProperty* new_item,
uint32_t index) {
// Spec: If the index is greater than or equal to length, then the new item is
// appended to the end of the list.
if (index > values_.size())
index = values_.size();
// Spec: Inserts a new item into the list at the specified position. The index
// of the item before which the new item is to be inserted. The first item is
// number 0. If the index is equal to 0, then the new item is inserted at the
// front of the list.
values_.insert(index, new_item);
new_item->SetOwnerList(this);
return new_item;
}
template <typename Derived, typename ItemProperty>
ItemProperty* SVGListPropertyHelper<Derived, ItemProperty>::RemoveItem(
uint32_t index,
ExceptionState& exception_state) {
if (!CheckIndexBound(index, exception_state))
return nullptr;
DCHECK_EQ(values_.at(index)->OwnerList(), this);
ItemPropertyType* old_item = values_.at(index);
values_.EraseAt(index);
old_item->SetOwnerList(nullptr);
return old_item;
}
template <typename Derived, typename ItemProperty>
ItemProperty* SVGListPropertyHelper<Derived, ItemProperty>::AppendItem(
ItemProperty* new_item) {
// Append the value and wrapper at the end of the list.
Append(new_item);
return new_item;
}
template <typename Derived, typename ItemProperty>
ItemProperty* SVGListPropertyHelper<Derived, ItemProperty>::ReplaceItem(
ItemProperty* new_item,
uint32_t index,
ExceptionState& exception_state) {
if (!CheckIndexBound(index, exception_state))
return nullptr;
// Update the value at the desired position 'index'.
Member<ItemPropertyType>& position = values_[index];
DCHECK_EQ(position->OwnerList(), this);
position->SetOwnerList(nullptr);
position = new_item;
new_item->SetOwnerList(this);
return new_item;
}
template <typename Derived, typename ItemProperty>
bool SVGListPropertyHelper<Derived, ItemProperty>::CheckIndexBound(
uint32_t index,
ExceptionState& exception_state) {
if (index >= values_.size()) {
exception_state.ThrowDOMException(
DOMExceptionCode::kIndexSizeError,
ExceptionMessages::IndexExceedsMaximumBound("index", index,
values_.size()));
return false;
}
return true;
}
template <typename Derived, typename ItemProperty>
void SVGListPropertyHelper<Derived, ItemProperty>::DeepCopy(Derived* from) {
Clear();
for (const auto& from_value : from->values_)
Append(from_value->Clone());
}
template <typename Derived, typename ItemProperty>
bool SVGListPropertyHelper<Derived, ItemProperty>::AdjustFromToListValues(
Derived* from_list,
Derived* to_list,
float percentage,
AnimationMode mode) {
// If no 'to' value is given, nothing to animate.
uint32_t to_list_size = to_list->length();
if (!to_list_size)
return false;
// If the 'from' value is given and it's length doesn't match the 'to' value
// list length, fallback to a discrete animation.
uint32_t from_list_size = from_list->length();
if (from_list_size != to_list_size && from_list_size) {
if (percentage < 0.5) {
if (mode != kToAnimation)
DeepCopy(from_list);
} else {
DeepCopy(to_list);
}
return false;
}
DCHECK(!from_list_size || from_list_size == to_list_size);
for (uint32_t i = length(); i < to_list_size; ++i)
Append(CreatePaddingItem());
return true;
}
template <typename Derived, typename ItemProperty>
String SVGListPropertyHelper<Derived, ItemProperty>::SerializeList() const {
if (values_.IsEmpty())
return String();
StringBuilder builder;
auto it = values_.begin();
auto it_end = values_.end();
while (it != it_end) {
builder.Append((*it)->ValueAsString());
++it;
if (it != it_end)
builder.Append(' ');
}
return builder.ToString();
}
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_SVG_PROPERTIES_SVG_LIST_PROPERTY_HELPER_H_