aboutsummaryrefslogtreecommitdiffstats
path: root/include/litehtml/gradient.h
blob: 1bfe77cde04361170684f9e4b72d5c3d10e73bc9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
#ifndef LITEHTML_GRADIENT_H
#define LITEHTML_GRADIENT_H

#include "css_length.h"
#include "string_id.h"
#include "types.h"
#include "web_color.h"

namespace litehtml
{
	enum gradient_side
	{
		gradient_side_none = 0,
		gradient_side_left = 0x01,
		gradient_side_right = 0x02,
		gradient_side_top = 0x04,
		gradient_side_bottom = 0x08,
		gradient_side_x_center = 0x10,
		gradient_side_y_center = 0x20,
		gradient_side_x_length = 0x40,
		gradient_side_y_length = 0x80,
	};
	static_assert(gradient_side_left == (1 << background_position_left), "parse_bg_position is also used to parse radial gradient position");

	enum radial_shape_t
	{
		radial_shape_none,
		radial_shape_circle,
		radial_shape_ellipse,
	};

#define radial_extent_strings "closest-corner;closest-side;farthest-corner;farthest-side"
	enum radial_extent_t
	{
		radial_extent_none,
		radial_extent_closest_corner,
		radial_extent_closest_side,
		radial_extent_farthest_corner,
		radial_extent_farthest_side,
	};

#define color_space_strings \
			"srgb;"\
			"srgb-linear;"\
			"display-p3;"\
			"a98-rgb;"\
			"prophoto-rgb;"\
			"rec2020;"\
			"lab;"\
			"oklab;"\
			"xyz;"\
			"xyz-d50;"\
			"xyz-d65;"\
			"hsl;"\
			"hwb;"\
			"lch;"\
			"oklch"

	enum color_space_t
	{
		color_space_none,

		// rectangular-color-space
		color_space_srgb,
		color_space_srgb_linear,
		color_space_display_p3,
		color_space_a98_rgb,
		color_space_prophoto_rgb,
		color_space_rec2020,
		color_space_lab,
		color_space_oklab,
		color_space_xyz,
		color_space_xyz_d50,
		color_space_xyz_d65,

		// polar-color-space
		color_space_hsl, color_space_polar_start = color_space_hsl,
		color_space_hwb,
		color_space_lch,
		color_space_oklch,
	};

#define hue_interpolation_strings "shorter;longer;increasing;decreasing"
	enum hue_interpolation_t
	{
		hue_interpolation_none,
		hue_interpolation_shorter,
		hue_interpolation_longer,
		hue_interpolation_increasing,
		hue_interpolation_decreasing
	};

	class gradient
	{
	public:
		// https://drafts.csswg.org/css-images-4/#typedef-color-stop-list
		// color_stop represents <linear-color-stop> | <linear-color-hint> | <angular-color-stop> | <angular-color-hint>
		// <linear-color-stop>  = <color> <length-percentage>{1,2}?
		// <linear-color-hint>  = <length-percentage>
		// <angular-color-stop> = <color> <angle-percentage>{1,2}?
		// <angular-color-hint> = <angle-percentage>
		// If two lengths/angles are specified they create two color-stops with the same color.
		class color_stop
		{
		public:
			bool is_color_hint = false;
			web_color color;
			optional<css_length> length;
			optional<float> angle;

			color_stop() {}
			color_stop(web_color color)                    : color(color)                        {}
			color_stop(web_color color, css_length length) : color(color), length(length)        {}
			color_stop(web_color color, float angle)       : color(color), angle(angle)          {}
			color_stop(css_length length)                  : is_color_hint(true), length(length) {}
			color_stop(float angle)                        : is_color_hint(true), angle(angle)   {}
		};

		string_id m_type;
		uint32_t m_side;
		float angle;
		vector<color_stop> m_colors;
		css_length position_x;
		css_length position_y;
		radial_shape_t radial_shape;
		radial_extent_t radial_extent;
		css_length radial_radius_x;
		css_length radial_radius_y;
		float conic_from_angle;
		color_space_t color_space;
		hue_interpolation_t hue_interpolation;


		explicit gradient(string_id type = empty_id)
		{
			m_type = type;

			// linear gradient:       m_side default is gradient_side_none (use angle)
			// radial,conic gradient: m_side default is gradient_side_x_center | gradient_side_y_center (see parse_gradient)
			m_side = gradient_side_none;
			// linear gradient angle, used when m_side == gradient_side_none
			angle = 180; // to bottom
			// radial,conic position (together with m_side)
			position_x.predef(0);
			position_y.predef(0);

			// actual default depends on the number of radii provided, see parse_radial_gradient_shape_size_position_interpolation
			radial_shape = radial_shape_ellipse;

			// <radial-size>  https://drafts.csswg.org/css-images-3/#valdef-radial-gradient-radial-size
			// if radius is specified radial_extent will be set to none, see parse_radial_size
			radial_extent = radial_extent_farthest_corner;
			radial_radius_x.predef(0);
			radial_radius_y.predef(0);

			conic_from_angle = 0;

			// If the host syntax does not define what color space interpolation should take place in, it defaults to Oklab.
			color_space = color_space_oklab;
			// Unless otherwise specified, if no specific hue interpolation algorithm is selected by the host syntax, the default is shorter.
			hue_interpolation = hue_interpolation_shorter;
		}

		bool is_empty() const
		{
			return m_type == empty_id || m_colors.empty();
		}

		bool is_linear() const { return m_type == _linear_gradient_ || m_type == _repeating_linear_gradient_; }
		bool is_radial() const { return m_type == _radial_gradient_ || m_type == _repeating_radial_gradient_; }
		bool is_conic() const { return m_type == _conic_gradient_ || m_type == _repeating_conic_gradient_; }

		static gradient transparent;
	};

	class image
	{
	public:
		enum type
		{
			type_none,
			type_url,
			type_gradient,
		};
		type type;
		string url;
		gradient m_gradient;

		image() : type(type_none) {}

		bool is_empty() const
		{
			switch (type)
			{
			case type_none:
				return true;
			case type_url:
				return url.empty();
			case type_gradient:
				return m_gradient.is_empty();
			}
			return true;
		}
	};

	bool parse_gradient(const css_token& token, gradient& gradient, document_container* container);
}

#endif //LITEHTML_GRADIENT_H