blob: 227b0ff492d15d15dd01ddec36fa5c7324d319f4 [file] [log] [blame]
/*
* Copyright (C) 2012, 2013 Adobe Systems Incorporated. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “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 HOLDER 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.
*/
#pragma once
#include "BasicShapes.h"
#include "OffsetRotation.h"
#include "Path.h"
#include "RenderStyleConstants.h"
#include <wtf/RefCounted.h>
#include <wtf/TypeCasts.h>
#include <wtf/text/WTFString.h>
namespace WebCore {
class SVGElement;
class PathOperation : public RefCounted<PathOperation> {
public:
enum OperationType {
Reference,
Shape,
Box,
Ray
};
virtual ~PathOperation() = default;
virtual bool operator==(const PathOperation&) const = 0;
bool operator!=(const PathOperation& o) const { return !(*this == o); }
OperationType type() const { return m_type; }
bool isSameType(const PathOperation& o) const { return o.type() == m_type; }
protected:
explicit PathOperation(OperationType type)
: m_type(type)
{
}
OperationType m_type;
};
class ReferencePathOperation final : public PathOperation {
public:
static Ref<ReferencePathOperation> create(const String& url, const AtomString& fragment, const RefPtr<SVGElement>);
const String& url() const { return m_url; }
const AtomString& fragment() const { return m_fragment; }
const SVGElement* element() const;
private:
bool operator==(const PathOperation& other) const override
{
if (!isSameType(other))
return false;
auto& referenceClip = downcast<ReferencePathOperation>(other);
return m_url == referenceClip.m_url;
}
ReferencePathOperation(const String& url, const AtomString& fragment, const RefPtr<SVGElement>);
String m_url;
AtomString m_fragment;
RefPtr<SVGElement> m_element;
};
class ShapePathOperation final : public PathOperation {
public:
static Ref<ShapePathOperation> create(Ref<BasicShape>&& shape)
{
return adoptRef(*new ShapePathOperation(WTFMove(shape)));
}
const BasicShape& basicShape() const { return m_shape; }
WindRule windRule() const { return m_shape.get().windRule(); }
const Path& pathForReferenceRect(const FloatRect& boundingRect) const { return m_shape.get().path(boundingRect); }
void setReferenceBox(CSSBoxType referenceBox) { m_referenceBox = referenceBox; }
CSSBoxType referenceBox() const { return m_referenceBox; }
private:
bool operator==(const PathOperation& other) const override
{
if (!isSameType(other))
return false;
auto& shapeClip = downcast<ShapePathOperation>(other);
return m_referenceBox == shapeClip.referenceBox()
&& (m_shape.ptr() == shapeClip.m_shape.ptr() || m_shape.get() == shapeClip.m_shape.get());
}
explicit ShapePathOperation(Ref<BasicShape>&& shape)
: PathOperation(Shape)
, m_shape(WTFMove(shape))
, m_referenceBox(CSSBoxType::BoxMissing)
{
}
Ref<BasicShape> m_shape;
CSSBoxType m_referenceBox;
};
class BoxPathOperation final : public PathOperation {
public:
static Ref<BoxPathOperation> create(CSSBoxType referenceBox)
{
return adoptRef(*new BoxPathOperation(referenceBox));
}
const Path pathForReferenceRect(const FloatRoundedRect& boundingRect) const
{
Path path;
path.addRoundedRect(boundingRect);
return path;
}
void setPathForReferenceRect(const FloatRoundedRect& boundingRect)
{
m_path.clear();
m_path.addRoundedRect(boundingRect);
}
const Path getPath() const { return m_path; }
CSSBoxType referenceBox() const { return m_referenceBox; }
private:
bool operator==(const PathOperation& other) const override
{
if (!isSameType(other))
return false;
auto& boxClip = downcast<BoxPathOperation>(other);
return m_referenceBox == boxClip.m_referenceBox;
}
explicit BoxPathOperation(CSSBoxType referenceBox)
: PathOperation(Box)
, m_referenceBox(referenceBox)
{
}
Path m_path;
CSSBoxType m_referenceBox;
};
class RayPathOperation final : public PathOperation {
public:
enum class Size {
ClosestSide,
ClosestCorner,
FarthestSide,
FarthestCorner,
Sides
};
static Ref<RayPathOperation> create(float angle, Size size, bool isContaining)
{
return adoptRef(*new RayPathOperation(angle, size, isContaining));
}
float angle() const { return m_angle; }
Size size() const { return m_size; }
bool isContaining() const { return m_isContaining; }
bool canBlend(const RayPathOperation& other) const
{
// Two rays can only be blended if they have the same size and are both containing.
return m_size == other.m_size && m_isContaining == other.m_isContaining;
}
Ref<RayPathOperation> blend(const RayPathOperation& to, const BlendingContext& context) const
{
return RayPathOperation::create(WebCore::blend(m_angle, to.m_angle, context), m_size, m_isContaining);
}
const Path pathForReferenceRect(const FloatRect& elementRect, const FloatPoint& anchor, const OffsetRotation rotation) const;
double lengthForPath() const;
double lengthForContainPath(const FloatRect& elementRect, double computedPathLength, const FloatPoint& anchor, const OffsetRotation rotation) const;
void setContainingBlockReferenceRect(const FloatRect& boundingRect)
{
m_containingBlockBoundingRect = boundingRect;
}
void setStartingPosition(const FloatPoint& position)
{
m_position = position;
}
private:
bool operator==(const PathOperation& other) const override
{
if (!isSameType(other))
return false;
auto& otherCasted = downcast<RayPathOperation>(other);
return m_angle == otherCasted.m_angle
&& m_size == otherCasted.m_size
&& m_isContaining == otherCasted.m_isContaining;
}
RayPathOperation(float angle, Size size, bool isContaining)
: PathOperation(Ray)
, m_angle(angle)
, m_size(size)
, m_isContaining(isContaining)
{
}
float m_angle { 0 };
Size m_size;
bool m_isContaining { false };
FloatRect m_containingBlockBoundingRect;
FloatPoint m_position;
};
} // namespace WebCore
#define SPECIALIZE_TYPE_TRAITS_CLIP_PATH_OPERATION(ToValueTypeName, predicate) \
SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::ToValueTypeName) \
static bool isType(const WebCore::PathOperation& operation) { return operation.type() == WebCore::predicate; } \
SPECIALIZE_TYPE_TRAITS_END()
SPECIALIZE_TYPE_TRAITS_CLIP_PATH_OPERATION(ReferencePathOperation, PathOperation::Reference)
SPECIALIZE_TYPE_TRAITS_CLIP_PATH_OPERATION(ShapePathOperation, PathOperation::Shape)
SPECIALIZE_TYPE_TRAITS_CLIP_PATH_OPERATION(BoxPathOperation, PathOperation::Box)
SPECIALIZE_TYPE_TRAITS_CLIP_PATH_OPERATION(RayPathOperation, PathOperation::Ray)