Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
gradient.cc
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <algorithm>
6
7#include "flutter/fml/logging.h"
9
10namespace impeller {
11
12static void AppendColor(const Color& color, GradientData* data) {
13 auto converted = color.ToR8G8B8A8();
14 data->color_bytes.push_back(converted[0]);
15 data->color_bytes.push_back(converted[1]);
16 data->color_bytes.push_back(converted[2]);
17 data->color_bytes.push_back(converted[3]);
18}
19
20GradientData CreateGradientBuffer(const std::vector<Color>& colors,
21 const std::vector<Scalar>& stops) {
22 FML_DCHECK(stops.size() == colors.size());
23
24 uint32_t texture_size;
25 if (stops.size() == 2) {
26 texture_size = colors.size();
27 } else {
28 auto minimum_delta = 1.0;
29 for (size_t i = 1; i < stops.size(); i++) {
30 auto value = stops[i] - stops[i - 1];
31 // Smaller than kEhCloseEnough
32 if (value < 0.0001) {
33 continue;
34 }
35 if (value < minimum_delta) {
36 minimum_delta = value;
37 }
38 }
39 // Avoid creating textures that are absurdly large due to stops that are
40 // very close together.
41 // TODO(jonahwilliams): this should use a platform specific max texture
42 // size.
43 texture_size = std::min(
44 static_cast<uint32_t>(std::round(1.0 / minimum_delta)) + 1, 1024u);
45 }
46 GradientData data = {
47 .color_bytes = {},
48 .texture_size = texture_size,
49 };
50 data.color_bytes.reserve(texture_size * 4);
51
52 if (texture_size == colors.size() && colors.size() <= 1024) {
53 for (auto i = 0u; i < colors.size(); i++) {
54 AppendColor(colors[i], &data);
55 }
56 } else {
57 Color previous_color = colors[0];
58 auto previous_stop = 0.0;
59 auto previous_color_index = 0;
60
61 // The first index is always equal to the first color, exactly.
62 AppendColor(previous_color, &data);
63
64 for (auto i = 1u; i < texture_size - 1; i++) {
65 auto scaled_i = i / (texture_size - 1.0);
66 Color next_color = colors[previous_color_index + 1];
67 auto next_stop = stops[previous_color_index + 1];
68 // We're almost exactly equal to the next stop.
69 if (ScalarNearlyEqual(scaled_i, next_stop)) {
70 AppendColor(next_color, &data);
71
72 previous_color = next_color;
73 previous_stop = next_stop;
74 previous_color_index += 1;
75 } else if (scaled_i < next_stop) {
76 // We're still between the current stop and the next stop.
77 auto t = (scaled_i - previous_stop) / (next_stop - previous_stop);
78 auto mixed_color = Color::Lerp(previous_color, next_color, t);
79
80 AppendColor(mixed_color, &data);
81 } else {
82 // We've slightly overshot the previous stop.
83 previous_color = next_color;
84 previous_stop = next_stop;
85 previous_color_index += 1;
86 next_color = colors[previous_color_index + 1];
87 auto next_stop = stops[previous_color_index + 1];
88
89 auto t = (scaled_i - previous_stop) / (next_stop - previous_stop);
90 auto mixed_color = Color::Lerp(previous_color, next_color, t);
91
92 AppendColor(mixed_color, &data);
93 }
94 }
95 // The last index is always equal to the last color, exactly.
96 AppendColor(colors.back(), &data);
97 }
98 return data;
99}
100
101} // namespace impeller
SkColor4f color
uint8_t value
#define FML_DCHECK(condition)
Definition logging.h:103
static void AppendColor(const Color &color, GradientData *data)
Definition gradient.cc:12
GradientData CreateGradientBuffer(const std::vector< Color > &colors, const std::vector< Scalar > &stops)
Populate a vector with the interpolated color bytes for the linear gradient described by colors and s...
Definition gradient.cc:20
constexpr bool ScalarNearlyEqual(Scalar x, Scalar y, Scalar tolerance=kEhCloseEnough)
Definition scalar.h:30
static constexpr Color Lerp(Color a, Color b, Scalar t)
Return a color that is linearly interpolated between colors a and b, according to the value of t.
Definition color.h:234