Skip to content

Commit bb6dcf7

Browse files
committed
Conic gradient support for the container_cairo
1 parent 37bbcc6 commit bb6dcf7

File tree

9 files changed

+236
-7
lines changed

9 files changed

+236
-7
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ else ()
200200
ExternalProject_Add(
201201
litehtml-tests
202202
GIT_REPOSITORY https://github.com/litehtml/litehtml-tests.git
203-
GIT_TAG 81e4d257f2701556385e91db5d18567ff29ad75d
203+
GIT_TAG 7511158e62cdac071de9071e060828e9e3c0bcc6
204204
SOURCE_DIR "${CMAKE_BINARY_DIR}/litehtml-tests-src"
205205
BINARY_DIR "${CMAKE_BINARY_DIR}/litehtml-tests-build"
206206
CMAKE_ARGS -DLITEHTML_PATH=${CMAKE_CURRENT_SOURCE_DIR}

containers/cairo/conic_gradient.cpp

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
#include "conic_gradient.h"
2+
3+
#define INTERPOLATE_COLOR(C1, C2, t) (((C2) - (C1)) * (t) + (C1))
4+
5+
static void sector_patch (cairo_pattern_t *pattern, double radius,
6+
double angle_A,
7+
double A_r, double A_g, double A_b, double A_a,
8+
double angle_B,
9+
double B_r, double B_g, double B_b, double B_a)
10+
{
11+
double r_sin_A, r_cos_A;
12+
double r_sin_B, r_cos_B;
13+
double h;
14+
15+
r_sin_A = radius * sin (angle_A);
16+
r_cos_A = radius * cos (angle_A);
17+
r_sin_B = radius * sin (angle_B);
18+
r_cos_B = radius * cos (angle_B);
19+
20+
h = 4.0/3.0 * tan ((angle_B - angle_A) / 4.0);
21+
22+
double x0 = r_cos_A;
23+
double y0 = r_sin_A;
24+
double x1 = r_cos_A - h * r_sin_A;
25+
double y1 = r_sin_A + h * r_cos_A;
26+
double x2 = r_cos_B + h * r_sin_B;
27+
double y2 = r_sin_B - h * r_cos_B;
28+
double x3 = r_cos_B;
29+
double y3 = r_sin_B;
30+
31+
cairo_mesh_pattern_begin_patch (pattern);
32+
33+
cairo_mesh_pattern_move_to (pattern, 0, 0);
34+
cairo_mesh_pattern_line_to (pattern, x0, y0);
35+
36+
cairo_mesh_pattern_curve_to (pattern,
37+
x1, y1,
38+
x2, y2,
39+
x3, y3);
40+
cairo_mesh_pattern_line_to (pattern, 0, 0);
41+
42+
cairo_mesh_pattern_set_corner_color_rgba (pattern, 0, A_r, A_g, A_b, A_a);
43+
cairo_mesh_pattern_set_corner_color_rgba (pattern, 1, A_r, A_g, A_b, A_a);
44+
cairo_mesh_pattern_set_corner_color_rgba (pattern, 2, B_r, B_g, B_b, B_a);
45+
cairo_mesh_pattern_set_corner_color_rgba (pattern, 3, B_r, B_g, B_b, B_a);
46+
47+
cairo_mesh_pattern_end_patch (pattern);
48+
}
49+
50+
cairo_pattern_t* create_conic_gradient_pattern(double angle, double radius, const std::vector<bg_color_point>& color_points)
51+
{
52+
if (color_points.empty())
53+
{
54+
return nullptr;
55+
}
56+
57+
if(color_points.size() == 2)
58+
{
59+
std::vector<bg_color_point> points;
60+
points.push_back(color_points[0]);
61+
bg_color_point cp;
62+
cp.offset = 0.5f;
63+
cp.color.red = INTERPOLATE_COLOR(color_points[0].color.red, color_points[1].color.red, 0.5f);
64+
cp.color.green = INTERPOLATE_COLOR(color_points[0].color.green, color_points[1].color.green, 0.5f);
65+
cp.color.blue = INTERPOLATE_COLOR(color_points[0].color.blue, color_points[1].color.blue, 0.5f);
66+
cp.color.alpha = INTERPOLATE_COLOR(color_points[0].color.alpha, color_points[1].color.alpha, 0.5f);
67+
points.push_back(cp);
68+
points.push_back(color_points[1]);
69+
return create_conic_gradient_pattern(angle, radius, points);
70+
}
71+
72+
const double two_pi = 2.0 * M_PI;
73+
74+
cairo_pattern_t* pattern = cairo_pattern_create_mesh();
75+
76+
for(size_t i = 0; i < color_points.size() - 1; ++i)
77+
{
78+
const bg_color_point& cp_A = color_points[i];
79+
const bg_color_point& cp_B = color_points[i + 1];
80+
double angle_A = cp_A.offset * two_pi + angle;
81+
double angle_B = color_points[i + 1].offset * two_pi + angle;
82+
83+
double A_r = cp_A.color.red / 255.0;
84+
double A_g = cp_A.color.green / 255.0;
85+
double A_b = cp_A.color.blue / 255.0;
86+
double A_a = cp_A.color.alpha / 255.0;
87+
88+
double B_r = cp_B.color.red / 255.0;
89+
double B_g = cp_B.color.green / 255.0;
90+
double B_b = cp_B.color.blue / 255.0;
91+
double B_a = cp_B.color.alpha / 255.0;
92+
93+
sector_patch(pattern, radius,
94+
angle_A, A_r, A_g, A_b, A_a,
95+
angle_B, B_r, B_g, B_b, B_a);
96+
}
97+
98+
return pattern;
99+
}

containers/cairo/conic_gradient.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#ifndef LITEHTML_CONIC_GRADIENT_H
2+
#define LITEHTML_CONIC_GRADIENT_H
3+
4+
#include <litehtml.h>
5+
#include <cairo.h>
6+
7+
using bg_color_point = litehtml::background_layer::color_point;
8+
9+
cairo_pattern_t* create_conic_gradient_pattern(double angle, double radius, const std::vector<bg_color_point>& color_points);
10+
11+
#endif //LITEHTML_CONIC_GRADIENT_H

containers/cairo/container_cairo.cpp

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "container_cairo.h"
22
#include "cairo_borders.h"
3+
#include "conic_gradient.h"
34
#include <cmath>
45

56
#ifndef M_PI
@@ -738,14 +739,34 @@ void container_cairo::draw_radial_gradient(litehtml::uint_ptr hdc, const litehtm
738739
}
739740

740741
void container_cairo::draw_conic_gradient(litehtml::uint_ptr hdc, const litehtml::background_layer &layer,
741-
const litehtml::background_layer::conic_gradient &/*gradient*/)
742+
const litehtml::background_layer::conic_gradient &gradient)
742743
{
743744
auto* cr = (cairo_t*) hdc;
744745
cairo_save(cr);
745746
apply_clip(cr);
746747

747748
clip_background_layer(cr, layer);
748749

750+
cairo_pattern_t* pattern = create_conic_gradient_pattern(gradient.angle * M_PI / 180.0 - M_PI / 2.0, gradient.radius, gradient.color_points);
751+
if(!pattern) return;
749752

753+
// Translate a pattern to the (layer.origin_box.x, layer.origin_box.y) point
754+
litehtml::pointF position = gradient.position;
755+
position.x -= (float) layer.origin_box.x;
756+
position.y -= (float) layer.origin_box.y;
757+
758+
draw_pattern(cr, pattern, layer, [&position](cairo_t* cr, cairo_pattern_t* pattern, int x, int y, int w, int h)
759+
{
760+
cairo_matrix_t flib_m;
761+
cairo_matrix_init_translate(&flib_m, -(position.x + (float ) x), -(position.y + (float ) y));
762+
cairo_pattern_set_matrix(pattern, &flib_m);
763+
764+
cairo_set_source(cr, pattern);
765+
cairo_rectangle(cr, x, y, w, h);
766+
cairo_fill(cr);
767+
}
768+
);
769+
770+
cairo_pattern_destroy(pattern);
750771
cairo_restore(cr);
751772
}

