mirror of
https://github.com/darlinghq/darling-WebCore.git
synced 2024-11-23 12:29:39 +00:00
232 lines
6.8 KiB
C++
232 lines
6.8 KiB
C++
/*
|
|
* Copyright (C) Research In Motion Limited 2010. All rights reserved.
|
|
* Copyright (C) 2018-2019 Apple Inc. All rights reserved.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public License
|
|
* along with this library; see the file COPYING.LIB. If not, write to
|
|
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
* Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "Path.h"
|
|
#include "SVGPathByteStream.h"
|
|
#include "SVGPathSeg.h"
|
|
#include "SVGPropertyList.h"
|
|
|
|
namespace WebCore {
|
|
|
|
class SVGPathSegList final : public SVGPropertyList<SVGPathSeg> {
|
|
friend class SVGAnimatedPathSegListAnimator;
|
|
friend class SVGPathSegListBuilder;
|
|
friend class SVGPathSegListSource;
|
|
|
|
using Base = SVGPropertyList<SVGPathSeg>;
|
|
using Base::Base;
|
|
|
|
public:
|
|
static Ref<SVGPathSegList> create(SVGPropertyOwner* owner, SVGPropertyAccess access)
|
|
{
|
|
return adoptRef(*new SVGPathSegList(owner, access));
|
|
}
|
|
|
|
static Ref<SVGPathSegList> create(const SVGPathSegList& other, SVGPropertyAccess access)
|
|
{
|
|
return adoptRef(*new SVGPathSegList(other, access));
|
|
}
|
|
|
|
static Ref<SVGPathSegList> create(Ref<SVGPathSeg>&& newItem)
|
|
{
|
|
return adoptRef(*new SVGPathSegList(WTFMove(newItem)));
|
|
}
|
|
|
|
SVGPathSegList& operator=(const SVGPathSegList& other)
|
|
{
|
|
pathByteStreamWillChange();
|
|
m_pathByteStream = other.pathByteStream();
|
|
return *this;
|
|
}
|
|
|
|
// Override SVGList::length() because numberOfItems() isn't virtual.
|
|
unsigned length() const { return numberOfItems(); }
|
|
|
|
unsigned numberOfItems() const
|
|
{
|
|
const_cast<SVGPathSegList*>(this)->ensureItems();
|
|
return Base::numberOfItems();
|
|
}
|
|
|
|
ExceptionOr<void> clear()
|
|
{
|
|
itemsWillChange();
|
|
return Base::clear();
|
|
}
|
|
|
|
ExceptionOr<Ref<SVGPathSeg>> getItem(unsigned index)
|
|
{
|
|
ensureItems();
|
|
return Base::getItem(index);
|
|
}
|
|
|
|
ExceptionOr<Ref<SVGPathSeg>> initialize(Ref<SVGPathSeg>&& newItem)
|
|
{
|
|
itemsWillChange();
|
|
return Base::initialize(WTFMove(newItem));
|
|
}
|
|
|
|
ExceptionOr<Ref<SVGPathSeg>> insertItemBefore(Ref<SVGPathSeg>&& newItem, unsigned index)
|
|
{
|
|
ensureItems();
|
|
itemsWillChange();
|
|
return Base::insertItemBefore(WTFMove(newItem), index);
|
|
}
|
|
|
|
ExceptionOr<Ref<SVGPathSeg>> replaceItem(Ref<SVGPathSeg>&& newItem, unsigned index)
|
|
{
|
|
ensureItems();
|
|
itemsWillChange();
|
|
return Base::replaceItem(WTFMove(newItem), index);
|
|
}
|
|
|
|
ExceptionOr<Ref<SVGPathSeg>> removeItem(unsigned index)
|
|
{
|
|
ensureItems();
|
|
itemsWillChange();
|
|
return Base::removeItem(index);
|
|
}
|
|
|
|
ExceptionOr<Ref<SVGPathSeg>> appendItem(Ref<SVGPathSeg>&& newItem)
|
|
{
|
|
ensureItems();
|
|
appendPathSegToPathByteStream(newItem);
|
|
clearPath();
|
|
return Base::appendItem(WTFMove(newItem));
|
|
}
|
|
|
|
// Override SVGList::setItem() because replaceItem() isn't virtual.
|
|
ExceptionOr<void> setItem(unsigned index, Ref<SVGPathSeg>&& newItem)
|
|
{
|
|
auto result = replaceItem(WTFMove(newItem), index);
|
|
if (result.hasException())
|
|
return result.releaseException();
|
|
return { };
|
|
}
|
|
|
|
const SVGPathByteStream& pathByteStream() const { return const_cast<SVGPathSegList*>(this)->pathByteStream(); }
|
|
SVGPathByteStream& pathByteStream()
|
|
{
|
|
ensurePathByteStream();
|
|
return m_pathByteStream;
|
|
}
|
|
|
|
bool parse(const String& value)
|
|
{
|
|
pathByteStreamWillChange();
|
|
return buildSVGPathByteStreamFromString(value, m_pathByteStream, UnalteredParsing);
|
|
}
|
|
|
|
Path path() const
|
|
{
|
|
if (!m_path)
|
|
m_path = buildPathFromByteStream(pathByteStream());
|
|
return *m_path;
|
|
}
|
|
|
|
size_t approximateMemoryCost() const
|
|
{
|
|
// This is an approximation for path memory cost since the path is parsed on demand.
|
|
size_t pathMemoryCost = (m_pathByteStream.size() / 10) * sizeof(FloatPoint);
|
|
// We need to account for the memory which is allocated by the m_path.
|
|
return m_path ? pathMemoryCost + sizeof(*m_path) : pathMemoryCost;
|
|
}
|
|
|
|
String valueAsString() const override
|
|
{
|
|
String value;
|
|
buildStringFromByteStream(pathByteStream(), value, UnalteredParsing);
|
|
return value;
|
|
}
|
|
|
|
private:
|
|
SVGPathSegList(const SVGPathSegList& other, SVGPropertyAccess access)
|
|
: Base(other.owner(), access)
|
|
, m_pathByteStream(other.pathByteStream())
|
|
{
|
|
}
|
|
|
|
// Used by appendPathSegToPathByteStream() to create a temporary SVGPathSegList with one item.
|
|
SVGPathSegList(Ref<SVGPathSeg>&& newItem)
|
|
{
|
|
append(WTFMove(newItem));
|
|
}
|
|
|
|
// Called when changing an item in the list.
|
|
void commitPropertyChange(SVGProperty* property) override
|
|
{
|
|
itemsWillChange();
|
|
Base::commitPropertyChange(property);
|
|
}
|
|
|
|
void ensureItems()
|
|
{
|
|
if (!m_items.isEmpty() || m_pathByteStream.isEmpty())
|
|
return;
|
|
buildSVGPathSegListFromByteStream(m_pathByteStream, *this, UnalteredParsing);
|
|
}
|
|
|
|
void ensurePathByteStream()
|
|
{
|
|
if (!m_pathByteStream.isEmpty() || m_items.isEmpty())
|
|
return;
|
|
buildSVGPathByteStreamFromSVGPathSegList(*this, m_pathByteStream, UnalteredParsing);
|
|
}
|
|
|
|
// Optimize appending an SVGPathSeg to the list. Instead of creating the whole
|
|
// byte stream, a temporary byte stream will be creating just for the new item
|
|
// and this temporary byte stream will be appended to m_pathByteStream.
|
|
void appendPathSegToPathByteStream(const Ref<SVGPathSeg>& item)
|
|
{
|
|
if (m_pathByteStream.isEmpty())
|
|
return;
|
|
|
|
Ref<SVGPathSegList> pathSegList = SVGPathSegList::create(item.copyRef());
|
|
SVGPathByteStream pathSegStream;
|
|
|
|
if (!buildSVGPathByteStreamFromSVGPathSegList(pathSegList, pathSegStream, UnalteredParsing, false))
|
|
return;
|
|
|
|
m_pathByteStream.append(pathSegStream);
|
|
}
|
|
|
|
void clearPathByteStream() { m_pathByteStream.clear(); }
|
|
void clearPath() { m_path = WTF::nullopt; }
|
|
|
|
void pathByteStreamWillChange()
|
|
{
|
|
clearItems();
|
|
clearPath();
|
|
}
|
|
|
|
void itemsWillChange()
|
|
{
|
|
clearPathByteStream();
|
|
clearPath();
|
|
}
|
|
|
|
SVGPathByteStream m_pathByteStream;
|
|
mutable Optional<Path> m_path;
|
|
};
|
|
|
|
}
|