2018-06-15 11:25:19 -07:00
|
|
|
/**
|
2018-09-11 15:27:47 -07:00
|
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
2018-06-15 11:25:19 -07:00
|
|
|
*
|
|
|
|
* This source code is licensed under the MIT license found in the
|
|
|
|
* LICENSE file in the root directory of this source tree.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
2018-09-07 11:12:11 -07:00
|
|
|
#include <fabric/graphics/Color.h>
|
2018-07-15 16:46:31 -07:00
|
|
|
#include <fabric/graphics/Geometry.h>
|
2018-09-07 11:12:11 -07:00
|
|
|
#include <folly/Optional.h>
|
2018-10-05 11:01:08 -07:00
|
|
|
#include <array>
|
|
|
|
#include <cmath>
|
2018-06-15 11:25:19 -07:00
|
|
|
|
|
|
|
namespace facebook {
|
|
|
|
namespace react {
|
|
|
|
|
2018-06-15 11:25:28 -07:00
|
|
|
struct Transform {
|
2018-10-05 11:01:08 -07:00
|
|
|
std::array<Float, 16> matrix{
|
|
|
|
{1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}};
|
2018-06-15 11:25:28 -07:00
|
|
|
|
|
|
|
static Transform Identity() {
|
2018-09-10 16:33:48 -07:00
|
|
|
return {};
|
2018-06-15 11:25:28 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static Transform Perspective(const Float &perspective) {
|
2018-10-05 11:01:08 -07:00
|
|
|
auto transform = Transform{};
|
2018-06-15 11:25:28 -07:00
|
|
|
transform.matrix[11] = -1.0 / perspective;
|
|
|
|
return transform;
|
|
|
|
}
|
|
|
|
|
2018-10-05 11:01:08 -07:00
|
|
|
static Transform
|
|
|
|
Scale(const Float &factorX, const Float &factorY, const Float &factorZ) {
|
|
|
|
auto transform = Transform{};
|
2018-06-15 11:25:28 -07:00
|
|
|
transform.matrix[0] = factorX;
|
|
|
|
transform.matrix[5] = factorY;
|
|
|
|
transform.matrix[10] = factorZ;
|
|
|
|
return transform;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Transform Translate(const Float &x, const Float &y, const Float &z) {
|
2018-10-05 11:01:08 -07:00
|
|
|
auto transform = Transform{};
|
2018-06-15 11:25:28 -07:00
|
|
|
transform.matrix[12] = x;
|
|
|
|
transform.matrix[13] = y;
|
|
|
|
transform.matrix[14] = z;
|
|
|
|
return transform;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Transform Skew(const Float &x, const Float &y) {
|
2018-10-05 11:01:08 -07:00
|
|
|
auto transform = Transform{};
|
2018-06-15 11:25:28 -07:00
|
|
|
transform.matrix[4] = std::tan(x);
|
|
|
|
transform.matrix[1] = std::tan(y);
|
|
|
|
return transform;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Transform RotateX(const Float &radians) {
|
2018-10-05 11:01:08 -07:00
|
|
|
auto transform = Transform{};
|
2018-06-15 11:25:28 -07:00
|
|
|
transform.matrix[5] = std::cos(radians);
|
|
|
|
transform.matrix[6] = std::sin(radians);
|
|
|
|
transform.matrix[9] = -std::sin(radians);
|
|
|
|
transform.matrix[10] = std::cos(radians);
|
|
|
|
return transform;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Transform RotateY(const Float &radians) {
|
2018-10-05 11:01:08 -07:00
|
|
|
auto transform = Transform{};
|
2018-06-15 11:25:28 -07:00
|
|
|
transform.matrix[0] = std::cos(radians);
|
|
|
|
transform.matrix[2] = -std::sin(radians);
|
|
|
|
transform.matrix[8] = std::sin(radians);
|
|
|
|
transform.matrix[10] = std::cos(radians);
|
|
|
|
return transform;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Transform RotateZ(const Float &radians) {
|
2018-10-05 11:01:08 -07:00
|
|
|
auto transform = Transform{};
|
2018-06-15 11:25:28 -07:00
|
|
|
transform.matrix[0] = std::cos(radians);
|
|
|
|
transform.matrix[1] = std::sin(radians);
|
|
|
|
transform.matrix[4] = -std::sin(radians);
|
|
|
|
transform.matrix[5] = std::cos(radians);
|
|
|
|
return transform;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Transform Rotate(const Float &x, const Float &y, const Float &z) {
|
2018-10-05 11:01:08 -07:00
|
|
|
auto transform = Transform{};
|
|
|
|
if (x != 0) {
|
|
|
|
transform = transform * Transform::RotateX(x);
|
|
|
|
}
|
|
|
|
if (y != 0) {
|
|
|
|
transform = transform * Transform::RotateY(y);
|
|
|
|
}
|
|
|
|
if (z != 0) {
|
|
|
|
transform = transform * Transform::RotateZ(z);
|
|
|
|
}
|
2018-06-15 11:25:28 -07:00
|
|
|
return transform;
|
|
|
|
}
|
|
|
|
|
2018-10-05 11:01:08 -07:00
|
|
|
bool operator==(const Transform &rhs) const {
|
2018-09-10 16:33:48 -07:00
|
|
|
for (auto i = 0; i < 16; i++) {
|
2018-06-15 11:25:28 -07:00
|
|
|
if (matrix[i] != rhs.matrix[i]) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-10-05 11:01:08 -07:00
|
|
|
bool operator!=(const Transform &rhs) const {
|
2018-06-15 11:25:28 -07:00
|
|
|
return !(*this == rhs);
|
|
|
|
}
|
|
|
|
|
2018-10-05 11:01:08 -07:00
|
|
|
Transform operator*(const Transform &rhs) const {
|
2018-06-15 11:25:28 -07:00
|
|
|
if (*this == Transform::Identity()) {
|
|
|
|
return rhs;
|
|
|
|
}
|
|
|
|
|
2018-09-10 16:33:48 -07:00
|
|
|
const auto &lhs = *this;
|
2018-10-05 11:01:08 -07:00
|
|
|
auto result = Transform{};
|
|
|
|
|
|
|
|
auto lhs00 = lhs.matrix[0], lhs01 = lhs.matrix[1], lhs02 = lhs.matrix[2],
|
|
|
|
lhs03 = lhs.matrix[3], lhs10 = lhs.matrix[4], lhs11 = lhs.matrix[5],
|
|
|
|
lhs12 = lhs.matrix[6], lhs13 = lhs.matrix[7], lhs20 = lhs.matrix[8],
|
|
|
|
lhs21 = lhs.matrix[9], lhs22 = lhs.matrix[10], lhs23 = lhs.matrix[11],
|
|
|
|
lhs30 = lhs.matrix[12], lhs31 = lhs.matrix[13], lhs32 = lhs.matrix[14],
|
|
|
|
lhs33 = lhs.matrix[15];
|
|
|
|
|
|
|
|
auto rhs0 = rhs.matrix[0], rhs1 = rhs.matrix[1], rhs2 = rhs.matrix[2],
|
|
|
|
rhs3 = rhs.matrix[3];
|
|
|
|
result.matrix[0] =
|
|
|
|
rhs0 * lhs00 + rhs1 * lhs10 + rhs2 * lhs20 + rhs3 * lhs30;
|
|
|
|
result.matrix[1] =
|
|
|
|
rhs0 * lhs01 + rhs1 * lhs11 + rhs2 * lhs21 + rhs3 * lhs31;
|
|
|
|
result.matrix[2] =
|
|
|
|
rhs0 * lhs02 + rhs1 * lhs12 + rhs2 * lhs22 + rhs3 * lhs32;
|
|
|
|
result.matrix[3] =
|
|
|
|
rhs0 * lhs03 + rhs1 * lhs13 + rhs2 * lhs23 + rhs3 * lhs33;
|
|
|
|
|
|
|
|
rhs0 = rhs.matrix[4];
|
|
|
|
rhs1 = rhs.matrix[5];
|
|
|
|
rhs2 = rhs.matrix[6];
|
|
|
|
rhs3 = rhs.matrix[7];
|
|
|
|
result.matrix[4] =
|
|
|
|
rhs0 * lhs00 + rhs1 * lhs10 + rhs2 * lhs20 + rhs3 * lhs30;
|
|
|
|
result.matrix[5] =
|
|
|
|
rhs0 * lhs01 + rhs1 * lhs11 + rhs2 * lhs21 + rhs3 * lhs31;
|
|
|
|
result.matrix[6] =
|
|
|
|
rhs0 * lhs02 + rhs1 * lhs12 + rhs2 * lhs22 + rhs3 * lhs32;
|
|
|
|
result.matrix[7] =
|
|
|
|
rhs0 * lhs03 + rhs1 * lhs13 + rhs2 * lhs23 + rhs3 * lhs33;
|
|
|
|
|
|
|
|
rhs0 = rhs.matrix[8];
|
|
|
|
rhs1 = rhs.matrix[9];
|
|
|
|
rhs2 = rhs.matrix[10];
|
|
|
|
rhs3 = rhs.matrix[11];
|
|
|
|
result.matrix[8] =
|
|
|
|
rhs0 * lhs00 + rhs1 * lhs10 + rhs2 * lhs20 + rhs3 * lhs30;
|
|
|
|
result.matrix[9] =
|
|
|
|
rhs0 * lhs01 + rhs1 * lhs11 + rhs2 * lhs21 + rhs3 * lhs31;
|
|
|
|
result.matrix[10] =
|
|
|
|
rhs0 * lhs02 + rhs1 * lhs12 + rhs2 * lhs22 + rhs3 * lhs32;
|
|
|
|
result.matrix[11] =
|
|
|
|
rhs0 * lhs03 + rhs1 * lhs13 + rhs2 * lhs23 + rhs3 * lhs33;
|
|
|
|
|
|
|
|
rhs0 = rhs.matrix[12];
|
|
|
|
rhs1 = rhs.matrix[13];
|
|
|
|
rhs2 = rhs.matrix[14];
|
|
|
|
rhs3 = rhs.matrix[15];
|
|
|
|
result.matrix[12] =
|
|
|
|
rhs0 * lhs00 + rhs1 * lhs10 + rhs2 * lhs20 + rhs3 * lhs30;
|
|
|
|
result.matrix[13] =
|
|
|
|
rhs0 * lhs01 + rhs1 * lhs11 + rhs2 * lhs21 + rhs3 * lhs31;
|
|
|
|
result.matrix[14] =
|
|
|
|
rhs0 * lhs02 + rhs1 * lhs12 + rhs2 * lhs22 + rhs3 * lhs32;
|
|
|
|
result.matrix[15] =
|
|
|
|
rhs0 * lhs03 + rhs1 * lhs13 + rhs2 * lhs23 + rhs3 * lhs33;
|
2018-06-15 11:25:28 -07:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-10-05 11:01:08 -07:00
|
|
|
enum class PointerEventsMode { Auto, None, BoxNone, BoxOnly };
|
2018-06-15 11:25:19 -07:00
|
|
|
|
2018-10-05 11:01:08 -07:00
|
|
|
enum class BorderStyle { Solid, Dotted, Dashed };
|
2018-06-15 11:25:19 -07:00
|
|
|
|
2018-09-07 11:12:11 -07:00
|
|
|
template <typename T>
|
|
|
|
struct CascadedRectangleEdges {
|
|
|
|
using Counterpart = RectangleEdges<T>;
|
|
|
|
using OptionalT = folly::Optional<T>;
|
|
|
|
|
2018-10-05 11:01:08 -07:00
|
|
|
OptionalT left{};
|
|
|
|
OptionalT top{};
|
|
|
|
OptionalT right{};
|
|
|
|
OptionalT bottom{};
|
|
|
|
OptionalT start{};
|
|
|
|
OptionalT end{};
|
|
|
|
OptionalT horizontal{};
|
|
|
|
OptionalT vertical{};
|
|
|
|
OptionalT all{};
|
2018-09-07 11:12:11 -07:00
|
|
|
|
|
|
|
Counterpart resolve(bool isRTL, T defaults) const {
|
|
|
|
const auto leading = isRTL ? end : start;
|
|
|
|
const auto trailing = isRTL ? start : end;
|
2018-10-05 11:01:08 -07:00
|
|
|
const auto horizontalOrAllOrDefault =
|
|
|
|
horizontal.value_or(all.value_or(defaults));
|
|
|
|
const auto verticalOrAllOrDefault =
|
|
|
|
vertical.value_or(all.value_or(defaults));
|
|
|
|
|
|
|
|
return Counterpart{
|
|
|
|
.left = left.value_or(leading.value_or(horizontalOrAllOrDefault)),
|
|
|
|
.right = right.value_or(trailing.value_or(horizontalOrAllOrDefault)),
|
|
|
|
.top = top.value_or(verticalOrAllOrDefault),
|
|
|
|
.bottom = bottom.value_or(verticalOrAllOrDefault)};
|
2018-09-07 11:12:11 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
bool operator==(const CascadedRectangleEdges<T> &rhs) const {
|
2018-10-05 11:01:08 -07:00
|
|
|
return std::tie(
|
|
|
|
this->left,
|
|
|
|
this->top,
|
|
|
|
this->right,
|
|
|
|
this->bottom,
|
|
|
|
this->start,
|
|
|
|
this->end,
|
|
|
|
this->horizontal,
|
|
|
|
this->vertical,
|
|
|
|
this->all) ==
|
|
|
|
std::tie(
|
|
|
|
rhs.left,
|
|
|
|
rhs.top,
|
|
|
|
rhs.right,
|
|
|
|
rhs.bottom,
|
|
|
|
rhs.start,
|
|
|
|
rhs.end,
|
|
|
|
rhs.horizontal,
|
|
|
|
rhs.vertical,
|
|
|
|
rhs.all);
|
2018-09-07 11:12:11 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
bool operator!=(const CascadedRectangleEdges<T> &rhs) const {
|
|
|
|
return !(*this == rhs);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
struct CascadedRectangleCorners {
|
|
|
|
using Counterpart = RectangleCorners<T>;
|
|
|
|
using OptionalT = folly::Optional<T>;
|
|
|
|
|
2018-10-05 11:01:08 -07:00
|
|
|
OptionalT topLeft{};
|
|
|
|
OptionalT topRight{};
|
|
|
|
OptionalT bottomLeft{};
|
|
|
|
OptionalT bottomRight{};
|
|
|
|
OptionalT topStart{};
|
|
|
|
OptionalT topEnd{};
|
|
|
|
OptionalT bottomStart{};
|
|
|
|
OptionalT bottomEnd{};
|
|
|
|
OptionalT all{};
|
2018-09-07 11:12:11 -07:00
|
|
|
|
|
|
|
Counterpart resolve(bool isRTL, T defaults) const {
|
|
|
|
const auto topLeading = isRTL ? topEnd : topStart;
|
|
|
|
const auto topTrailing = isRTL ? topStart : topEnd;
|
|
|
|
const auto bottomLeading = isRTL ? bottomEnd : bottomStart;
|
|
|
|
const auto bottomTrailing = isRTL ? bottomStart : bottomEnd;
|
|
|
|
|
2018-10-05 11:01:08 -07:00
|
|
|
return Counterpart{
|
|
|
|
.topLeft =
|
|
|
|
topLeft.value_or(topLeading.value_or(all.value_or(defaults))),
|
|
|
|
.topRight =
|
|
|
|
topRight.value_or(topTrailing.value_or(all.value_or(defaults))),
|
|
|
|
.bottomLeft =
|
|
|
|
bottomLeft.value_or(topLeading.value_or(all.value_or(defaults))),
|
|
|
|
.bottomRight =
|
|
|
|
bottomRight.value_or(topTrailing.value_or(all.value_or(defaults)))};
|
2018-09-07 11:12:11 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
bool operator==(const CascadedRectangleCorners<T> &rhs) const {
|
2018-10-05 11:01:08 -07:00
|
|
|
return std::tie(
|
|
|
|
this->topLeft,
|
|
|
|
this->topRight,
|
|
|
|
this->bottomLeft,
|
|
|
|
this->bottomRight,
|
|
|
|
this->topStart,
|
|
|
|
this->topEnd,
|
|
|
|
this->bottomStart,
|
|
|
|
this->bottomEnd,
|
|
|
|
this->all) ==
|
|
|
|
std::tie(
|
|
|
|
rhs.topLeft,
|
|
|
|
rhs.topRight,
|
|
|
|
rhs.bottomLeft,
|
|
|
|
rhs.bottomRight,
|
|
|
|
rhs.topStart,
|
|
|
|
rhs.topEnd,
|
|
|
|
rhs.bottomStart,
|
|
|
|
rhs.bottomEnd,
|
|
|
|
rhs.all);
|
2018-09-07 11:12:11 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
bool operator!=(const CascadedRectangleCorners<T> &rhs) const {
|
|
|
|
return !(*this == rhs);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
using BorderWidths = RectangleEdges<Float>;
|
|
|
|
using BorderStyles = RectangleEdges<BorderStyle>;
|
|
|
|
using BorderColors = RectangleEdges<SharedColor>;
|
|
|
|
using BorderRadii = RectangleCorners<Float>;
|
|
|
|
|
|
|
|
using CascadedBorderWidths = CascadedRectangleEdges<Float>;
|
|
|
|
using CascadedBorderStyles = CascadedRectangleEdges<BorderStyle>;
|
|
|
|
using CascadedBorderColors = CascadedRectangleEdges<SharedColor>;
|
|
|
|
using CascadedBorderRadii = CascadedRectangleCorners<Float>;
|
|
|
|
|
|
|
|
struct BorderMetrics {
|
2018-10-05 11:01:08 -07:00
|
|
|
BorderColors borderColors{};
|
|
|
|
BorderWidths borderWidths{};
|
|
|
|
BorderRadii borderRadii{};
|
|
|
|
BorderStyles borderStyles{};
|
2018-09-07 11:12:11 -07:00
|
|
|
|
|
|
|
bool operator==(const BorderMetrics &rhs) const {
|
2018-10-05 11:01:08 -07:00
|
|
|
return std::tie(
|
|
|
|
this->borderColors,
|
|
|
|
this->borderWidths,
|
|
|
|
this->borderRadii,
|
|
|
|
this->borderStyles) ==
|
|
|
|
std::tie(
|
|
|
|
rhs.borderColors,
|
|
|
|
rhs.borderWidths,
|
|
|
|
rhs.borderRadii,
|
|
|
|
rhs.borderStyles);
|
2018-09-07 11:12:11 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
bool operator!=(const BorderMetrics &rhs) const {
|
|
|
|
return !(*this == rhs);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-06-15 11:25:19 -07:00
|
|
|
} // namespace react
|
|
|
|
} // namespace facebook
|