doc/document_container.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -357,11 +357,13 @@ class conic_gradient : public gradient_base
357357
{
358358
public:
359359
pointF position;
360-
float angle;
360+
float angle;
361+
float radius;
361362
};
362363
```
363-
* ```position``` - the center of the gradient.
364-
* ```angle``` - the angle of the gradient.
364+
* ```position``` - the center of the conic gradient
365+
* ```angle``` - the angle of the gradient in degrees, starting from 0 at the top and going clockwise
366+
* ```radius``` - the distance from the center to the farthest corner of the background box
365367

366368
### draw_borders
367369
```cpp

include/litehtml/background.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,9 @@ namespace litehtml
8282
class conic_gradient : public gradient_base
8383
{
8484
public:
85-
pointF position;
86-
float angle = 0;
85+
pointF position; // position is the center of the conic gradient
86+
float angle = 0; // angle is the angle of the gradient in degrees, starting from 0 at the top and going clockwise
87+
float radius = 0; // radius is the distance from the center to the farthest corner of the background box
8788
};
8889
};
8990

include/litehtml/css_calc.h

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#ifndef LITEHTML_CSS_CALC_H
2+
#define LITEHTML_CSS_CALC_H
3+
4+
#include "litehtml/css_length.h"
5+
#include "litehtml/css_tokenizer.h"
6+
#include "litehtml/types.h"
7+
#include <memory>
8+
#include <utility>
9+
10+
namespace litehtml
11+
{
12+
namespace expr
13+
{
14+
// Node base class
15+
class node
16+
{
17+
public:
18+
node() {}
19+
virtual ~node() = default;
20+
};
21+
22+
// Operation base class
23+
class node_op : public node
24+
{
25+
std::unique_ptr<node> m_left;
26+
std::unique_ptr<node> m_right;
27+
};
28+
29+
// Value node
30+
class node_value : public node
31+
{
32+
float value = 0;
33+
css_units units = css_units_none;
34+
};
35+
36+
// Function base class
37+
class node_func : public node
38+
{
39+
std::unique_ptr<node> m_root;
40+
};
41+
42+
// Expression class
43+
class expression
44+
{
45+
std::unique_ptr<node> m_root;
46+
47+
public:
48+
expression();
49+
50+
bool from_token(const css_token& token, int options);
51+
52+
private:
53+
54+
};
55+
} // namespace expr
56+
57+
} // namespace litehtml
58+
59+
#endif // LITEHTML_CSS_CALC_H

