mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2024-11-30 01:55:39 +00:00
373 lines
8.2 KiB
C++
373 lines
8.2 KiB
C++
#ifndef LAYOUTCONTEXT_H
|
|
#define LAYOUTCONTEXT_H
|
|
|
|
#include "property.h"
|
|
#include "canvas.h"
|
|
|
|
#include <list>
|
|
#include <map>
|
|
#include <set>
|
|
|
|
namespace lunasvg {
|
|
|
|
enum class LayoutId {
|
|
Symbol,
|
|
Group,
|
|
Shape,
|
|
Mask,
|
|
ClipPath,
|
|
Marker,
|
|
LinearGradient,
|
|
RadialGradient,
|
|
Pattern,
|
|
SolidColor
|
|
};
|
|
|
|
class RenderState;
|
|
|
|
class LayoutObject {
|
|
public:
|
|
LayoutObject(LayoutId id);
|
|
virtual ~LayoutObject();
|
|
virtual void render(RenderState&) const;
|
|
virtual void apply(RenderState&) const;
|
|
virtual Rect map(const Rect&) const;
|
|
|
|
virtual const Rect& fillBoundingBox() const { return Rect::Invalid;}
|
|
virtual const Rect& strokeBoundingBox() const { return Rect::Invalid;}
|
|
|
|
bool isPaint() const { return id == LayoutId::LinearGradient || id == LayoutId::RadialGradient || id == LayoutId::Pattern || id == LayoutId::SolidColor; }
|
|
bool isHidden() const { return isPaint() || id == LayoutId::ClipPath || id == LayoutId::Mask || id == LayoutId::Marker; }
|
|
|
|
public:
|
|
LayoutId id;
|
|
};
|
|
|
|
using LayoutList = std::list<std::unique_ptr<LayoutObject>>;
|
|
|
|
class LayoutContainer : public LayoutObject {
|
|
public:
|
|
LayoutContainer(LayoutId id);
|
|
|
|
const Rect& fillBoundingBox() const;
|
|
const Rect& strokeBoundingBox() const;
|
|
|
|
LayoutObject* addChild(std::unique_ptr<LayoutObject> child);
|
|
LayoutObject* addChildIfNotEmpty(std::unique_ptr<LayoutContainer> child);
|
|
void renderChildren(RenderState& state) const;
|
|
|
|
public:
|
|
LayoutList children;
|
|
|
|
protected:
|
|
mutable Rect m_fillBoundingBox{Rect::Invalid};
|
|
mutable Rect m_strokeBoundingBox{Rect::Invalid};
|
|
};
|
|
|
|
class LayoutClipPath : public LayoutContainer {
|
|
public:
|
|
LayoutClipPath();
|
|
|
|
void apply(RenderState& state) const;
|
|
|
|
public:
|
|
Units units;
|
|
Transform transform;
|
|
const LayoutClipPath* clipper;
|
|
};
|
|
|
|
class LayoutMask : public LayoutContainer {
|
|
public:
|
|
LayoutMask();
|
|
|
|
void apply(RenderState& state) const;
|
|
|
|
public:
|
|
double x;
|
|
double y;
|
|
double width;
|
|
double height;
|
|
Units units;
|
|
Units contentUnits;
|
|
double opacity;
|
|
const LayoutMask* masker;
|
|
const LayoutClipPath* clipper;
|
|
};
|
|
|
|
class LayoutSymbol : public LayoutContainer {
|
|
public:
|
|
LayoutSymbol();
|
|
|
|
void render(RenderState& state) const;
|
|
Rect map(const Rect& rect) const;
|
|
|
|
public:
|
|
double width;
|
|
double height;
|
|
Transform transform;
|
|
Rect clip;
|
|
double opacity;
|
|
const LayoutMask* masker;
|
|
const LayoutClipPath* clipper;
|
|
};
|
|
|
|
class LayoutGroup : public LayoutContainer {
|
|
public:
|
|
LayoutGroup();
|
|
|
|
void render(RenderState& state) const;
|
|
Rect map(const Rect& rect) const;
|
|
|
|
public:
|
|
Transform transform;
|
|
double opacity;
|
|
const LayoutMask* masker;
|
|
const LayoutClipPath* clipper;
|
|
};
|
|
|
|
class LayoutMarker : public LayoutContainer {
|
|
public:
|
|
LayoutMarker();
|
|
|
|
Transform markerTransform(const Point& origin, double angle, double strokeWidth) const;
|
|
Rect markerBoundingBox(const Point& origin, double angle, double strokeWidth) const;
|
|
void renderMarker(RenderState& state, const Point& origin, double angle, double strokeWidth) const;
|
|
|
|
public:
|
|
double refX;
|
|
double refY;
|
|
Transform transform;
|
|
Angle orient;
|
|
MarkerUnits units;
|
|
Rect clip;
|
|
double opacity;
|
|
const LayoutMask* masker;
|
|
const LayoutClipPath* clipper;
|
|
};
|
|
|
|
class LayoutPattern : public LayoutContainer {
|
|
public:
|
|
LayoutPattern();
|
|
|
|
void apply(RenderState& state) const;
|
|
|
|
public:
|
|
double x;
|
|
double y;
|
|
double width;
|
|
double height;
|
|
Transform transform;
|
|
Units units;
|
|
Units contentUnits;
|
|
Rect viewBox;
|
|
PreserveAspectRatio preserveAspectRatio;
|
|
};
|
|
|
|
class LayoutGradient : public LayoutObject {
|
|
public:
|
|
LayoutGradient(LayoutId id);
|
|
|
|
public:
|
|
Transform transform;
|
|
SpreadMethod spreadMethod;
|
|
Units units;
|
|
GradientStops stops;
|
|
};
|
|
|
|
class LayoutLinearGradient : public LayoutGradient {
|
|
public:
|
|
LayoutLinearGradient();
|
|
|
|
void apply(RenderState& state) const;
|
|
|
|
public:
|
|
double x1;
|
|
double y1;
|
|
double x2;
|
|
double y2;
|
|
};
|
|
|
|
class LayoutRadialGradient : public LayoutGradient {
|
|
public:
|
|
LayoutRadialGradient();
|
|
|
|
void apply(RenderState& state) const;
|
|
|
|
public:
|
|
double cx;
|
|
double cy;
|
|
double r;
|
|
double fx;
|
|
double fy;
|
|
};
|
|
|
|
class LayoutSolidColor : public LayoutObject {
|
|
public:
|
|
LayoutSolidColor();
|
|
|
|
void apply(RenderState& state) const;
|
|
|
|
public:
|
|
Color color;
|
|
};
|
|
|
|
class FillData {
|
|
public:
|
|
FillData() = default;
|
|
|
|
void fill(RenderState& state, const Path& path) const;
|
|
|
|
public:
|
|
const LayoutObject* painter{nullptr};
|
|
Color color{Color::Transparent};
|
|
double opacity{0};
|
|
WindRule fillRule{WindRule::NonZero};
|
|
};
|
|
|
|
class StrokeData {
|
|
public:
|
|
StrokeData() = default;
|
|
|
|
void stroke(RenderState& state, const Path& path) const;
|
|
void inflate(Rect& box) const;
|
|
|
|
public:
|
|
const LayoutObject* painter{nullptr};
|
|
Color color{Color::Transparent};
|
|
double opacity{0};
|
|
double width{1};
|
|
double miterlimit{4};
|
|
LineCap cap{LineCap::Butt};
|
|
LineJoin join{LineJoin::Miter};
|
|
DashData dash;
|
|
};
|
|
|
|
class MarkerPosition {
|
|
public:
|
|
MarkerPosition(const LayoutMarker* marker, const Point& origin, double angle);
|
|
|
|
public:
|
|
const LayoutMarker* marker;
|
|
Point origin;
|
|
double angle;
|
|
};
|
|
|
|
using MarkerPositionList = std::vector<MarkerPosition>;
|
|
|
|
class MarkerData {
|
|
public:
|
|
MarkerData() = default;
|
|
|
|
void add(const LayoutMarker* marker, const Point& origin, double angle);
|
|
void render(RenderState& state) const;
|
|
void inflate(Rect& box) const;
|
|
|
|
public:
|
|
MarkerPositionList positions;
|
|
double strokeWidth{1};
|
|
};
|
|
|
|
class LayoutShape : public LayoutObject {
|
|
public:
|
|
LayoutShape();
|
|
|
|
void render(RenderState& state) const;
|
|
Rect map(const Rect& rect) const;
|
|
const Rect& fillBoundingBox() const;
|
|
const Rect& strokeBoundingBox() const;
|
|
|
|
public:
|
|
Path path;
|
|
Transform transform;
|
|
FillData fillData;
|
|
StrokeData strokeData;
|
|
MarkerData markerData;
|
|
Visibility visibility;
|
|
WindRule clipRule;
|
|
double opacity;
|
|
const LayoutMask* masker;
|
|
const LayoutClipPath* clipper;
|
|
|
|
private:
|
|
mutable Rect m_fillBoundingBox{Rect::Invalid};
|
|
mutable Rect m_strokeBoundingBox{Rect::Invalid};
|
|
};
|
|
|
|
enum class RenderMode {
|
|
Display,
|
|
Clipping
|
|
};
|
|
|
|
struct BlendInfo {
|
|
const LayoutClipPath* clipper;
|
|
const LayoutMask* masker;
|
|
double opacity;
|
|
Rect clip;
|
|
};
|
|
|
|
class RenderState {
|
|
public:
|
|
RenderState(const LayoutObject* object, RenderMode mode);
|
|
|
|
void beginGroup(RenderState& state, const BlendInfo& info);
|
|
void endGroup(RenderState& state, const BlendInfo& info);
|
|
|
|
const LayoutObject* object() const { return m_object;}
|
|
RenderMode mode() const { return m_mode; }
|
|
const Rect& objectBoundingBox() const { return m_object->fillBoundingBox(); }
|
|
|
|
public:
|
|
std::shared_ptr<Canvas> canvas;
|
|
Transform transform;
|
|
|
|
private:
|
|
const LayoutObject* m_object;
|
|
RenderMode m_mode;
|
|
};
|
|
|
|
class TreeBuilder;
|
|
class StyledElement;
|
|
class GeometryElement;
|
|
|
|
class LayoutContext {
|
|
public:
|
|
LayoutContext(const TreeBuilder* builder, LayoutSymbol* root);
|
|
|
|
Element* getElementById(const std::string& id) const;
|
|
LayoutObject* getResourcesById(const std::string& id) const;
|
|
LayoutObject* addToResourcesCache(const std::string& id, std::unique_ptr<LayoutObject> resources);
|
|
LayoutMask* getMasker(const std::string& id);
|
|
LayoutClipPath* getClipper(const std::string& id);
|
|
LayoutMarker* getMarker(const std::string& id);
|
|
LayoutObject* getPainter(const std::string& id);
|
|
|
|
FillData fillData(const StyledElement* element);
|
|
DashData dashData(const StyledElement* element);
|
|
StrokeData strokeData(const StyledElement* element);
|
|
MarkerData markerData(const GeometryElement* element, const Path& path);
|
|
|
|
void addReference(const Element* element);
|
|
void removeReference(const Element* element);
|
|
bool hasReference(const Element* element) const;
|
|
|
|
private:
|
|
const TreeBuilder* m_builder;
|
|
LayoutSymbol* m_root;
|
|
std::map<std::string, LayoutObject*> m_resourcesCache;
|
|
std::set<const Element*> m_references;
|
|
};
|
|
|
|
class LayoutBreaker {
|
|
public:
|
|
LayoutBreaker(LayoutContext* context, const Element* element);
|
|
~LayoutBreaker();
|
|
|
|
private:
|
|
LayoutContext* m_context;
|
|
const Element* m_element;
|
|
};
|
|
|
|
} // namespace lunasvg
|
|
|
|
#endif // LAYOUTCONTEXT_H
|