This commit is contained in:
Yamozha
2021-04-02 02:24:13 +03:00
parent c23950b545
commit 7256d79e2c
31493 changed files with 3036630 additions and 0 deletions

View File

@ -0,0 +1,123 @@
load("@fbsource//tools/build_defs/apple:flag_defs.bzl", "get_preprocessor_flags_for_build_mode")
load(
"//tools/build_defs/oss:rn_defs.bzl",
"ANDROID",
"APPLE",
"CXX",
"fb_xplat_cxx_test",
"get_apple_compiler_flags",
"get_apple_inspector_flags",
"rn_xplat_cxx_library",
"subdir_glob",
)
APPLE_COMPILER_FLAGS = get_apple_compiler_flags()
rn_xplat_cxx_library(
name = "graphics",
srcs = glob(
[
"*.cpp",
],
),
headers = subdir_glob(
[
("", "*.h"),
],
prefix = "",
),
header_namespace = "",
exported_headers = subdir_glob(
[
("", "*.h"),
],
prefix = "react/graphics",
),
compiler_flags = [
"-fexceptions",
"-frtti",
"-std=c++14",
"-Wall",
],
cxx_exported_headers = subdir_glob(
[
("platform/cxx", "**/*.h"),
],
prefix = "react/graphics",
),
cxx_srcs = glob(
[
"platform/cxx/**/*.cpp",
],
),
fbandroid_exported_headers = subdir_glob(
[
("platform/cxx", "**/*.h"),
],
prefix = "react/graphics",
),
fbandroid_srcs = glob(
[
"platform/cxx/**/*.cpp",
],
),
fbobjc_compiler_flags = APPLE_COMPILER_FLAGS,
fbobjc_labels = ["supermodule:ios/default/public.react_native.infra"],
fbobjc_preprocessor_flags = get_preprocessor_flags_for_build_mode() + get_apple_inspector_flags(),
force_static = True,
ios_deps = [
"//xplat/js:RCTImage",
"//xplat/js/react-native-github:RCTCxxBridge",
],
ios_exported_headers = subdir_glob(
[
("platform/ios", "*.h"),
],
prefix = "react/graphics",
),
ios_frameworks = [
"$SDKROOT/System/Library/Frameworks/CoreGraphics.framework",
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
"$SDKROOT/System/Library/Frameworks/UIKit.framework",
],
ios_srcs = glob(
[
"platform/ios/**/*.cpp",
"platform/ios/**/*.mm",
],
),
macosx_tests_override = [],
platforms = (ANDROID, APPLE, CXX),
preprocessor_flags = [
"-DLOG_TAG=\"ReactNative\"",
"-DWITH_FBSYSTRACE=1",
],
tests = [":tests"],
visibility = ["PUBLIC"],
deps = [
"//xplat/fbsystrace:fbsystrace",
"//xplat/folly:headers_only",
"//xplat/folly:memory",
"//xplat/folly:molly",
"//xplat/third-party/glog:glog",
],
)
fb_xplat_cxx_test(
name = "tests",
srcs = glob(["tests/**/*.cpp"]),
headers = glob(["tests/**/*.h"]),
compiler_flags = [
"-fexceptions",
"-frtti",
"-std=c++14",
"-Wall",
],
contacts = ["oncall+react_native@xmail.facebook.com"],
platforms = (ANDROID, APPLE, CXX),
deps = [
":graphics",
"//xplat/folly:molly",
"//xplat/third-party/gmock:gtest",
],
)

View File

@ -0,0 +1,21 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
namespace facebook {
namespace react {
struct ColorComponents {
float red{0};
float green{0};
float blue{0};
float alpha{0};
};
} // namespace react
} // namespace facebook

View File

