#ifndef LayerUtilities_h
#define LayerUtilities_h
#if USE(ACCELERATED_COMPOSITING)
#include "FloatPoint.h"
#include "FloatPoint3D.h"
#include "FloatQuad.h"
#include "FloatSize.h"
#include "LayerCompositingThread.h"
#include "TransformationMatrix.h"
#include <algorithm>
#include <wtf/Vector.h>
namespace WebCore {
inline float determinant(const FloatSize& a, const FloatSize& b)
{
return a.width() * b.height() - a.height() * b.width();
}
inline float dot(const FloatSize& a, const FloatSize& b)
{
return a.width() * b.width() + a.height() * b.height();
}
class LayerClipEdge {
public:
LayerClipEdge(const FloatPoint& first, const FloatPoint& second)
: m_first(first)
, m_second(second)
{
}
inline bool isPointInside(const FloatPoint& p) const
{
const float epsilon = 1e-6;
return determinant(m_second - m_first, p - m_first) > -epsilon;
}
inline FloatPoint computeIntersection(const FloatPoint& p1, const FloatPoint& p2) const
{
const FloatPoint& p3 = m_first;
const FloatPoint& p4 = m_second;
float denominator = determinant(p1 - p2, p3 - p4);
FloatSize determinants(determinant(toFloatSize(p1), toFloatSize(p2)), determinant(toFloatSize(p3), toFloatSize(p4)));
FloatPoint result(
determinant(determinants, FloatSize(p1.x() - p2.x(), p3.x() - p4.x())) / denominator,
determinant(determinants, FloatSize(p1.y() - p2.y(), p3.y() - p4.y())) / denominator);
return result;
}
private:
FloatPoint m_first;
FloatPoint m_second;
};
class LayerClipPlane {
public:
LayerClipPlane(FloatPoint3D n, float d)
: m_n(n)
, m_d(d)
{
}
inline bool isPointInside(const FloatPoint3D& p) const
{
return p * m_n + m_d > 0;
}
inline FloatPoint3D computeIntersection(const FloatPoint3D& p1, const FloatPoint3D& p2) const
{
float u = (-m_d - p1 * m_n) / ((p2 - p1) * m_n);
return p1 + u * (p2 - p1);
}
protected:
FloatPoint3D m_n;
float m_d;
};
template<typename Point, size_t inlineCapacity, typename ClipPrimitive>
inline Vector<Point, inlineCapacity> intersect(const Vector<Point, inlineCapacity>& inputList, const ClipPrimitive& clipPrimitive)
{
Vector<Point, inlineCapacity> outputList;
Point s;
if (!inputList.isEmpty())
s = inputList.last();
for (typename Vector<Point, inlineCapacity>::const_iterator eIterator = inputList.begin(); eIterator != inputList.end(); ++eIterator) {
const Point& e = *eIterator;
if (clipPrimitive.isPointInside(e)) {
if (!clipPrimitive.isPointInside(s))
outputList.append(clipPrimitive.computeIntersection(s, e));
outputList.append(e);
} else if (clipPrimitive.isPointInside(s))
outputList.append(clipPrimitive.computeIntersection(s, e));
s = e;
}
return outputList;
}
template<size_t inlineCapacity>
inline Vector<FloatPoint, inlineCapacity> intersectPolygonWithRect(const Vector<FloatPoint, inlineCapacity>& subjectPolygon, const FloatRect& clipRect)
{
FloatQuad clipQuad(clipRect);
Vector<LayerClipEdge> edges;
edges.append(LayerClipEdge(clipQuad.p1(), clipQuad.p2()));
edges.append(LayerClipEdge(clipQuad.p2(), clipQuad.p3()));
edges.append(LayerClipEdge(clipQuad.p3(), clipQuad.p4()));
edges.append(LayerClipEdge(clipQuad.p4(), clipQuad.p1()));
Vector<FloatPoint> outputList = subjectPolygon;
for (Vector<LayerClipEdge>::const_iterator clipEdgeIterator = edges.begin(); clipEdgeIterator != edges.end(); ++clipEdgeIterator) {
const LayerClipEdge& clipEdge = *clipEdgeIterator;
Vector<FloatPoint> inputList = outputList;
outputList = intersect(inputList, clipEdge);
}
return outputList;
}
template<size_t inlineCapacity>
inline FloatRect boundingBox(const Vector<FloatPoint, inlineCapacity>& points)
{
if (points.isEmpty())
return FloatRect();
float xmin, xmax, ymin, ymax;
xmin = ymin = std::numeric_limits<float>::infinity();
xmax = ymax = -std::numeric_limits<float>::infinity();
for (size_t i = 0; i < points.size(); ++i) {
const FloatPoint& p = points[i];
if (p.x() < xmin)
xmin = p.x();
if (p.x() > xmax)
xmax = p.x();
if (p.y() < ymin)
ymin = p.y();
if (p.y() > ymax)
ymax = p.y();
}
return FloatRect(xmin, ymin, xmax - xmin, ymax - ymin);
}
inline FloatPoint3D computeBarycentricCoordinates(const FloatPoint& p, const FloatPoint& t1, const FloatPoint& t2, const FloatPoint& t3, bool& ok)
{
FloatSize v0 = t2 - t1;
FloatSize v1 = t3 - t1;
FloatSize v2 = p - t1;
float dot00 = dot(v0, v0);
float dot01 = dot(v0, v1);
float dot02 = dot(v0, v2);
float dot11 = dot(v1, v1);
float dot12 = dot(v1, v2);
float denominator = (dot00 * dot11 - dot01 * dot01);
ok = (denominator != 0.0);
if (!ok)
return FloatPoint3D();
float v = (dot11 * dot02 - dot01 * dot12) / denominator;
float w = (dot00 * dot12 - dot01 * dot02) / denominator;
return FloatPoint3D(1.0f - v - w, v, w);
}
inline float manhattanDistanceToViewport(const FloatPoint& p)
{
float d = 0;
if (fabsf(p.x()) > 1)
d += fabsf(p.x()) - 1;
if (fabsf(p.y()) > 1)
d += fabsf(p.y()) - 1;
return d;
}
struct UnprojectionVertex {
FloatPoint xy;
float w;
FloatSize uv;
};
inline bool compareManhattanDistanceToViewport(const UnprojectionVertex& a, const UnprojectionVertex& b)
{
return manhattanDistanceToViewport(a.xy) < manhattanDistanceToViewport(b.xy);
}
template<size_t inlineCapacity>
inline Vector<FloatPoint, inlineCapacity> unproject(LayerCompositingThread* layer, const Vector<FloatPoint, inlineCapacity>& points)
{
Vector<FloatPoint, 4> bounds = layer->transformedBounds();
Vector<float, 4> ws = layer->ws();
if (ws.isEmpty())
ws.fill(0.0f, bounds.size());
const Vector<FloatPoint>& texCoords = layer->textureCoordinates();
if (bounds.size() < 3)
return Vector<FloatPoint, inlineCapacity>();
Vector<UnprojectionVertex, 4> vertices(bounds.size());
for (size_t i = 0; i < bounds.size(); ++i) {
vertices[i].xy = bounds[i];
vertices[i].w = ws[i];
vertices[i].uv = toFloatSize(texCoords[i]);
}
std::sort(vertices.begin(), vertices.end(), compareManhattanDistanceToViewport);
Vector<FloatPoint, inlineCapacity> result;
size_t i0 = 0;
const FloatPoint& p0 = vertices[i0].xy;
float w0 = vertices[i0].w;
FloatSize uv0 = vertices[i0].uv;
for (size_t j = 0; j < points.size(); ++j) {
const FloatPoint& p = points[j];
FloatPoint texCoord;
for (size_t di = 1; di + 1 < vertices.size(); ++di) {
size_t i = (i0 + di) % vertices.size();
const FloatPoint& p1 = vertices[i].xy;
const FloatPoint& p2 = vertices[i + 1].xy;
float w1 = vertices[i].w;
float w2 = vertices[i + 1].w;
FloatSize uv1 = vertices[i].uv;
FloatSize uv2 = vertices[i + 1].uv;
bool ok;
FloatPoint3D b = computeBarycentricCoordinates(p, p0, p1, p2, ok);
if (!ok)
continue;
if (w0 && w1 && w2) {
FloatPoint3D bw(b.x() / w0, b.y() / w1, b.z() / w2);
float denominator = bw.x() + bw.y() + bw.z();
texCoord = FloatPoint::zero() + (bw.x() * uv0 + bw.y() * uv1 + bw.z() * uv2);
texCoord.setX(texCoord.x() / denominator);
texCoord.setY(texCoord.y() / denominator);
} else {
texCoord = FloatPoint::zero() + (b.x() * uv0 + b.y() * uv1 + b.z() * uv2);
}
break;
}
result.append(texCoord);
}
return result;
}
inline FloatPoint3D multVecMatrix(const TransformationMatrix& matrix, const FloatPoint3D& p, float& w)
{
FloatPoint3D result(
matrix.m41() + p.x() * matrix.m11() + p.y() * matrix.m21() + p.z() * matrix.m31(),
matrix.m42() + p.x() * matrix.m12() + p.y() * matrix.m22() + p.z() * matrix.m32(),
matrix.m43() + p.x() * matrix.m13() + p.y() * matrix.m23() + p.z() * matrix.m33());
w = matrix.m44() + p.x() * matrix.m14() + p.y() * matrix.m24() + p.z() * matrix.m34();
return result;
}
template<typename Point, size_t inlineCapacity>
inline Vector<Point, inlineCapacity> toVector(const FloatQuad& quad)
{
Vector<Point, inlineCapacity> result;
result.append(quad.p1());
result.append(quad.p2());
result.append(quad.p3());
result.append(quad.p4());
return result;
}
}
#endif // USE(ACCELERATED_COMPOSITING)
#endif // LayerUtilities_h