Files
react-native-svg/windows/RNSVG/D2DHelpers.h
Marlene Cota f88532d195 [Windows] Port to Direct2D to remove win2d dependency (#2052)
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.
2023-11-14 11:33:19 +01:00

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