@ -0,0 +1,307 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <algorithm>
#include <functional>
#include <tuple>
#include <folly/Hash.h>
#include <react/graphics/Float.h>
namespace facebook {
namespace react {
/*
* Point
*/
struct Point {
Float x{0};
Float y{0};
Point &operator+=(const Point &point) {
x += point.x;
y += point.y;
return *this;
}
Point &operator-=(const Point &point) {
x -= point.x;
y -= point.y;
return *this;
}
Point &operator*=(const Point &point) {
x *= point.x;
y *= point.y;
return *this;
}
friend Point operator+(Point lhs, const Point &rhs) {
return lhs += rhs;
}
friend Point operator-(Point lhs, const Point &rhs) {
return lhs -= rhs;
}
bool operator==(const Point &rhs) const {
return std::tie(this->x, this->y) == std::tie(rhs.x, rhs.y);
}
bool operator!=(const Point &rhs) const {
return !(*this == rhs);
}
};
struct Vector {
Float x{0};
Float y{0};
Float z{0};
Float w{0};
};
/*
* Size
*/
struct Size {
Float width{0};
Float height{0};
Size &operator+=(const Point &point) {
width += point.x;
height += point.y;
return *this;
}
Size &operator*=(const Point &point) {
width *= point.x;
height *= point.y;
return *this;
}
bool operator==(const Size &rhs) const {
return std::tie(this->width, this->height) ==
std::tie(rhs.width, rhs.height);
}
bool operator!=(const Size &rhs) const {
return !(*this == rhs);
}
};
/*
* Rect: Point and Size
*/
struct Rect {
Point origin{0, 0};
Size size{0, 0};
bool operator==(const Rect &rhs) const {
return std::tie(this->origin, this->size) == std::tie(rhs.origin, rhs.size);
}
bool operator!=(const Rect &rhs) const {
return !(*this == rhs);
}
Float getMaxX() const {
return size.width > 0 ? origin.x + size.width : origin.x;
}
Float getMaxY() const {
return size.height > 0 ? origin.y + size.height : origin.y;
}
Float getMinX() const {
return size.width >= 0 ? origin.x : origin.x + size.width;
}
Float getMinY() const {
return size.height >= 0 ? origin.y : origin.y + size.height;
}
Float getMidX() const {
return origin.x + size.width / 2;
}
Float getMidY() const {
return origin.y + size.height / 2;
}
Point getCenter() const {
return {getMidX(), getMidY()};
}
void unionInPlace(const Rect &rect) {
auto x1 = std::min(getMinX(), rect.getMinX());
auto y1 = std::min(getMinY(), rect.getMinY());
auto x2 = std::max(getMaxX(), rect.getMaxX());
auto y2 = std::max(getMaxY(), rect.getMaxY());
origin = {x1, y1};
size = {x2 - x1, y2 - y1};
}
bool containsPoint(Point point) {
return point.x >= origin.x && point.y >= origin.y &&
point.x <= (origin.x + size.width) &&
point.y <= (origin.y + size.height);
}
static Rect
boundingRect(Point const &a, Point const &b, Point const &c, Point const &d) {
auto leftTopPoint = a;
auto rightBottomPoint = a;
leftTopPoint.x = std::min(leftTopPoint.x, b.x);
leftTopPoint.x = std::min(leftTopPoint.x, c.x);
leftTopPoint.x = std::min(leftTopPoint.x, d.x);
leftTopPoint.y = std::min(leftTopPoint.y, b.y);
leftTopPoint.y = std::min(leftTopPoint.y, c.y);
leftTopPoint.y = std::min(leftTopPoint.y, d.y);
rightBottomPoint.x = std::max(rightBottomPoint.x, b.x);
rightBottomPoint.x = std::max(rightBottomPoint.x, c.x);
rightBottomPoint.x = std::max(rightBottomPoint.x, d.x);
rightBottomPoint.y = std::max(rightBottomPoint.y, b.y);
rightBottomPoint.y = std::max(rightBottomPoint.y, c.y);
rightBottomPoint.y = std::max(rightBottomPoint.y, d.y);
return {leftTopPoint,
{rightBottomPoint.x - leftTopPoint.x,
rightBottomPoint.y - leftTopPoint.y}};
}
};
/*
* Generic data structure describes some values associated with *edges*
* of a rectangle.
*/
template <typename T>
struct RectangleEdges {
T left{};
T top{};
T right{};
T bottom{};
bool operator==(const RectangleEdges<T> &rhs) const {
return std::tie(this->left, this->top, this->right, this->bottom) ==
std::tie(rhs.left, rhs.top, rhs.right, rhs.bottom);
}
bool operator!=(const RectangleEdges<T> &rhs) const {
return !(*this == rhs);
}
bool isUniform() const {
return left == top && left == right && left == bottom;
}
};
template <typename T>
RectangleEdges<T> operator+(
RectangleEdges<T> const &lhs,
RectangleEdges<T> const &rhs) {
return RectangleEdges<T>{lhs.left + rhs.left,
lhs.top + rhs.top,
lhs.right + rhs.right,
lhs.bottom + rhs.bottom};
}
template <typename T>
RectangleEdges<T> operator-(
RectangleEdges<T> const &lhs,
RectangleEdges<T> const &rhs) {
return RectangleEdges<T>{lhs.left - rhs.left,
lhs.top - rhs.top,
lhs.right - rhs.right,
lhs.bottom - rhs.bottom};
}
/*
* Generic data structure describes some values associated with *corners*
* of a rectangle.
*/
template <typename T>
struct RectangleCorners {
T topLeft{};
T topRight{};
T bottomLeft{};
T bottomRight{};
bool operator==(const RectangleCorners<T> &rhs) const {
return std::tie(
this->topLeft,
this->topRight,
this->bottomLeft,
this->bottomRight) ==
std::tie(rhs.topLeft, rhs.topRight, rhs.bottomLeft, rhs.bottomRight);
}
bool operator!=(const RectangleCorners<T> &rhs) const {
return !(*this == rhs);
}
bool isUniform() const {
return topLeft == topRight && topLeft == bottomLeft &&
topLeft == bottomRight;
}
};
/*
* EdgeInsets
*/
using EdgeInsets = RectangleEdges<Float>;
/*
* CornerInsets
*/
using CornerInsets = RectangleCorners<Float>;
} // namespace react
} // namespace facebook
namespace std {
template <>
struct hash<facebook::react::Point> {
size_t operator()(const facebook::react::Point &point) const {
return folly::hash::hash_combine(0, point.x, point.y);
}
};
template <>
struct hash<facebook::react::Size> {
size_t operator()(const facebook::react::Size &size) const {
return folly::hash::hash_combine(0, size.width, size.height);
}
};
template <>
struct hash<facebook::react::Rect> {
size_t operator()(const facebook::react::Rect &rect) const {
return folly::hash::hash_combine(0, rect.origin, rect.size);
}
};
template <typename T>
struct hash<facebook::react::RectangleEdges<T>> {
size_t operator()(const facebook::react::RectangleEdges<T> &edges) const {
return folly::hash::hash_combine(
0, edges.left, edges.right, edges.top, edges.bottom);
}
};
template <typename T>
struct hash<facebook::react::RectangleCorners<T>> {
size_t operator()(const facebook::react::RectangleCorners<T> &corners) const {
return folly::hash::hash_combine(
0,
corners.topLeft,
corners.bottomLeft,
corners.topRight,
corners.bottomRight);
}
};
} // namespace std

