mirror of
https://github.com/zoriya/react-native-svg.git
synced 2025-12-06 07:06:11 +00:00
This change removes the win2d (Direct2D wrapper) dependency by using D2D directly. This removes the manual step of adding the win2d to any new react-native-windows projects that want to use react-native-svg. It is also a stepping stone to an easier Fabric implementation for windows.
226 lines
6.9 KiB
C++
226 lines
6.9 KiB
C++
#pragma once
|
|
|
|
#include "pch.h"
|
|
|
|
#include "dwrite.h"
|
|
|
|
namespace winrt::RNSVG {
|
|
struct D2DHelpers {
|
|
public:
|
|
|
|
static void PushOpacityLayer(
|
|
ID2D1DeviceContext *deviceContext,
|
|
ID2D1Geometry *clipPathGeometry,
|
|
float opacity) {
|
|
com_ptr<ID2D1Layer> opacityLayer;
|
|
check_hresult(deviceContext->CreateLayer(nullptr, opacityLayer.put()));
|
|
|
|
D2D1_LAYER_PARAMETERS layerParams{D2D1::LayerParameters()};
|
|
layerParams.opacity = opacity;
|
|
|
|
if (clipPathGeometry) {
|
|
layerParams.geometricMask = clipPathGeometry;
|
|
}
|
|
|
|
deviceContext->PushLayer(layerParams, opacityLayer.get());
|
|
}
|
|
|
|
static void PushOpacityLayer(
|
|
ID2D1DeviceContext *deviceContext,
|
|
ID2D1Geometry *clipPathGeometry,
|
|
float opacity,
|
|
D2D1_MATRIX_3X2_F transform) {
|
|
com_ptr<ID2D1Layer> opacityLayer;
|
|
check_hresult(deviceContext->CreateLayer(nullptr, opacityLayer.put()));
|
|
|
|
D2D1_LAYER_PARAMETERS layerParams{D2D1::LayerParameters()};
|
|
layerParams.opacity = opacity;
|
|
layerParams.maskTransform = transform;
|
|
|
|
if (clipPathGeometry) {
|
|
layerParams.geometricMask = clipPathGeometry;
|
|
}
|
|
|
|
deviceContext->PushLayer(layerParams, opacityLayer.get());
|
|
}
|
|
|
|
static D2D1_CAP_STYLE GetLineCap(RNSVG::LineCap const &lineCap) {
|
|
switch (lineCap) {
|
|
case RNSVG::LineCap::Square:
|
|
return D2D1_CAP_STYLE_SQUARE;
|
|
case RNSVG::LineCap::Round:
|
|
return D2D1_CAP_STYLE_ROUND;
|
|
case RNSVG::LineCap::Butt:
|
|
default:
|
|
return D2D1_CAP_STYLE_FLAT;
|
|
}
|
|
}
|
|
|
|
static D2D1_LINE_JOIN GetLineJoin(RNSVG::LineJoin const &lineJoin) {
|
|
switch (lineJoin) {
|
|
case RNSVG::LineJoin::Bevel:
|
|
return D2D1_LINE_JOIN_BEVEL;
|
|
case RNSVG::LineJoin::Round:
|
|
return D2D1_LINE_JOIN_ROUND;
|
|
case RNSVG::LineJoin::Miter:
|
|
default:
|
|
return D2D1_LINE_JOIN_MITER;
|
|
}
|
|
}
|
|
|
|
static D2D1_FILL_MODE GetFillRule(RNSVG::FillRule const &fillRule) {
|
|
switch (fillRule) {
|
|
case RNSVG::FillRule::EvenOdd:
|
|
return D2D1_FILL_MODE_ALTERNATE;
|
|
case RNSVG::FillRule::NonZero:
|
|
default:
|
|
return D2D1_FILL_MODE_WINDING;
|
|
}
|
|
}
|
|
|
|
static D2D1::ColorF AsD2DColor(ui::Color const &color) {
|
|
return {
|
|
color.R / 255.0f,
|
|
color.G / 255.0f,
|
|
color.B / 255.0f,
|
|
color.A / 255.0f};
|
|
}
|
|
|
|
static ui::Color FromD2DColor(D2D1::ColorF const color) {
|
|
return ui::ColorHelper::FromArgb(
|
|
static_cast<uint8_t>(color.a),
|
|
static_cast<uint8_t>(color.r),
|
|
static_cast<uint8_t>(color.g),
|
|
static_cast<uint8_t>(color.b));
|
|
}
|
|
|
|
static D2D1_RECT_F AsD2DRect(Rect const &rect) {
|
|
return {rect.X, rect.Y, rect.Width + rect.X, rect.Height + rect.Y};
|
|
}
|
|
|
|
static Rect FromD2DRect(D2D1_RECT_F const rect) {
|
|
return {rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top};
|
|
}
|
|
|
|
static Size SizeFromD2DRect(D2D1_RECT_F const rect) {
|
|
return {rect.right - rect.left, rect.bottom - rect.top};
|
|
}
|
|
|
|
static float WidthFromD2DRect(D2D1_RECT_F const rect) {
|
|
return rect.right - rect.left;
|
|
}
|
|
|
|
static float HeightFromD2DRect(D2D1_RECT_F const rect) {
|
|
return rect.bottom - rect.top;
|
|
}
|
|
|
|
static Numerics::float3x2 FromD2DTransform(D2D1_MATRIX_3X2_F const transform) {
|
|
return Numerics::float3x2(
|
|
transform.m11, transform.m12, transform.m21, transform.m22, transform._31, transform._32);
|
|
}
|
|
|
|
static D2D1::Matrix3x2F AsD2DTransform(Numerics::float3x2 const &transform) {
|
|
return D2D1::Matrix3x2F(transform.m11, transform.m12, transform.m21, transform.m22, transform.m31, transform.m32);
|
|
}
|
|
|
|
static D2D1_MATRIX_3X2_F GetTransform(ID2D1DeviceContext* deviceContext) {
|
|
D2D1_MATRIX_3X2_F transform;
|
|
deviceContext->GetTransform(&transform);
|
|
|
|
return transform;
|
|
}
|
|
|
|
static DWRITE_FONT_WEIGHT FontWeightFrom(hstring const &weight, xaml::FrameworkElement const &parent) {
|
|
if (weight == L"normal") {
|
|
return DWRITE_FONT_WEIGHT_NORMAL;
|
|
} else if (weight == L"bold") {
|
|
return DWRITE_FONT_WEIGHT_BOLD;
|
|
}
|
|
|
|
auto const &groupView{parent.try_as<RNSVG::GroupView>()};
|
|
DWRITE_FONT_WEIGHT parentWeight{
|
|
groupView ? D2DHelpers::FontWeightFrom(groupView.FontWeight(), groupView.SvgParent()) : DWRITE_FONT_WEIGHT_NORMAL};
|
|
|
|
if (weight == L"bolder") {
|
|
return D2DHelpers::Bolder(parentWeight);
|
|
} else if (weight == L"lighter") {
|
|
return D2DHelpers::Lighter(parentWeight);
|
|
} else if (weight == L"auto") {
|
|
return parentWeight;
|
|
}
|
|
|
|
return D2DHelpers::GetClosestFontWeight(std::stof(weight.c_str(), nullptr));
|
|
}
|
|
|
|
// https://developer.mozilla.org/en-US/docs/Web/CSS/font-weight#meaning_of_relative_weights
|
|
static DWRITE_FONT_WEIGHT Bolder(DWRITE_FONT_WEIGHT weight) {
|
|
switch (weight) {
|
|
case DWRITE_FONT_WEIGHT_THIN:
|
|
case DWRITE_FONT_WEIGHT_EXTRA_LIGHT:
|
|
case DWRITE_FONT_WEIGHT_LIGHT:
|
|
case DWRITE_FONT_WEIGHT_SEMI_LIGHT:
|
|
return DWRITE_FONT_WEIGHT_NORMAL;
|
|
case DWRITE_FONT_WEIGHT_NORMAL:
|
|
case DWRITE_FONT_WEIGHT_MEDIUM:
|
|
case DWRITE_FONT_WEIGHT_SEMI_BOLD:
|
|
return DWRITE_FONT_WEIGHT_BOLD;
|
|
case DWRITE_FONT_WEIGHT_BOLD:
|
|
case DWRITE_FONT_WEIGHT_EXTRA_BOLD:
|
|
return DWRITE_FONT_WEIGHT_BLACK;
|
|
case DWRITE_FONT_WEIGHT_BLACK:
|
|
default:
|
|
return DWRITE_FONT_WEIGHT_EXTRA_BLACK;
|
|
}
|
|
}
|
|
|
|
static DWRITE_FONT_WEIGHT Lighter(DWRITE_FONT_WEIGHT weight) {
|
|
switch (weight) {
|
|
case DWRITE_FONT_WEIGHT_THIN:
|
|
case DWRITE_FONT_WEIGHT_EXTRA_LIGHT:
|
|
case DWRITE_FONT_WEIGHT_LIGHT:
|
|
case DWRITE_FONT_WEIGHT_SEMI_LIGHT:
|
|
case DWRITE_FONT_WEIGHT_NORMAL:
|
|
case DWRITE_FONT_WEIGHT_MEDIUM:
|
|
return DWRITE_FONT_WEIGHT_THIN;
|
|
case DWRITE_FONT_WEIGHT_SEMI_BOLD:
|
|
case DWRITE_FONT_WEIGHT_BOLD:
|
|
return DWRITE_FONT_WEIGHT_NORMAL;
|
|
case DWRITE_FONT_WEIGHT_EXTRA_BOLD:
|
|
case DWRITE_FONT_WEIGHT_BLACK:
|
|
default:
|
|
return DWRITE_FONT_WEIGHT_BOLD;
|
|
}
|
|
}
|
|
|
|
static DWRITE_FONT_WEIGHT GetClosestFontWeight(float weight) {
|
|
if (weight > 325 && weight < 375) {
|
|
return DWRITE_FONT_WEIGHT_SEMI_LIGHT;
|
|
} else if (weight > 925) {
|
|
return DWRITE_FONT_WEIGHT_EXTRA_BLACK;
|
|
} else {
|
|
switch (static_cast<uint16_t>(std::round(weight / 100.0f))) {
|
|
case 1:
|
|
return DWRITE_FONT_WEIGHT_THIN;
|
|
case 2:
|
|
return DWRITE_FONT_WEIGHT_EXTRA_LIGHT;
|
|
case 3:
|
|
return DWRITE_FONT_WEIGHT_LIGHT;
|
|
case 4:
|
|
return DWRITE_FONT_WEIGHT_NORMAL;
|
|
case 5:
|
|
return DWRITE_FONT_WEIGHT_MEDIUM;
|
|
case 6:
|
|
return DWRITE_FONT_WEIGHT_SEMI_BOLD;
|
|
case 7:
|
|
return DWRITE_FONT_WEIGHT_BOLD;
|
|
case 8:
|
|
return DWRITE_FONT_WEIGHT_EXTRA_BOLD;
|
|
case 9:
|
|
default:
|
|
return DWRITE_FONT_WEIGHT_BLACK;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
} // namespace winrt::RNSVG
|