blob: 0f4f5bf859865cc5d4923d4824dcb365f50a20da [file] [log] [blame]
/*
* Copyright 2022 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef skgpu_graphite_geom_Geometry_DEFINED
#define skgpu_graphite_geom_Geometry_DEFINED
#include "include/core/SkVertices.h"
#include "src/core/SkVerticesPriv.h"
#include "src/gpu/graphite/geom/Rect.h"
#include "src/gpu/graphite/geom/Shape.h"
#include "src/gpu/graphite/geom/SubRunData.h"
namespace skgpu::graphite {
/**
* Geometry is a container that can house Shapes, SkVertices, and text SubRuns.
* TODO - Add unit tests for Geometry.
*/
class Geometry {
public:
enum class Type : uint8_t {
kEmpty, kShape, kVertices, kSubRun
};
Geometry() {}
explicit Geometry(const Shape& shape) { this->setShape(shape); }
explicit Geometry(const SubRunData& subrun) { this->setSubRun(subrun); }
explicit Geometry(sk_sp<SkVertices> vertices) { this->setVertices(vertices); }
~Geometry() { this->setType(Type::kEmpty); }
Geometry& operator=(Geometry&& geom) {
if (this != &geom) {
switch (geom.type()) {
case Type::kEmpty:
this->setType(Type::kEmpty);
break;
case Type::kShape:
this->setShape(geom.shape());
geom.setType(Type::kEmpty);
break;
case Type::kVertices:
this->setVertices(std::move(geom.fVertices));
geom.setType(Type::kEmpty);
break;
case Type::kSubRun:
this->setSubRun(geom.subRunData());
geom.setType(Type::kEmpty);
break;
}
}
return *this;
}
Geometry& operator=(const Geometry& geom) {
switch (geom.type()) {
case Type::kEmpty: this->setType(Type::kEmpty); break;
case Type::kShape: this->setShape(geom.shape()); break;
case Type::kSubRun: this->setSubRun(geom.subRunData()); break;
case Type::kVertices: this->setVertices(geom.fVertices); break;
default: break;
}
return *this;
}
Geometry(const Geometry& geom) {
*this = geom;
}
void setShape(const Shape& shape) {
if (fType == Type::kShape) {
fShape = shape;
} else {
this->setType(Type::kShape);
new (&fShape) Shape(shape);
}
}
void setSubRun(const SubRunData& subRun) {
if (fType == Type::kSubRun) {
fSubRunData = subRun;
} else {
this->setType(Type::kSubRun);
new (&fSubRunData) SubRunData(subRun);
}
}
void setVertices(sk_sp<SkVertices> vertices) {
if (fType == Type::kVertices) {
fVertices = std::move(vertices);
} else {
this->setType(Type::kVertices);
new (&fVertices) sk_sp<SkVertices>(std::move(vertices));
}
}
const Shape& shape() const { SkASSERT(this->isShape()); return fShape; }
const SubRunData& subRunData() const { SkASSERT(this->isSubRun()); return fSubRunData; }
const SkVertices* vertices() const { SkASSERT(this->isVertices()); return fVertices.get(); }
sk_sp<SkVertices> refVertices() const {
SkASSERT(this->isVertices());
return fVertices;
}
Rect bounds() const {
switch (fType) {
case Type::kEmpty: return Rect(0, 0, 0, 0);
case Type::kShape: return fShape.bounds();
case Type::kVertices: return fVertices->bounds();
case Type::kSubRun: return fSubRunData.bounds();
}
SkUNREACHABLE;
}
Type type() const { return fType; }
bool isShape() const { return fType == Type::kShape; }
bool isVertices() const { return fType == Type::kVertices; }
bool isSubRun() const { return fType == Type::kSubRun; }
bool isEmpty() const {
return fType == (Type::kEmpty) || (this->isShape() && this->shape().isEmpty());
}
private:
void setType(Type type) {
if (this->isShape() && type != Type::kShape) {
fShape.~Shape();
} else if (this->isSubRun() && type != Type::kSubRun) {
fSubRunData.~SubRunData();
} else if (this->isVertices() && type != Type::kVertices) {
fVertices.~sk_sp<SkVertices>();
}
fType = type;
}
Type fType = Type::kEmpty;
union {
Shape fShape;
SubRunData fSubRunData;
sk_sp<SkVertices> fVertices;
};
};
} // namespace skgpu::graphite
#endif // skgpu_graphite_geom_Geometry_DEFINED