View File

@ -0,0 +1,41 @@
# Copyright (c) Facebook, Inc. and its affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
require "json"
package = JSON.parse(File.read(File.join(__dir__, "..", "..", "..", "package.json")))
version = package['version']
source = { :git => 'https://github.com/facebook/react-native.git' }
if version == '1000.0.0'
# This is an unpublished version, use the latest commit hash of the react-native repo, which were presumably in.
source[:commit] = `git rev-parse HEAD`.strip
else
source[:tag] = "v#{version}"
end
folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32'
folly_version = '2020.01.13.00'
Pod::Spec.new do |s|
s.name = "React-graphics"
s.version = version
s.summary = "Fabric for React Native."
s.homepage = "https://reactnative.dev/"
s.license = package["license"]
s.author = "Facebook, Inc. and its affiliates"
s.platforms = { :ios => "9.0", :tvos => "10.0" }
s.source = source
s.library = "stdc++"
s.compiler_flags = folly_compiler_flags
s.source_files = "**/*.{m,mm,cpp,h}"
s.exclude_files = "**/tests/*",
"**/android/*",
"**/cxx/*"
s.header_dir = "react/graphics"
s.pod_target_xcconfig = { "USE_HEADERMAP" => "NO", "HEADER_SEARCH_PATHS" => "\"$(PODS_TARGET_SRCROOT)/ReactCommon\" \"$(PODS_ROOT)/Folly\"" }
s.dependency "Folly/Fabric", folly_version
end

View File