src/background.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -602,6 +602,12 @@ std::unique_ptr<litehtml::background_layer::conic_gradient> litehtml::background
602602
ret->color_space = m_image[idx].m_gradient.color_space;
603603
ret->hue_interpolation = m_image[idx].m_gradient.hue_interpolation;
604604

605+
float corner1 = distance(ret->position, {(float) layer.origin_box.left(), (float) layer.origin_box.top()});
606+
float corner2 = distance(ret->position, {(float) layer.origin_box.right(), (float) layer.origin_box.top()});
607+
float corner3 = distance(ret->position, {(float) layer.origin_box.left(), (float) layer.origin_box.bottom()});
608+
float corner4 = distance(ret->position, {(float) layer.origin_box.right(), (float) layer.origin_box.bottom()});
609+
ret->radius = std::max({corner1, corner2, corner3, corner4});
610+
605611
if(ret->prepare_color_points(0, m_image[idx].m_gradient.m_type, m_image[idx].m_gradient.m_colors))
606612
{
607613
return ret;

src/css_calc.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#include "css_calc.h"
2+
#include "css_length.h"
3+
#include "css_tokenizer.h"
4+
#include <memory>
5+
6+
bool litehtml::css_calc::from_token(const css_token& token, int options)
7+
{
8+
if(token.type == CV_FUNCTION && token.name == "calc")
9+
{
10+
m_root = std::make_unique<css_calc_node>(css_calc_node_type::root);
11+
12+
for(const auto& tok : token.value)
13+
{
14+
switch(tok.type)
15+
{
16+
case PERCENTAGE:
17+
case NUMBER:
18+
case DIMENSION:
19+
{
20+
css_length len;
21+
if(!len.from_token(tok, options))
22+
return false;
23+
m_root
24+
}
25+
break;
26+
}
27+
}
28+
}
29+
return false;
30+
}

0 commit comments

Comments
 (0)