@ -0,0 +1,220 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "Transform.h"
#include <cmath>
namespace facebook {
namespace react {
Transform Transform::Identity() {
return {};
}
Transform Transform::Perspective(Float perspective) {
auto transform = Transform{};
transform.matrix[11] = -1.0 / perspective;
return transform;
}
Transform Transform::Scale(Float factorX, Float factorY, Float factorZ) {
auto transform = Transform{};
transform.matrix[0] = factorX;
transform.matrix[5] = factorY;
transform.matrix[10] = factorZ;
return transform;
}
Transform Transform::Translate(Float x, Float y, Float z) {
auto transform = Transform{};
transform.matrix[12] = x;
transform.matrix[13] = y;
transform.matrix[14] = z;
return transform;
}
Transform Transform::Skew(Float x, Float y) {
auto transform = Transform{};
transform.matrix[4] = std::tan(x);
transform.matrix[1] = std::tan(y);
return transform;
}
Transform Transform::RotateX(Float radians) {
auto transform = Transform{};
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;
}
Transform Transform::RotateY(Float radians) {
auto transform = Transform{};
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;
}
Transform Transform::RotateZ(Float radians) {
auto transform = Transform{};
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;
}
Transform Transform::Rotate(Float x, Float y, Float z) {
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);
}
return transform;
}
bool Transform::operator==(Transform const &rhs) const {
for (auto i = 0; i < 16; i++) {
if (matrix[i] != rhs.matrix[i]) {
return false;
}
}
return true;
}
bool Transform::operator!=(Transform const &rhs) const {
return !(*this == rhs);
}
Transform Transform::operator*(Transform const &rhs) const {
if (*this == Transform::Identity()) {
return rhs;
}
const auto &lhs = *this;
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;
return result;
}
Float &Transform::at(int i, int j) {
return matrix[(i * 4) + j];
}
Float const &Transform::at(int i, int j) const {
return matrix[(i * 4) + j];
}
Point operator*(Point const &point, Transform const &transform) {
if (transform == Transform::Identity()) {
return point;
}
auto result = transform * Vector{point.x, point.y, 0, 1};
return {result.x, result.y};
}
Rect operator*(Rect const &rect, Transform const &transform) {
auto centre = rect.getCenter();
auto a = Point{rect.origin.x, rect.origin.y} - centre;
auto b = Point{rect.getMaxX(), rect.origin.y} - centre;
auto c = Point{rect.getMaxX(), rect.getMaxY()} - centre;
auto d = Point{rect.origin.x, rect.getMaxY()} - centre;
auto vectorA = transform * Vector{a.x, a.y, 0, 1};
auto vectorB = transform * Vector{b.x, b.y, 0, 1};
auto vectorC = transform * Vector{c.x, c.y, 0, 1};
auto vectorD = transform * Vector{d.x, d.y, 0, 1};
Point transformedA{vectorA.x + centre.x, vectorA.y + centre.y};
Point transformedB{vectorB.x + centre.x, vectorB.y + centre.y};
Point transformedC{vectorC.x + centre.x, vectorC.y + centre.y};
Point transformedD{vectorD.x + centre.x, vectorD.y + centre.y};
return Rect::boundingRect(
transformedA, transformedB, transformedC, transformedD);
}
Vector operator*(Transform const &transform, Vector const &vector) {
return {
vector.x * transform.at(0, 0) + vector.y * transform.at(1, 0) +
vector.z * transform.at(2, 0) + vector.w * transform.at(3, 0),
vector.x * transform.at(0, 1) + vector.y * transform.at(1, 1) +
vector.z * transform.at(2, 1) + vector.w * transform.at(3, 1),
vector.x * transform.at(0, 2) + vector.y * transform.at(1, 2) +
vector.z * transform.at(2, 2) + vector.w * transform.at(3, 2),
vector.x * transform.at(0, 3) + vector.y * transform.at(1, 3) +
vector.z * transform.at(2, 3) + vector.w * transform.at(3, 3),
};
}
Size operator*(Size const &size, Transform const &transform) {
if (transform == Transform::Identity()) {
return size;
}
auto result = Size{};
result.width = transform.at(0, 0) * size.width;
result.height = transform.at(1, 1) * size.height;
return result;
}
} // namespace react
} // namespace facebook

View File

@ -0,0 +1,124 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <array>
#include <folly/Hash.h>
#include <react/graphics/Float.h>
#include <react/graphics/Geometry.h>
namespace facebook {
namespace react {
/*
* Defines transform matrix to apply affine transformations.
*/
struct Transform {
std::array<Float, 16> matrix{
{1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}};
/*
* Returns the identity transform (`[1 0 0 0; 0 1 0 0; 0 0 1 0; 0 0 0 1]`).
*/
static Transform Identity();
/*
* Returns a Perspective transform.
*/
static Transform Perspective(Float perspective);
/*
* Returns a Scale transform.
*/
static Transform Scale(Float factorX, Float factorY, Float factorZ);
/*
* Returns a Translate transform.
*/
static Transform Translate(Float x, Float y, Float z);
/*
* Returns a Skew transform.
*/
static Transform Skew(Float x, Float y);
/*
* Returns a transform that rotates by `angle` radians along the given axis.
*/
static Transform RotateX(Float angle);
static Transform RotateY(Float angle);
static Transform RotateZ(Float angle);
static Transform Rotate(Float angleX, Float angleY, Float angleZ);
/*
* Equality operators.
*/
bool operator==(Transform const &rhs) const;
bool operator!=(Transform const &rhs) const;
/*
* Matrix subscript.
*/
Float &at(int x, int y);
Float const &at(int x, int y) const;
/*
* Concatenates (multiplies) transform matrices.
*/
Transform operator*(Transform const &rhs) const;
};
/*
* Applies tranformation to the given point.
*/
Point operator*(Point const &point, Transform const &transform);
/*
* Applies tranformation to the given size.
*/
Size operator*(Size const &size, Transform const &transform);
/*
* Applies tranformation to the given rect.
* ONLY SUPPORTS scale and translation transformation.
*/
Rect operator*(Rect const &rect, Transform const &transform);
Vector operator*(Transform const &transform, Vector const &vector);
} // namespace react
} // namespace facebook
namespace std {
template <>
struct hash<facebook::react::Transform> {
size_t operator()(const facebook::react::Transform &transform) const {
return folly::hash::hash_combine(
0,
transform.matrix[0],
transform.matrix[1],
transform.matrix[2],
transform.matrix[3],
transform.matrix[4],
transform.matrix[5],
transform.matrix[6],
transform.matrix[7],
transform.matrix[8],
transform.matrix[9],
transform.matrix[10],
transform.matrix[11],
transform.matrix[12],
transform.matrix[13],
transform.matrix[14],
transform.matrix[15]);
}
};
} // namespace std

View File

@ -0,0 +1,212 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <better/map.h>
#include <folly/dynamic.h>
#include <react/core/RawProps.h>
#include <react/graphics/Color.h>
#include <react/graphics/Geometry.h>
namespace facebook {
namespace react {
#pragma mark - Color
inline void fromRawValue(const RawValue &value, SharedColor &result) {
float red;
float green;
float blue;
float alpha;
if (value.hasType<int>()) {
auto argb = (int64_t)value;
auto ratio = 256.f;
alpha = ((argb >> 24) & 0xFF) / ratio;
red = ((argb >> 16) & 0xFF) / ratio;
green = ((argb >> 8) & 0xFF) / ratio;
blue = (argb & 0xFF) / ratio;
} else if (value.hasType<std::vector<float>>()) {
auto items = (std::vector<float>)value;
auto length = items.size();
assert(length == 3 || length == 4);
red = items.at(0);
green = items.at(1);
blue = items.at(2);
alpha = length == 4 ? items.at(3) : 1.0;
} else {
abort();
}
result = colorFromComponents({red, green, blue, alpha});
}
#ifdef ANDROID
inline folly::dynamic toDynamic(const SharedColor &color) {
ColorComponents components = colorComponentsFromColor(color);
auto ratio = 256.f;
return (
((int)(components.alpha * ratio) & 0xff) << 24 |
((int)(components.red * ratio) & 0xff) << 16 |
((int)(components.green * ratio) & 0xff) << 8 |
((int)(components.blue * ratio) & 0xff));
}
#endif
inline std::string toString(const SharedColor &value) {
ColorComponents components = colorComponentsFromColor(value);
auto ratio = 256.f;
return "rgba(" + folly::to<std::string>(round(components.red * ratio)) +
", " + folly::to<std::string>(round(components.green * ratio)) + ", " +
folly::to<std::string>(round(components.blue * ratio)) + ", " +
folly::to<std::string>(round(components.alpha * ratio)) + ")";
}
#pragma mark - Geometry
inline void fromRawValue(const RawValue &value, Point &result) {
if (value.hasType<better::map<std::string, Float>>()) {
auto map = (better::map<std::string, Float>)value;
for (const auto &pair : map) {
if (pair.first == "x") {
result.x = pair.second;
} else if (pair.first == "y") {
result.y = pair.second;
}
}
return;
}
if (value.hasType<std::vector<Float>>()) {
auto array = (std::vector<Float>)value;
assert(array.size() == 2);
result = {array.at(0), array.at(1)};
return;
}
abort();
}
inline void fromRawValue(const RawValue &value, Size &result) {
if (value.hasType<better::map<std::string, Float>>()) {
auto map = (better::map<std::string, Float>)value;
for (const auto &pair : map) {
if (pair.first == "width") {
result.width = pair.second;
} else if (pair.first == "height") {
result.height = pair.second;
}
}
return;
}
if (value.hasType<std::vector<Float>>()) {
auto array = (std::vector<Float>)value;
assert(array.size() == 2);
result = {array.at(0), array.at(1)};
return;
}
abort();
}
inline void fromRawValue(const RawValue &value, EdgeInsets &result) {
if (value.hasType<Float>()) {
auto number = (Float)value;
result = {number, number, number, number};
}
if (value.hasType<better::map<std::string, Float>>()) {
auto map = (better::map<std::string, Float>)value;
for (const auto &pair : map) {
if (pair.first == "top") {
result.top = pair.second;
} else if (pair.first == "left") {
result.left = pair.second;
} else if (pair.first == "bottom") {
result.bottom = pair.second;
} else if (pair.first == "right") {
result.right = pair.second;
}
}
return;
}
if (value.hasType<std::vector<Float>>()) {
auto array = (std::vector<Float>)value;
assert(array.size() == 4);
result = {array.at(0), array.at(1), array.at(2), array.at(3)};
return;
}
abort();
}
inline void fromRawValue(const RawValue &value, CornerInsets &result) {
if (value.hasType<Float>()) {
auto number = (Float)value;
result = {number, number, number, number};
}
if (value.hasType<better::map<std::string, Float>>()) {
auto map = (better::map<std::string, Float>)value;
for (const auto &pair : map) {
if (pair.first == "topLeft") {
result.topLeft = pair.second;
} else if (pair.first == "topRight") {
result.topRight = pair.second;
} else if (pair.first == "bottomLeft") {
result.bottomLeft = pair.second;
} else if (pair.first == "bottomRight") {
result.bottomRight = pair.second;
}
}
return;
}
if (value.hasType<std::vector<Float>>()) {
auto array = (std::vector<Float>)value;
assert(array.size() == 4);
result = {array.at(0), array.at(1), array.at(2), array.at(3)};
return;
}
abort();
}
inline std::string toString(const Point &point) {
return "{" + folly::to<std::string>(point.x) + ", " +
folly::to<std::string>(point.y) + "}";
}
inline std::string toString(const Size &size) {
return "{" + folly::to<std::string>(size.width) + ", " +
folly::to<std::string>(size.height) + "}";
}
inline std::string toString(const Rect &rect) {
return "{" + toString(rect.origin) + ", " + toString(rect.size) + "}";
}
inline std::string toString(const EdgeInsets &edgeInsets) {
return "{" + folly::to<std::string>(edgeInsets.left) + ", " +
folly::to<std::string>(edgeInsets.top) + ", " +
folly::to<std::string>(edgeInsets.right) + ", " +
folly::to<std::string>(edgeInsets.bottom) + "}";
}
inline std::string toString(const CornerInsets &cornerInsets) {
return "{" + folly::to<std::string>(cornerInsets.topLeft) + ", " +
folly::to<std::string>(cornerInsets.topRight) + ", " +
folly::to<std::string>(cornerInsets.bottomLeft) + ", " +
folly::to<std::string>(cornerInsets.bottomRight) + "}";
}
} // namespace react
} // namespace facebook

View File

@ -0,0 +1,47 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "Color.h"
namespace facebook {
namespace react {
SharedColor colorFromComponents(ColorComponents components) {
float ratio = 255.9999;
return SharedColor(
((int)(components.alpha * ratio) & 0xff) << 24 |
((int)(components.red * ratio) & 0xff) << 16 |
((int)(components.green * ratio) & 0xff) << 8 |
((int)(components.blue * ratio) & 0xff));
}
ColorComponents colorComponentsFromColor(SharedColor sharedColor) {
float ratio = 256;
Color color = *sharedColor;
return ColorComponents{(float)((color >> 16) & 0xff) / ratio,
(float)((color >> 8) & 0xff) / ratio,
(float)((color >> 0) & 0xff) / ratio,
(float)((color >> 24) & 0xff) / ratio};
}
SharedColor clearColor() {
static SharedColor color = colorFromComponents(ColorComponents{0, 0, 0, 0});
return color;
}
SharedColor blackColor() {
static SharedColor color = colorFromComponents(ColorComponents{0, 0, 0, 1});
return color;
}
SharedColor whiteColor() {
static SharedColor color = colorFromComponents(ColorComponents{1, 1, 1, 1});
return color;
}
} // namespace react
} // namespace facebook

View File

@ -0,0 +1,78 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <functional>
#include <limits>
#include <react/graphics/ColorComponents.h>
namespace facebook {
namespace react {
using Color = int;
/*
* On Android, a color can be represented as 32 bits integer, so there is no
* need to instantiate complex color objects and then pass them as shared
* pointers. Hense instead of using shared_ptr, we use a simple wrapper class
* which provides a pointer-like interface.
*/
class SharedColor {
public:
static const Color UndefinedColor = std::numeric_limits<Color>::max();
SharedColor() : color_(UndefinedColor) {}
SharedColor(const SharedColor &sharedColor) : color_(sharedColor.color_) {}
SharedColor(Color color) : color_(color) {}
SharedColor &operator=(const SharedColor &sharedColor) {
color_ = sharedColor.color_;
return *this;
}
Color operator*() const {
return color_;
}
bool operator==(const SharedColor &otherColor) const {
return color_ == otherColor.color_;
}
bool operator!=(const SharedColor &otherColor) const {
return color_ != otherColor.color_;
}
operator bool() const {
return color_ != UndefinedColor;
}
private:
Color color_;
};
SharedColor colorFromComponents(ColorComponents components);
ColorComponents colorComponentsFromColor(SharedColor color);
SharedColor clearColor();
SharedColor blackColor();
SharedColor whiteColor();
} // namespace react
} // namespace facebook
namespace std {
template <>
struct hash<facebook::react::SharedColor> {
size_t operator()(const facebook::react::SharedColor &sharedColor) const {
return hash<decltype(*sharedColor)>{}(*sharedColor);
}
};
} // namespace std

View File

@ -0,0 +1,22 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <limits>
namespace facebook {
namespace react {
/*
* Exact type of float numbers which ideally should match a type behing
* platform- and chip-architecture-specific float type.
*/
using Float = float;
} // namespace react
} // namespace facebook

View File

@ -0,0 +1,55 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "Color.h"
#include <cassert>
namespace facebook {
namespace react {
SharedColor colorFromComponents(ColorComponents components) {
const CGFloat componentsArray[] = {
components.red, components.green, components.blue, components.alpha};
auto color = CGColorCreate(CGColorSpaceCreateDeviceRGB(), componentsArray);
return SharedColor(color, CFRelease);
}
ColorComponents colorComponentsFromColor(SharedColor color) {
if (!color) {
// Empty color object can be considered as `clear` (black, fully
// transparent) color.
return ColorComponents{0, 0, 0, 0};
}
auto numberOfComponents __unused = CGColorGetNumberOfComponents(color.get());
assert(numberOfComponents == 4);
const CGFloat *components = CGColorGetComponents(color.get());
return ColorComponents{(float)components[0],
(float)components[1],
(float)components[2],
(float)components[3]};
}
SharedColor clearColor() {
static SharedColor color = colorFromComponents(ColorComponents{0, 0, 0, 0});
return color;
}
SharedColor blackColor() {
static SharedColor color = colorFromComponents(ColorComponents{0, 0, 0, 1});
return color;
}
SharedColor whiteColor() {
static SharedColor color = colorFromComponents(ColorComponents{1, 1, 1, 1});
return color;
}
} // namespace react
} // namespace facebook

View File

@ -0,0 +1,30 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <memory>
#include <CoreGraphics/CoreGraphics.h>
#include <react/graphics/ColorComponents.h>
#include <react/graphics/Float.h>
namespace facebook {
namespace react {
using Color = CGColor;
using SharedColor = std::shared_ptr<Color>;
SharedColor colorFromComponents(ColorComponents components);
ColorComponents colorComponentsFromColor(SharedColor color);
SharedColor clearColor();
SharedColor blackColor();
SharedColor whiteColor();
} // namespace react
} // namespace facebook

View File

@ -0,0 +1,23 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <CoreGraphics/CoreGraphics.h>
#include <limits>
namespace facebook {
namespace react {
/*
* Exact type of float numbers which ideally should match a type behing
* platform- and chip-architecture-specific float type.
*/
using Float = CGFloat;
} // namespace react
} // namespace facebook

View File

@ -0,0 +1,82 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <react/graphics/Float.h>
namespace facebook {
namespace react {
/*
* Convenience functions for rounding float values to be aligned with a device
* pixel grid.
*
* Usage example:
* auto scaleFactor = Float{3};
* auto value = Float{42.9001};
* auto crispValue = roundToPixel<&std::ceil>(value, scaleFactor);
* auto size = Size{value, value + 42.0};
* auto crispSize = roundToPixel<&std::ceil>(size, scaleFactor);
*/
template <Float (*RoundingFunction)(Float)>
Float roundToPixel(Float value, Float scaleFactor) {
return RoundingFunction(value * scaleFactor) / scaleFactor;
}
template <Float (*RoundingFunction)(Float)>
Point roundToPixel(Point value, Float scaleFactor) {
return Point{roundToPixel<RoundingFunction>(value.x, scaleFactor),
roundToPixel<RoundingFunction>(value.y, scaleFactor)};
}
template <Float (*RoundingFunction)(Float)>
Size roundToPixel(Size value, Float scaleFactor) {
return Size{roundToPixel<RoundingFunction>(value.width, scaleFactor),
roundToPixel<RoundingFunction>(value.height, scaleFactor)};
}
template <Float (*RoundingFunction)(Float)>
Rect roundToPixel(Rect value, Float scaleFactor) {
return Rect{roundToPixel<RoundingFunction>(value.origin),
roundToPixel<RoundingFunction>(value.size)};
}
/*
* GCC-based Android NDK does not have rounding functions as part of STL.
*/
inline float round(float value) noexcept {
return ::roundf(value);
}
inline double round(double value) noexcept {
return ::round(value);
}
inline long double round(long double value) noexcept {
return ::roundl(value);
}
inline float ceil(float value) noexcept {
return ::ceilf(value);
}
inline double ceil(double value) noexcept {
return ::ceil(value);
}
inline long double ceil(long double value) noexcept {
return ::ceill(value);
}
inline float floor(float value) noexcept {
return ::floorf(value);
}
inline double floor(double value) noexcept {
return ::floor(value);
}
inline long double floor(long double value) noexcept {
return ::floorl(value);
}
} // namespace react
} // namespace facebook

View File

@ -0,0 +1,14 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <memory>
#include <gtest/gtest.h>
TEST(GraphicsTest, testSomething) {
// TODO
}

View File

@ -0,0 +1,68 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <react/graphics/Transform.h>
#include <gtest/gtest.h>
#include <math.h>
using namespace facebook::react;
TEST(TransformTest, transformingSize) {
auto size = facebook::react::Size{100, 200};
auto scaledSize = size * Transform::Scale(0.5, 0.5, 1);
EXPECT_EQ(scaledSize.width, 50);
EXPECT_EQ(scaledSize.height, 100);
}
TEST(TransformTest, transformingPoint) {
auto point = facebook::react::Point{100, 200};
auto translatedPoint = point * Transform::Translate(-50, -100, 0);
EXPECT_EQ(translatedPoint.x, 50);
EXPECT_EQ(translatedPoint.y, 100);
}
TEST(TransformTest, scalingRect) {
auto point = facebook::react::Point{100, 200};
auto size = facebook::react::Size{300, 400};
auto rect = facebook::react::Rect{point, size};
auto transformedRect = rect * Transform::Scale(0.5, 0.5, 1);
EXPECT_EQ(transformedRect.origin.x, 175);
EXPECT_EQ(transformedRect.origin.y, 300);
EXPECT_EQ(transformedRect.size.width, 150);
EXPECT_EQ(transformedRect.size.height, 200);
}
TEST(TransformTest, rotatingRect) {
auto point = facebook::react::Point{10, 10};
auto size = facebook::react::Size{10, 10};
auto rect = facebook::react::Rect{point, size};
auto transformedRect = rect * Transform::RotateZ(M_PI_4);
ASSERT_NEAR(transformedRect.origin.x, 7.9289, 0.0001);
ASSERT_NEAR(transformedRect.origin.y, 7.9289, 0.0001);
ASSERT_NEAR(transformedRect.size.width, 14.1421, 0.0001);
ASSERT_NEAR(transformedRect.size.height, 14.1421, 0.0001);
}
TEST(TransformTest, scalingAndTranslatingRect) {
auto point = facebook::react::Point{100, 200};
auto size = facebook::react::Size{300, 400};
auto rect = facebook::react::Rect{point, size};
auto transformedRect =
rect * Transform::Scale(0.5, 0.5, 1) * Transform::Translate(1, 1, 0);
EXPECT_EQ(transformedRect.origin.x, 176);
EXPECT_EQ(transformedRect.origin.y, 301);
EXPECT_EQ(transformedRect.size.width, 150);
EXPECT_EQ(transformedRect.size.height, 200);
}