зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1614890 - Implement conic-gradient for WebRender graphics backend. r=gw,nical,emilio
Differential Revision: https://phabricator.services.mozilla.com/D61599 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
a6716c2b92
Коммит
d0a5c12f8e
|
@ -1195,6 +1195,17 @@ void DisplayListBuilder::PushRadialGradient(
|
|||
aStops.Length(), aExtendMode, aTileSize, aTileSpacing);
|
||||
}
|
||||
|
||||
void DisplayListBuilder::PushConicGradient(
|
||||
const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
|
||||
bool aIsBackfaceVisible, const wr::LayoutPoint& aCenter, const float aAngle,
|
||||
const nsTArray<wr::GradientStop>& aStops, wr::ExtendMode aExtendMode,
|
||||
const wr::LayoutSize aTileSize, const wr::LayoutSize aTileSpacing) {
|
||||
wr_dp_push_conic_gradient(mWrState, aBounds, MergeClipLeaf(aClip),
|
||||
aIsBackfaceVisible, &mCurrentSpaceAndClipChain,
|
||||
aCenter, aAngle, aStops.Elements(), aStops.Length(),
|
||||
aExtendMode, aTileSize, aTileSpacing);
|
||||
}
|
||||
|
||||
void DisplayListBuilder::PushImage(
|
||||
const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
|
||||
bool aIsBackfaceVisible, wr::ImageRendering aFilter, wr::ImageKey aImage,
|
||||
|
@ -1317,6 +1328,18 @@ void DisplayListBuilder::PushBorderRadialGradient(
|
|||
aStops.Elements(), aStops.Length(), aExtendMode, aOutset);
|
||||
}
|
||||
|
||||
void DisplayListBuilder::PushBorderConicGradient(
|
||||
const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
|
||||
bool aIsBackfaceVisible, const wr::LayoutSideOffsets& aWidths, bool aFill,
|
||||
const wr::LayoutPoint& aCenter, const float aAngle,
|
||||
const nsTArray<wr::GradientStop>& aStops, wr::ExtendMode aExtendMode,
|
||||
const wr::LayoutSideOffsets& aOutset) {
|
||||
wr_dp_push_border_conic_gradient(
|
||||
mWrState, aBounds, MergeClipLeaf(aClip), aIsBackfaceVisible,
|
||||
&mCurrentSpaceAndClipChain, aWidths, aFill, aCenter, aAngle,
|
||||
aStops.Elements(), aStops.Length(), aExtendMode, aOutset);
|
||||
}
|
||||
|
||||
void DisplayListBuilder::PushText(const wr::LayoutRect& aBounds,
|
||||
const wr::LayoutRect& aClip,
|
||||
bool aIsBackfaceVisible,
|
||||
|
|
|
@ -493,6 +493,14 @@ class DisplayListBuilder final {
|
|||
const wr::LayoutSize aTileSize,
|
||||
const wr::LayoutSize aTileSpacing);
|
||||
|
||||
void PushConicGradient(const wr::LayoutRect& aBounds,
|
||||
const wr::LayoutRect& aClip, bool aIsBackfaceVisible,
|
||||
const wr::LayoutPoint& aCenter, const float aAngle,
|
||||
const nsTArray<wr::GradientStop>& aStops,
|
||||
wr::ExtendMode aExtendMode,
|
||||
const wr::LayoutSize aTileSize,
|
||||
const wr::LayoutSize aTileSpacing);
|
||||
|
||||
void PushImage(const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
|
||||
bool aIsBackfaceVisible, wr::ImageRendering aFilter,
|
||||
wr::ImageKey aImage, bool aPremultipliedAlpha = true,
|
||||
|
@ -557,6 +565,13 @@ class DisplayListBuilder final {
|
|||
const nsTArray<wr::GradientStop>& aStops, wr::ExtendMode aExtendMode,
|
||||
const wr::LayoutSideOffsets& aOutset);
|
||||
|
||||
void PushBorderConicGradient(
|
||||
const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
|
||||
bool aIsBackfaceVisible, const wr::LayoutSideOffsets& aWidths, bool aFill,
|
||||
const wr::LayoutPoint& aCenter, const float aAngle,
|
||||
const nsTArray<wr::GradientStop>& aStops, wr::ExtendMode aExtendMode,
|
||||
const wr::LayoutSideOffsets& aOutset);
|
||||
|
||||
void PushText(const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
|
||||
bool aIsBackfaceVisible, const wr::ColorF& aColor,
|
||||
wr::FontInstanceKey aFontKey,
|
||||
|
|
|
@ -3364,6 +3364,69 @@ pub extern "C" fn wr_dp_push_border_radial_gradient(state: &mut WrState,
|
|||
);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wr_dp_push_border_conic_gradient(state: &mut WrState,
|
||||
rect: LayoutRect,
|
||||
clip: LayoutRect,
|
||||
is_backface_visible: bool,
|
||||
parent: &WrSpaceAndClipChain,
|
||||
widths: LayoutSideOffsets,
|
||||
fill: bool,
|
||||
center: LayoutPoint,
|
||||
angle: f32,
|
||||
stops: *const GradientStop,
|
||||
stops_count: usize,
|
||||
extend_mode: ExtendMode,
|
||||
outset: LayoutSideOffsets) {
|
||||
debug_assert!(unsafe { is_in_main_thread() });
|
||||
|
||||
let stops_slice = unsafe { make_slice(stops, stops_count) };
|
||||
let stops_vector = stops_slice.to_owned();
|
||||
|
||||
let slice = SideOffsets2D::new(
|
||||
widths.top as i32,
|
||||
widths.right as i32,
|
||||
widths.bottom as i32,
|
||||
widths.left as i32,
|
||||
);
|
||||
|
||||
let gradient = state.frame_builder.dl_builder.create_conic_gradient(
|
||||
center.into(),
|
||||
angle,
|
||||
stops_vector,
|
||||
extend_mode.into()
|
||||
);
|
||||
|
||||
let border_details = BorderDetails::NinePatch(NinePatchBorder {
|
||||
source: NinePatchBorderSource::ConicGradient(gradient),
|
||||
width: rect.size.width as i32,
|
||||
height: rect.size.height as i32,
|
||||
slice,
|
||||
fill,
|
||||
outset: outset.into(),
|
||||
repeat_horizontal: RepeatMode::Stretch,
|
||||
repeat_vertical: RepeatMode::Stretch,
|
||||
});
|
||||
|
||||
let space_and_clip = parent.to_webrender(state.pipeline_id);
|
||||
|
||||
let prim_info = CommonItemProperties {
|
||||
clip_rect: clip,
|
||||
clip_id: space_and_clip.clip_id,
|
||||
spatial_id: space_and_clip.spatial_id,
|
||||
flags: prim_flags(is_backface_visible),
|
||||
hit_info: state.current_tag,
|
||||
item_key: state.current_item_key,
|
||||
};
|
||||
|
||||
state.frame_builder.dl_builder.push_border(
|
||||
&prim_info,
|
||||
rect,
|
||||
widths.into(),
|
||||
border_details,
|
||||
);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wr_dp_push_linear_gradient(state: &mut WrState,
|
||||
rect: LayoutRect,
|
||||
|
@ -3453,6 +3516,50 @@ pub extern "C" fn wr_dp_push_radial_gradient(state: &mut WrState,
|
|||
tile_spacing);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wr_dp_push_conic_gradient(state: &mut WrState,
|
||||
rect: LayoutRect,
|
||||
clip: LayoutRect,
|
||||
is_backface_visible: bool,
|
||||
parent: &WrSpaceAndClipChain,
|
||||
center: LayoutPoint,
|
||||
angle: f32,
|
||||
stops: *const GradientStop,
|
||||
stops_count: usize,
|
||||
extend_mode: ExtendMode,
|
||||
tile_size: LayoutSize,
|
||||
tile_spacing: LayoutSize) {
|
||||
debug_assert!(unsafe { is_in_main_thread() });
|
||||
|
||||
let stops_slice = unsafe { make_slice(stops, stops_count) };
|
||||
let stops_vector = stops_slice.to_owned();
|
||||
|
||||
let gradient = state.frame_builder
|
||||
.dl_builder
|
||||
.create_conic_gradient(center.into(),
|
||||
angle,
|
||||
stops_vector,
|
||||
extend_mode.into());
|
||||
|
||||
let space_and_clip = parent.to_webrender(state.pipeline_id);
|
||||
|
||||
let prim_info = CommonItemProperties {
|
||||
clip_rect: clip,
|
||||
clip_id: space_and_clip.clip_id,
|
||||
spatial_id: space_and_clip.spatial_id,
|
||||
flags: prim_flags(is_backface_visible),
|
||||
hit_info: state.current_tag,
|
||||
item_key: state.current_item_key,
|
||||
};
|
||||
|
||||
state.frame_builder.dl_builder.push_conic_gradient(
|
||||
&prim_info,
|
||||
rect,
|
||||
gradient,
|
||||
tile_size,
|
||||
tile_spacing);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wr_dp_push_box_shadow(state: &mut WrState,
|
||||
_rect: LayoutRect,
|
||||
|
|
|
@ -49,6 +49,7 @@ bool gecko_profiler_thread_is_being_profiled();
|
|||
macro(line_decoration); \
|
||||
macro(linear_grad); \
|
||||
macro(radial_grad); \
|
||||
macro(conic_grad); \
|
||||
macro(picture); \
|
||||
macro(text_run); \
|
||||
macro(filterdata); \
|
||||
|
|
|
@ -89,6 +89,7 @@ FWD_DECLARE_VS_FUNCTION(blend_brush_vs)
|
|||
FWD_DECLARE_VS_FUNCTION(mix_blend_brush_vs)
|
||||
FWD_DECLARE_VS_FUNCTION(linear_gradient_brush_vs)
|
||||
FWD_DECLARE_VS_FUNCTION(radial_gradient_brush_vs)
|
||||
FWD_DECLARE_VS_FUNCTION(conic_gradient_brush_vs)
|
||||
FWD_DECLARE_VS_FUNCTION(yuv_brush_vs)
|
||||
FWD_DECLARE_VS_FUNCTION(opacity_brush_vs)
|
||||
|
||||
|
@ -258,6 +259,7 @@ Fragment blend_brush_fs();
|
|||
Fragment mix_blend_brush_fs();
|
||||
Fragment linear_gradient_brush_fs();
|
||||
Fragment radial_gradient_brush_fs();
|
||||
Fragment conic_gradient_brush_fs();
|
||||
Fragment yuv_brush_fs();
|
||||
Fragment opacity_brush_fs();
|
||||
Fragment multi_brush_fs(int brush_kind);
|
||||
|
|
|
@ -0,0 +1,140 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#define VECS_PER_CONIC_GRADIENT_BRUSH 2
|
||||
#define VECS_PER_SPECIFIC_BRUSH VECS_PER_CONIC_GRADIENT_BRUSH
|
||||
|
||||
#define WR_BRUSH_VS_FUNCTION conic_gradient_brush_vs
|
||||
#define WR_BRUSH_FS_FUNCTION conic_gradient_brush_fs
|
||||
|
||||
#include shared,prim_shared,brush
|
||||
|
||||
#define V_GRADIENT_ADDRESS flat_varying_highp_int_address_0
|
||||
|
||||
#define V_CENTER flat_varying_vec4_0.xy
|
||||
#define V_ANGLE flat_varying_vec4_0.z
|
||||
|
||||
// Size of the gradient pattern's rectangle, used to compute horizontal and vertical
|
||||
// repetitions. Not to be confused with another kind of repetition of the pattern
|
||||
// which happens along the gradient stops.
|
||||
#define V_REPEATED_SIZE flat_varying_vec4_1.xy
|
||||
// Repetition along the gradient stops.
|
||||
#define V_GRADIENT_REPEAT flat_varying_vec4_1.z
|
||||
|
||||
#define V_POS varying_vec4_0.zw
|
||||
|
||||
#ifdef WR_FEATURE_ALPHA_PASS
|
||||
#define V_LOCAL_POS varying_vec4_0.xy
|
||||
#define V_TILE_REPEAT flat_varying_vec4_2.xy
|
||||
#endif
|
||||
|
||||
#define PI 3.1415926538
|
||||
|
||||
#ifdef WR_VERTEX_SHADER
|
||||
|
||||
struct ConicGradient {
|
||||
vec2 center_point;
|
||||
float angle;
|
||||
int extend_mode;
|
||||
vec2 stretch_size;
|
||||
};
|
||||
|
||||
ConicGradient fetch_gradient(int address) {
|
||||
vec4 data[2] = fetch_from_gpu_cache_2(address);
|
||||
return ConicGradient(
|
||||
data[0].xy,
|
||||
float(data[0].z),
|
||||
int(data[1].x),
|
||||
data[1].yz
|
||||
);
|
||||
}
|
||||
|
||||
void conic_gradient_brush_vs(
|
||||
VertexInfo vi,
|
||||
int prim_address,
|
||||
RectWithSize local_rect,
|
||||
RectWithSize segment_rect,
|
||||
ivec4 prim_user_data,
|
||||
int specific_resource_address,
|
||||
mat4 transform,
|
||||
PictureTask pic_task,
|
||||
int brush_flags,
|
||||
vec4 texel_rect
|
||||
) {
|
||||
ConicGradient gradient = fetch_gradient(prim_address);
|
||||
|
||||
if ((brush_flags & BRUSH_FLAG_SEGMENT_RELATIVE) != 0) {
|
||||
V_POS = (vi.local_pos - segment_rect.p0) / segment_rect.size;
|
||||
V_POS = V_POS * (texel_rect.zw - texel_rect.xy) + texel_rect.xy;
|
||||
V_POS = V_POS * local_rect.size;
|
||||
} else {
|
||||
V_POS = vi.local_pos - local_rect.p0;
|
||||
}
|
||||
|
||||
V_CENTER = gradient.center_point;
|
||||
V_ANGLE = gradient.angle;
|
||||
|
||||
vec2 tile_repeat = local_rect.size / gradient.stretch_size;
|
||||
V_REPEATED_SIZE = gradient.stretch_size;
|
||||
|
||||
V_GRADIENT_ADDRESS = prim_user_data.x;
|
||||
|
||||
// Whether to repeat the gradient along the line instead of clamping.
|
||||
V_GRADIENT_REPEAT = float(gradient.extend_mode != EXTEND_MODE_CLAMP);
|
||||
|
||||
#ifdef WR_FEATURE_ALPHA_PASS
|
||||
V_TILE_REPEAT = tile_repeat;
|
||||
V_LOCAL_POS = vi.local_pos;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WR_FRAGMENT_SHADER
|
||||
Fragment conic_gradient_brush_fs() {
|
||||
|
||||
#ifdef WR_FEATURE_ALPHA_PASS
|
||||
// Handle top and left inflated edges (see brush_image).
|
||||
vec2 local_pos = max(V_POS, vec2(0.0));
|
||||
|
||||
// Apply potential horizontal and vertical repetitions.
|
||||
vec2 pos = mod(local_pos, V_REPEATED_SIZE);
|
||||
|
||||
vec2 prim_size = V_REPEATED_SIZE * V_TILE_REPEAT;
|
||||
// Handle bottom and right inflated edges (see brush_image).
|
||||
if (local_pos.x >= prim_size.x) {
|
||||
pos.x = V_REPEATED_SIZE.x;
|
||||
}
|
||||
if (local_pos.y >= prim_size.y) {
|
||||
pos.y = V_REPEATED_SIZE.y;
|
||||
}
|
||||
#else
|
||||
// Apply potential horizontal and vertical repetitions.
|
||||
vec2 pos = mod(V_POS, V_REPEATED_SIZE);
|
||||
#endif
|
||||
|
||||
vec2 current_dir = pos - V_CENTER;
|
||||
float current_angle = atan(current_dir.y, current_dir.x) + (PI / 2 - V_ANGLE);
|
||||
float offset = mod(current_angle / (2 * PI), 1.0);
|
||||
|
||||
vec4 color = sample_gradient(V_GRADIENT_ADDRESS,
|
||||
offset,
|
||||
V_GRADIENT_REPEAT);
|
||||
|
||||
#ifdef WR_FEATURE_ALPHA_PASS
|
||||
color *= init_transform_fs(V_LOCAL_POS);
|
||||
#endif
|
||||
|
||||
return Fragment(color);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Undef macro names that could be re-defined by other shaders.
|
||||
#undef V_GRADIENT_ADDRESS
|
||||
#undef V_START_POINT
|
||||
#undef V_SCALE_DIR
|
||||
#undef V_REPEATED_SIZE
|
||||
#undef V_GRADIENT_REPEAT
|
||||
#undef V_POS
|
||||
#undef V_LOCAL_POS
|
||||
#undef V_TILE_REPEAT
|
|
@ -18,10 +18,11 @@
|
|||
#define BRUSH_KIND_TEXT 3
|
||||
#define BRUSH_KIND_LINEAR_GRADIENT 4
|
||||
#define BRUSH_KIND_RADIAL_GRADIENT 5
|
||||
#define BRUSH_KIND_BLEND 6
|
||||
#define BRUSH_KIND_MIX_BLEND 7
|
||||
#define BRUSH_KIND_YV 8
|
||||
#define BRUSH_KIND_OPACITY 9
|
||||
#define BRUSH_KIND_CONIC_GRADIENT 6
|
||||
#define BRUSH_KIND_BLEND 7
|
||||
#define BRUSH_KIND_MIX_BLEND 8
|
||||
#define BRUSH_KIND_YV 9
|
||||
#define BRUSH_KIND_OPACITY 10
|
||||
|
||||
int vecs_per_brush(int brush_kind);
|
||||
|
||||
|
@ -75,6 +76,14 @@ int vecs_per_brush(int brush_kind);
|
|||
#undef WR_BRUSH_VS_FUNCTION
|
||||
#undef WR_BRUSH_FS_FUNCTION
|
||||
|
||||
#ifdef WR_FEATURE_CONIC_GRADIENT_BRUSH
|
||||
#include brush_conic_gradient
|
||||
#endif
|
||||
|
||||
#undef VECS_PER_SPECIFIC_BRUSH
|
||||
#undef WR_BRUSH_VS_FUNCTION
|
||||
#undef WR_BRUSH_FS_FUNCTION
|
||||
|
||||
#ifdef WR_FEATURE_OPACITY_BRUSH
|
||||
#include brush_opacity
|
||||
#endif
|
||||
|
@ -109,6 +118,11 @@ int vecs_per_brush(int brush_kind) {
|
|||
case BRUSH_KIND_RADIAL_GRADIENT: return VECS_PER_RADIAL_GRADIENT_BRUSH;
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef WR_FEATURE_CONIC_GRADIENT_BRUSH
|
||||
case BRUSH_KIND_CONIC_GRADIENT: return VECS_PER_CONIC_GRADIENT_BRUSH;
|
||||
#endif
|
||||
|
||||
#ifdef WR_FEATURE_OPACITY_BRUSH
|
||||
case BRUSH_KIND_OPACITY: return VECS_PER_OPACITY_BRUSH;
|
||||
#endif
|
||||
|
@ -173,6 +187,12 @@ void multi_brush_vs(
|
|||
break;
|
||||
#endif
|
||||
|
||||
#ifdef WR_FEATURE_CONIC_GRADIENT_BRUSH
|
||||
case BRUSH_KIND_CONIC_GRADIENT:
|
||||
conic_gradient_brush_vs(BRUSH_VS_PARAMS);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef WR_FEATURE_OPACITY_BRUSH
|
||||
case BRUSH_KIND_OPACITY:
|
||||
opacity_brush_vs(BRUSH_VS_PARAMS);
|
||||
|
@ -213,6 +233,10 @@ Fragment multi_brush_fs(int brush_kind) {
|
|||
case BRUSH_KIND_RADIAL_GRADIENT: return radial_gradient_brush_fs();
|
||||
#endif
|
||||
|
||||
#ifdef WR_FEATURE_CONIC_GRADIENT_BRUSH
|
||||
case BRUSH_KIND_CONIC_GRADIENT: return conic_gradient_brush_fs();
|
||||
#endif
|
||||
|
||||
#ifdef WR_FEATURE_OPACITY_BRUSH
|
||||
case BRUSH_KIND_OPACITY: return opacity_brush_fs();
|
||||
#endif
|
||||
|
|
|
@ -56,6 +56,7 @@ pub enum BrushBatchKind {
|
|||
backdrop_id: RenderTaskId,
|
||||
},
|
||||
YuvImage(ImageBufferKind, YuvFormat, ColorDepth, YuvColorSpace, ColorRange),
|
||||
ConicGradient,
|
||||
RadialGradient,
|
||||
LinearGradient,
|
||||
Opacity,
|
||||
|
@ -77,6 +78,7 @@ impl BatchKind {
|
|||
BatchKind::Brush(BrushBatchKind::Image(..)) => BrushShaderKind::Image,
|
||||
BatchKind::Brush(BrushBatchKind::LinearGradient) => BrushShaderKind::LinearGradient,
|
||||
BatchKind::Brush(BrushBatchKind::RadialGradient) => BrushShaderKind::RadialGradient,
|
||||
BatchKind::Brush(BrushBatchKind::ConicGradient) => BrushShaderKind::ConicGradient,
|
||||
BatchKind::Brush(BrushBatchKind::Blend) => BrushShaderKind::Blend,
|
||||
BatchKind::Brush(BrushBatchKind::MixBlend { .. }) => BrushShaderKind::MixBlend,
|
||||
BatchKind::Brush(BrushBatchKind::YuvImage(..)) => BrushShaderKind::Yuv,
|
||||
|
@ -2330,6 +2332,87 @@ impl BatchBuilder {
|
|||
);
|
||||
}
|
||||
}
|
||||
PrimitiveInstanceKind::ConicGradient { data_handle, ref visible_tiles_range, .. } => {
|
||||
let prim_data = &ctx.data_stores.conic_grad[data_handle];
|
||||
let specified_blend_mode = BlendMode::PremultipliedAlpha;
|
||||
|
||||
let mut prim_header = PrimitiveHeader {
|
||||
local_rect: prim_rect,
|
||||
local_clip_rect: prim_info.combined_local_clip_rect,
|
||||
specific_prim_address: GpuCacheAddress::INVALID,
|
||||
transform_id,
|
||||
};
|
||||
|
||||
if visible_tiles_range.is_empty() {
|
||||
let non_segmented_blend_mode = if !prim_data.opacity.is_opaque ||
|
||||
prim_info.clip_task_index != ClipTaskIndex::INVALID ||
|
||||
transform_kind == TransformedRectKind::Complex
|
||||
{
|
||||
specified_blend_mode
|
||||
} else {
|
||||
BlendMode::None
|
||||
};
|
||||
|
||||
let batch_params = BrushBatchParameters::shared(
|
||||
BrushBatchKind::ConicGradient,
|
||||
BatchTextures::no_texture(),
|
||||
[
|
||||
prim_data.stops_handle.as_int(gpu_cache),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
],
|
||||
0,
|
||||
);
|
||||
|
||||
prim_header.specific_prim_address = gpu_cache.get_address(&prim_data.gpu_cache_handle);
|
||||
|
||||
let prim_header_index = prim_headers.push(
|
||||
&prim_header,
|
||||
z_id,
|
||||
batch_params.prim_user_data,
|
||||
);
|
||||
|
||||
let segments = if prim_data.brush_segments.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(prim_data.brush_segments.as_slice())
|
||||
};
|
||||
|
||||
self.add_segmented_prim_to_batch(
|
||||
segments,
|
||||
prim_data.opacity,
|
||||
&batch_params,
|
||||
specified_blend_mode,
|
||||
non_segmented_blend_mode,
|
||||
batch_features,
|
||||
prim_header_index,
|
||||
bounding_rect,
|
||||
transform_kind,
|
||||
render_tasks,
|
||||
z_id,
|
||||
prim_info.clip_task_index,
|
||||
prim_vis_mask,
|
||||
ctx,
|
||||
);
|
||||
} else {
|
||||
let visible_tiles = &ctx.scratch.gradient_tiles[*visible_tiles_range];
|
||||
|
||||
self.add_gradient_tiles(
|
||||
visible_tiles,
|
||||
&prim_data.stops_handle,
|
||||
BrushBatchKind::ConicGradient,
|
||||
specified_blend_mode,
|
||||
bounding_rect,
|
||||
clip_task_address.unwrap(),
|
||||
gpu_cache,
|
||||
&prim_header,
|
||||
prim_headers,
|
||||
z_id,
|
||||
prim_vis_mask,
|
||||
);
|
||||
}
|
||||
}
|
||||
PrimitiveInstanceKind::Backdrop { data_handle } => {
|
||||
let prim_data = &ctx.data_stores.backdrop[data_handle];
|
||||
let backdrop_pic_index = prim_data.kind.pic_index;
|
||||
|
|
|
@ -78,10 +78,11 @@ pub enum BrushShaderKind {
|
|||
Text = 3,
|
||||
LinearGradient = 4,
|
||||
RadialGradient = 5,
|
||||
Blend = 6,
|
||||
MixBlend = 7,
|
||||
Yuv = 8,
|
||||
Opacity = 9,
|
||||
ConicGradient = 6,
|
||||
Blend = 7,
|
||||
MixBlend = 8,
|
||||
Yuv = 9,
|
||||
Opacity = 10,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
|
|
|
@ -122,7 +122,7 @@ use crate::prim_store::backdrop::Backdrop;
|
|||
#[cfg(any(feature = "capture", feature = "replay"))]
|
||||
use crate::prim_store::borders::{ImageBorder, NormalBorderPrim};
|
||||
#[cfg(any(feature = "capture", feature = "replay"))]
|
||||
use crate::prim_store::gradient::{LinearGradient, RadialGradient};
|
||||
use crate::prim_store::gradient::{LinearGradient, RadialGradient, ConicGradient};
|
||||
#[cfg(any(feature = "capture", feature = "replay"))]
|
||||
use crate::prim_store::image::{Image, YuvImage};
|
||||
#[cfg(any(feature = "capture", feature = "replay"))]
|
||||
|
@ -2714,6 +2714,7 @@ impl TileCacheInstance {
|
|||
PrimitiveInstanceKind::NormalBorder { .. } |
|
||||
PrimitiveInstanceKind::LinearGradient { .. } |
|
||||
PrimitiveInstanceKind::RadialGradient { .. } |
|
||||
PrimitiveInstanceKind::ConicGradient { .. } |
|
||||
PrimitiveInstanceKind::Backdrop { .. } => {
|
||||
// These don't contribute dependencies
|
||||
}
|
||||
|
|
|
@ -562,6 +562,222 @@ impl IsVisible for RadialGradient {
|
|||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Conic gradients
|
||||
|
||||
/// Hashable conic gradient parameters, for use during prim interning.
|
||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
#[derive(Debug, Clone, MallocSizeOf, PartialEq)]
|
||||
pub struct ConicGradientAngle {
|
||||
pub angle: f32, // in radians
|
||||
}
|
||||
|
||||
impl Eq for ConicGradientAngle {}
|
||||
|
||||
impl hash::Hash for ConicGradientAngle {
|
||||
fn hash<H: hash::Hasher>(&self, state: &mut H) {
|
||||
self.angle.to_bits().hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
/// Identifying key for a line decoration.
|
||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Hash, MallocSizeOf)]
|
||||
pub struct ConicGradientKey {
|
||||
pub common: PrimKeyCommonData,
|
||||
pub extend_mode: ExtendMode,
|
||||
pub center: PointKey,
|
||||
pub angle: ConicGradientAngle,
|
||||
pub stretch_size: SizeKey,
|
||||
pub stops: Vec<GradientStopKey>,
|
||||
pub tile_spacing: SizeKey,
|
||||
pub nine_patch: Option<Box<NinePatchDescriptor>>,
|
||||
}
|
||||
|
||||
impl ConicGradientKey {
|
||||
pub fn new(
|
||||
flags: PrimitiveFlags,
|
||||
prim_size: LayoutSize,
|
||||
conic_grad: ConicGradient,
|
||||
) -> Self {
|
||||
ConicGradientKey {
|
||||
common: PrimKeyCommonData {
|
||||
flags,
|
||||
prim_size: prim_size.into(),
|
||||
},
|
||||
extend_mode: conic_grad.extend_mode,
|
||||
center: conic_grad.center,
|
||||
angle: conic_grad.angle,
|
||||
stretch_size: conic_grad.stretch_size,
|
||||
stops: conic_grad.stops,
|
||||
tile_spacing: conic_grad.tile_spacing,
|
||||
nine_patch: conic_grad.nine_patch,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl InternDebug for ConicGradientKey {}
|
||||
|
||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
#[derive(MallocSizeOf)]
|
||||
pub struct ConicGradientTemplate {
|
||||
pub common: PrimTemplateCommonData,
|
||||
pub extend_mode: ExtendMode,
|
||||
pub center: LayoutPoint,
|
||||
pub angle: ConicGradientAngle,
|
||||
pub stretch_size: LayoutSize,
|
||||
pub tile_spacing: LayoutSize,
|
||||
pub brush_segments: Vec<BrushSegment>,
|
||||
pub stops: Vec<GradientStop>,
|
||||
pub stops_handle: GpuCacheHandle,
|
||||
}
|
||||
|
||||
impl Deref for ConicGradientTemplate {
|
||||
type Target = PrimTemplateCommonData;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.common
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for ConicGradientTemplate {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.common
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ConicGradientKey> for ConicGradientTemplate {
|
||||
fn from(item: ConicGradientKey) -> Self {
|
||||
let common = PrimTemplateCommonData::with_key_common(item.common);
|
||||
let mut brush_segments = Vec::new();
|
||||
|
||||
if let Some(ref nine_patch) = item.nine_patch {
|
||||
brush_segments = nine_patch.create_segments(common.prim_size);
|
||||
}
|
||||
|
||||
let stops = item.stops.iter().map(|stop| {
|
||||
GradientStop {
|
||||
offset: stop.offset,
|
||||
color: stop.color.into(),
|
||||
}
|
||||
}).collect();
|
||||
|
||||
ConicGradientTemplate {
|
||||
common,
|
||||
center: item.center.into(),
|
||||
extend_mode: item.extend_mode,
|
||||
angle: item.angle,
|
||||
stretch_size: item.stretch_size.into(),
|
||||
tile_spacing: item.tile_spacing.into(),
|
||||
brush_segments,
|
||||
stops,
|
||||
stops_handle: GpuCacheHandle::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ConicGradientTemplate {
|
||||
/// Update the GPU cache for a given primitive template. This may be called multiple
|
||||
/// times per frame, by each primitive reference that refers to this interned
|
||||
/// template. The initial request call to the GPU cache ensures that work is only
|
||||
/// done if the cache entry is invalid (due to first use or eviction).
|
||||
pub fn update(
|
||||
&mut self,
|
||||
frame_state: &mut FrameBuildingState,
|
||||
) {
|
||||
if let Some(mut request) =
|
||||
frame_state.gpu_cache.request(&mut self.common.gpu_cache_handle) {
|
||||
// write_prim_gpu_blocks
|
||||
request.push([
|
||||
self.center.x,
|
||||
self.center.y,
|
||||
self.angle.angle,
|
||||
0.0,
|
||||
]);
|
||||
request.push([
|
||||
pack_as_float(self.extend_mode as u32),
|
||||
self.stretch_size.width,
|
||||
self.stretch_size.height,
|
||||
0.0,
|
||||
]);
|
||||
|
||||
// write_segment_gpu_blocks
|
||||
for segment in &self.brush_segments {
|
||||
// has to match VECS_PER_SEGMENT
|
||||
request.write_segment(
|
||||
segment.local_rect,
|
||||
segment.extra_data,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(mut request) = frame_state.gpu_cache.request(&mut self.stops_handle) {
|
||||
GradientGpuBlockBuilder::build(
|
||||
false,
|
||||
&mut request,
|
||||
&self.stops,
|
||||
);
|
||||
}
|
||||
|
||||
self.opacity = PrimitiveOpacity::translucent();
|
||||
}
|
||||
}
|
||||
|
||||
pub type ConicGradientDataHandle = InternHandle<ConicGradient>;
|
||||
|
||||
#[derive(Debug, MallocSizeOf)]
|
||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
pub struct ConicGradient {
|
||||
pub extend_mode: ExtendMode,
|
||||
pub center: PointKey,
|
||||
pub angle: ConicGradientAngle,
|
||||
pub stretch_size: SizeKey,
|
||||
pub stops: Vec<GradientStopKey>,
|
||||
pub tile_spacing: SizeKey,
|
||||
pub nine_patch: Option<Box<NinePatchDescriptor>>,
|
||||
}
|
||||
|
||||
impl Internable for ConicGradient {
|
||||
type Key = ConicGradientKey;
|
||||
type StoreData = ConicGradientTemplate;
|
||||
type InternData = PrimitiveSceneData;
|
||||
}
|
||||
|
||||
impl InternablePrimitive for ConicGradient {
|
||||
fn into_key(
|
||||
self,
|
||||
info: &LayoutPrimitiveInfo,
|
||||
) -> ConicGradientKey {
|
||||
ConicGradientKey::new(
|
||||
info.flags,
|
||||
info.rect.size,
|
||||
self,
|
||||
)
|
||||
}
|
||||
|
||||
fn make_instance_kind(
|
||||
_key: ConicGradientKey,
|
||||
data_handle: ConicGradientDataHandle,
|
||||
_prim_store: &mut PrimitiveStore,
|
||||
_reference_frame_relative_offset: LayoutVector2D,
|
||||
) -> PrimitiveInstanceKind {
|
||||
PrimitiveInstanceKind::ConicGradient {
|
||||
data_handle,
|
||||
visible_tiles_range: GradientTileRange::empty(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IsVisible for ConicGradient {
|
||||
fn is_visible(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// The gradient entry index for the first color stop
|
||||
pub const GRADIENT_DATA_FIRST_STOP: usize = 0;
|
||||
// The gradient entry index for the last color stop
|
||||
|
@ -783,4 +999,8 @@ fn test_struct_sizes() {
|
|||
assert_eq!(mem::size_of::<RadialGradient>(), 72, "RadialGradient size changed");
|
||||
assert_eq!(mem::size_of::<RadialGradientTemplate>(), 120, "RadialGradientTemplate size changed");
|
||||
assert_eq!(mem::size_of::<RadialGradientKey>(), 88, "RadialGradientKey size changed");
|
||||
|
||||
assert_eq!(mem::size_of::<ConicGradient>(), 64, "ConicGradient size changed");
|
||||
assert_eq!(mem::size_of::<ConicGradientTemplate>(), 112, "ConicGradientTemplate size changed");
|
||||
assert_eq!(mem::size_of::<ConicGradientKey>(), 80, "ConicGradientKey size changed");
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ pub use crate::prim_store::backdrop::Backdrop;
|
|||
pub use crate::prim_store::borders::{ImageBorder, NormalBorderPrim};
|
||||
pub use crate::prim_store::image::{Image, YuvImage};
|
||||
pub use crate::prim_store::line_dec::{LineDecoration};
|
||||
pub use crate::prim_store::gradient::{LinearGradient, RadialGradient};
|
||||
pub use crate::prim_store::gradient::{LinearGradient, RadialGradient, ConicGradient};
|
||||
pub use crate::prim_store::picture::Picture;
|
||||
pub use crate::prim_store::text_run::TextRun;
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ use crate::picture::{PrimitiveList, RecordedDirtyRegion, SurfaceIndex, RetainedT
|
|||
use crate::prim_store::backdrop::BackdropDataHandle;
|
||||
use crate::prim_store::borders::{ImageBorderDataHandle, NormalBorderDataHandle};
|
||||
use crate::prim_store::gradient::{GRADIENT_FP_STOPS, GradientCacheKey, GradientStopKey};
|
||||
use crate::prim_store::gradient::{LinearGradientPrimitive, LinearGradientDataHandle, RadialGradientDataHandle};
|
||||
use crate::prim_store::gradient::{LinearGradientPrimitive, LinearGradientDataHandle, RadialGradientDataHandle, ConicGradientDataHandle};
|
||||
use crate::prim_store::image::{ImageDataHandle, ImageInstance, VisibleImageTile, YuvImageDataHandle};
|
||||
use crate::prim_store::line_dec::LineDecorationDataHandle;
|
||||
use crate::prim_store::picture::PictureDataHandle;
|
||||
|
@ -1426,6 +1426,11 @@ pub enum PrimitiveInstanceKind {
|
|||
data_handle: RadialGradientDataHandle,
|
||||
visible_tiles_range: GradientTileRange,
|
||||
},
|
||||
ConicGradient {
|
||||
/// Handle to the common interned data for this primitive.
|
||||
data_handle: ConicGradientDataHandle,
|
||||
visible_tiles_range: GradientTileRange,
|
||||
},
|
||||
/// Clear out a rect, used for special effects.
|
||||
Clear {
|
||||
/// Handle to the common interned data for this primitive.
|
||||
|
@ -1623,6 +1628,9 @@ impl PrimitiveInstance {
|
|||
PrimitiveInstanceKind::RadialGradient { data_handle, .. } => {
|
||||
data_handle.uid()
|
||||
}
|
||||
PrimitiveInstanceKind::ConicGradient { data_handle, .. } => {
|
||||
data_handle.uid()
|
||||
}
|
||||
PrimitiveInstanceKind::TextRun { data_handle, .. } => {
|
||||
data_handle.uid()
|
||||
}
|
||||
|
@ -2240,6 +2248,7 @@ impl PrimitiveStore {
|
|||
PrimitiveInstanceKind::Image { .. } => debug_colors::BLUE,
|
||||
PrimitiveInstanceKind::LinearGradient { .. } => debug_colors::PINK,
|
||||
PrimitiveInstanceKind::RadialGradient { .. } => debug_colors::PINK,
|
||||
PrimitiveInstanceKind::ConicGradient { .. } => debug_colors::PINK,
|
||||
PrimitiveInstanceKind::Clear { .. } => debug_colors::CYAN,
|
||||
PrimitiveInstanceKind::Backdrop { .. } => debug_colors::MEDIUMAQUAMARINE,
|
||||
};
|
||||
|
@ -2559,6 +2568,7 @@ impl PrimitiveStore {
|
|||
PrimitiveInstanceKind::YuvImage { .. } |
|
||||
PrimitiveInstanceKind::LinearGradient { .. } |
|
||||
PrimitiveInstanceKind::RadialGradient { .. } |
|
||||
PrimitiveInstanceKind::ConicGradient { .. } |
|
||||
PrimitiveInstanceKind::PushClipChain |
|
||||
PrimitiveInstanceKind::PopClipChain |
|
||||
PrimitiveInstanceKind::LineDecoration { .. } |
|
||||
|
@ -2702,6 +2712,7 @@ impl PrimitiveStore {
|
|||
PrimitiveInstanceKind::Image { .. } |
|
||||
PrimitiveInstanceKind::LinearGradient { .. } |
|
||||
PrimitiveInstanceKind::RadialGradient { .. } |
|
||||
PrimitiveInstanceKind::ConicGradient { .. } |
|
||||
PrimitiveInstanceKind::PushClipChain |
|
||||
PrimitiveInstanceKind::PopClipChain |
|
||||
PrimitiveInstanceKind::Clear { .. } |
|
||||
|
@ -3327,6 +3338,70 @@ impl PrimitiveStore {
|
|||
// TODO(gw): Consider whether it's worth doing segment building
|
||||
// for gradient primitives.
|
||||
}
|
||||
PrimitiveInstanceKind::ConicGradient { data_handle, ref mut visible_tiles_range, .. } => {
|
||||
let prim_data = &mut data_stores.conic_grad[*data_handle];
|
||||
|
||||
if prim_data.stretch_size.width >= prim_data.common.prim_size.width &&
|
||||
prim_data.stretch_size.height >= prim_data.common.prim_size.height {
|
||||
|
||||
// We are performing the decomposition on the CPU here, no need to
|
||||
// have it in the shader.
|
||||
prim_data.common.may_need_repetition = false;
|
||||
}
|
||||
|
||||
// Update the template this instane references, which may refresh the GPU
|
||||
// cache with any shared template data.
|
||||
prim_data.update(frame_state);
|
||||
|
||||
if prim_data.tile_spacing != LayoutSize::zero() {
|
||||
let prim_info = &scratch.prim_info[prim_instance.visibility_info.0 as usize];
|
||||
let prim_rect = LayoutRect::new(
|
||||
prim_instance.prim_origin,
|
||||
prim_data.common.prim_size,
|
||||
);
|
||||
|
||||
let map_local_to_world = SpaceMapper::new_with_target(
|
||||
ROOT_SPATIAL_NODE_INDEX,
|
||||
prim_spatial_node_index,
|
||||
frame_context.global_screen_world_rect,
|
||||
frame_context.spatial_tree,
|
||||
);
|
||||
|
||||
prim_data.common.may_need_repetition = false;
|
||||
|
||||
*visible_tiles_range = decompose_repeated_primitive(
|
||||
&prim_info.combined_local_clip_rect,
|
||||
&prim_rect,
|
||||
prim_info.clipped_world_rect,
|
||||
&prim_data.stretch_size,
|
||||
&prim_data.tile_spacing,
|
||||
frame_state,
|
||||
&mut scratch.gradient_tiles,
|
||||
&map_local_to_world,
|
||||
&mut |_, mut request| {
|
||||
request.push([
|
||||
prim_data.center.x,
|
||||
prim_data.center.y,
|
||||
prim_data.angle.angle,
|
||||
0.0,
|
||||
]);
|
||||
request.push([
|
||||
pack_as_float(prim_data.extend_mode as u32),
|
||||
prim_data.stretch_size.width,
|
||||
prim_data.stretch_size.height,
|
||||
0.0,
|
||||
]);
|
||||
},
|
||||
);
|
||||
|
||||
if visible_tiles_range.is_empty() {
|
||||
prim_instance.visibility_info = PrimitiveVisibilityIndex::INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(gw): Consider whether it's worth doing segment building
|
||||
// for gradient primitives.
|
||||
}
|
||||
PrimitiveInstanceKind::Picture { pic_index, segment_instance_index, data_handle, .. } => {
|
||||
let pic = &mut self.pictures[pic_index.0];
|
||||
let prim_info = &scratch.prim_info[prim_instance.visibility_info.0 as usize];
|
||||
|
@ -3718,6 +3793,7 @@ impl PrimitiveInstance {
|
|||
PrimitiveInstanceKind::Clear { .. } |
|
||||
PrimitiveInstanceKind::LinearGradient { .. } |
|
||||
PrimitiveInstanceKind::RadialGradient { .. } |
|
||||
PrimitiveInstanceKind::ConicGradient { .. } |
|
||||
PrimitiveInstanceKind::PushClipChain |
|
||||
PrimitiveInstanceKind::PopClipChain |
|
||||
PrimitiveInstanceKind::LineDecoration { .. } |
|
||||
|
@ -3863,6 +3939,17 @@ impl PrimitiveInstance {
|
|||
return false;
|
||||
}
|
||||
|
||||
prim_data.brush_segments.as_slice()
|
||||
}
|
||||
PrimitiveInstanceKind::ConicGradient { data_handle, .. } => {
|
||||
let prim_data = &data_stores.conic_grad[data_handle];
|
||||
|
||||
// TODO: This is quite messy - once we remove legacy primitives we
|
||||
// can change this to be a tuple match on (instance, template)
|
||||
if prim_data.brush_segments.is_empty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
prim_data.brush_segments.as_slice()
|
||||
}
|
||||
};
|
||||
|
|
|
@ -805,6 +805,7 @@ impl BackendProfileCounters {
|
|||
//TODO: generate this by a macro
|
||||
intern: InternProfileCounters {
|
||||
prim: ResourceProfileCounter::new("Interned primitives", None, None),
|
||||
conic_grad: ResourceProfileCounter::new("Interned conic gradients", None, None),
|
||||
image: ResourceProfileCounter::new("Interned images", None, None),
|
||||
image_border: ResourceProfileCounter::new("Interned image borders", None, None),
|
||||
line_decoration: ResourceProfileCounter::new("Interned line decorations", None, None),
|
||||
|
|
|
@ -309,6 +309,10 @@ impl DataStores {
|
|||
let prim_data = &self.radial_grad[data_handle];
|
||||
&prim_data.common
|
||||
}
|
||||
PrimitiveInstanceKind::ConicGradient { data_handle, .. } => {
|
||||
let prim_data = &self.conic_grad[data_handle];
|
||||
&prim_data.common
|
||||
}
|
||||
PrimitiveInstanceKind::TextRun { data_handle, .. } => {
|
||||
let prim_data = &self.text_run[data_handle];
|
||||
&prim_data.common
|
||||
|
|
|
@ -153,6 +153,10 @@ const GPU_TAG_BRUSH_RADIAL_GRADIENT: GpuProfileTag = GpuProfileTag {
|
|||
label: "B_RadialGradient",
|
||||
color: debug_colors::LIGHTPINK,
|
||||
};
|
||||
const GPU_TAG_BRUSH_CONIC_GRADIENT: GpuProfileTag = GpuProfileTag {
|
||||
label: "B_ConicGradient",
|
||||
color: debug_colors::GREEN,
|
||||
};
|
||||
const GPU_TAG_BRUSH_YUV_IMAGE: GpuProfileTag = GpuProfileTag {
|
||||
label: "B_YuvImage",
|
||||
color: debug_colors::DARKGREEN,
|
||||
|
@ -255,6 +259,7 @@ impl BatchKind {
|
|||
BrushBatchKind::Blend => "Brush (Blend)",
|
||||
BrushBatchKind::MixBlend { .. } => "Brush (Composite)",
|
||||
BrushBatchKind::YuvImage(..) => "Brush (YuvImage)",
|
||||
BrushBatchKind::ConicGradient => "Brush (ConicGradient)",
|
||||
BrushBatchKind::RadialGradient => "Brush (RadialGradient)",
|
||||
BrushBatchKind::LinearGradient => "Brush (LinearGradient)",
|
||||
BrushBatchKind::Opacity => "Brush (Opacity)",
|
||||
|
@ -274,6 +279,7 @@ impl BatchKind {
|
|||
BrushBatchKind::Blend => GPU_TAG_BRUSH_BLEND,
|
||||
BrushBatchKind::MixBlend { .. } => GPU_TAG_BRUSH_MIXBLEND,
|
||||
BrushBatchKind::YuvImage(..) => GPU_TAG_BRUSH_YUV_IMAGE,
|
||||
BrushBatchKind::ConicGradient => GPU_TAG_BRUSH_CONIC_GRADIENT,
|
||||
BrushBatchKind::RadialGradient => GPU_TAG_BRUSH_RADIAL_GRADIENT,
|
||||
BrushBatchKind::LinearGradient => GPU_TAG_BRUSH_LINEAR_GRADIENT,
|
||||
BrushBatchKind::Opacity => GPU_TAG_BRUSH_OPACITY,
|
||||
|
@ -6865,6 +6871,7 @@ fn should_skip_batch(kind: &BatchKind, flags: DebugFlags) -> bool {
|
|||
BatchKind::TextRun(_) => {
|
||||
flags.contains(DebugFlags::DISABLE_TEXT_PRIMS)
|
||||
}
|
||||
BatchKind::Brush(BrushBatchKind::ConicGradient) |
|
||||
BatchKind::Brush(BrushBatchKind::RadialGradient) |
|
||||
BatchKind::Brush(BrushBatchKind::LinearGradient) => {
|
||||
flags.contains(DebugFlags::DISABLE_GRADIENT_PRIMS)
|
||||
|
|
|
@ -17,7 +17,7 @@ use crate::internal_types::{FastHashMap, FastHashSet};
|
|||
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
|
||||
use crate::prim_store::backdrop::Backdrop;
|
||||
use crate::prim_store::borders::{ImageBorder, NormalBorderPrim};
|
||||
use crate::prim_store::gradient::{LinearGradient, RadialGradient};
|
||||
use crate::prim_store::gradient::{LinearGradient, RadialGradient, ConicGradient};
|
||||
use crate::prim_store::image::{Image, YuvImage};
|
||||
use crate::prim_store::line_dec::LineDecoration;
|
||||
use crate::prim_store::picture::Picture;
|
||||
|
|
|
@ -31,7 +31,7 @@ use crate::prim_store::{register_prim_chase_id, get_line_decoration_size};
|
|||
use crate::prim_store::{SpaceSnapper};
|
||||
use crate::prim_store::backdrop::Backdrop;
|
||||
use crate::prim_store::borders::{ImageBorder, NormalBorderPrim};
|
||||
use crate::prim_store::gradient::{GradientStopKey, LinearGradient, RadialGradient, RadialGradientParams};
|
||||
use crate::prim_store::gradient::{GradientStopKey, LinearGradient, RadialGradient, RadialGradientParams, ConicGradient, ConicGradientAngle};
|
||||
use crate::prim_store::image::{Image, YuvImage};
|
||||
use crate::prim_store::line_dec::{LineDecoration, LineDecorationCacheKey};
|
||||
use crate::prim_store::picture::{Picture, PictureCompositeKey, PictureKey};
|
||||
|
@ -1311,6 +1311,37 @@ impl<'a> SceneBuilder<'a> {
|
|||
prim_key_kind,
|
||||
);
|
||||
}
|
||||
DisplayItem::ConicGradient(ref info) => {
|
||||
let (layout, unsnapped_rect, clip_and_scroll) = self.process_common_properties_with_bounds(
|
||||
&info.common,
|
||||
&info.bounds,
|
||||
apply_pipeline_clip,
|
||||
);
|
||||
|
||||
let tile_size = process_repeat_size(
|
||||
&layout.rect,
|
||||
&unsnapped_rect,
|
||||
info.tile_size,
|
||||
);
|
||||
|
||||
let prim_key_kind = self.create_conic_gradient_prim(
|
||||
&layout,
|
||||
info.gradient.center,
|
||||
info.gradient.angle,
|
||||
item.gradient_stops(),
|
||||
info.gradient.extend_mode,
|
||||
tile_size,
|
||||
info.tile_spacing,
|
||||
None,
|
||||
);
|
||||
|
||||
self.add_nonshadowable_primitive(
|
||||
clip_and_scroll,
|
||||
&layout,
|
||||
Vec::new(),
|
||||
prim_key_kind,
|
||||
);
|
||||
}
|
||||
DisplayItem::BoxShadow(ref info) => {
|
||||
let (layout, _, clip_and_scroll) = self.process_common_properties_with_bounds(
|
||||
&info.common,
|
||||
|
@ -2893,6 +2924,25 @@ impl<'a> SceneBuilder<'a> {
|
|||
Some(Box::new(nine_patch)),
|
||||
);
|
||||
|
||||
self.add_nonshadowable_primitive(
|
||||
clip_and_scroll,
|
||||
info,
|
||||
Vec::new(),
|
||||
prim,
|
||||
);
|
||||
}
|
||||
NinePatchBorderSource::ConicGradient(gradient) => {
|
||||
let prim = self.create_conic_gradient_prim(
|
||||
&info,
|
||||
gradient.center,
|
||||
gradient.angle,
|
||||
gradient_stops,
|
||||
gradient.extend_mode,
|
||||
LayoutSize::new(border.height as f32, border.width as f32),
|
||||
LayoutSize::zero(),
|
||||
Some(Box::new(nine_patch)),
|
||||
);
|
||||
|
||||
self.add_nonshadowable_primitive(
|
||||
clip_and_scroll,
|
||||
info,
|
||||
|
@ -3013,6 +3063,38 @@ impl<'a> SceneBuilder<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn create_conic_gradient_prim(
|
||||
&mut self,
|
||||
info: &LayoutPrimitiveInfo,
|
||||
center: LayoutPoint,
|
||||
angle: f32,
|
||||
stops: ItemRange<GradientStop>,
|
||||
extend_mode: ExtendMode,
|
||||
stretch_size: LayoutSize,
|
||||
mut tile_spacing: LayoutSize,
|
||||
nine_patch: Option<Box<NinePatchDescriptor>>,
|
||||
) -> ConicGradient {
|
||||
let mut prim_rect = info.rect;
|
||||
simplify_repeated_primitive(&stretch_size, &mut tile_spacing, &mut prim_rect);
|
||||
|
||||
let stops = stops.iter().map(|stop| {
|
||||
GradientStopKey {
|
||||
offset: stop.offset,
|
||||
color: stop.color.into(),
|
||||
}
|
||||
}).collect();
|
||||
|
||||
ConicGradient {
|
||||
extend_mode,
|
||||
center: center.into(),
|
||||
angle: ConicGradientAngle { angle },
|
||||
stretch_size: stretch_size.into(),
|
||||
tile_spacing: tile_spacing.into(),
|
||||
nine_patch,
|
||||
stops,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_text(
|
||||
&mut self,
|
||||
clip_and_scroll: ScrollNodeAndClipChain,
|
||||
|
|
|
@ -536,6 +536,7 @@ pub struct Shaders {
|
|||
brush_blend: BrushShader,
|
||||
brush_mix_blend: BrushShader,
|
||||
brush_yuv_image: Vec<Option<BrushShader>>,
|
||||
brush_conic_gradient: BrushShader,
|
||||
brush_radial_gradient: BrushShader,
|
||||
brush_linear_gradient: BrushShader,
|
||||
brush_opacity: BrushShader,
|
||||
|
@ -614,6 +615,20 @@ impl Shaders {
|
|||
use_pixel_local_storage,
|
||||
)?;
|
||||
|
||||
let brush_conic_gradient = BrushShader::new(
|
||||
"brush_conic_gradient",
|
||||
device,
|
||||
if options.enable_dithering {
|
||||
&[DITHERING_FEATURE]
|
||||
} else {
|
||||
&[]
|
||||
},
|
||||
options.precache_flags,
|
||||
false /* advanced blend */,
|
||||
false /* dual source */,
|
||||
use_pixel_local_storage,
|
||||
)?;
|
||||
|
||||
let brush_radial_gradient = BrushShader::new(
|
||||
"brush_radial_gradient",
|
||||
device,
|
||||
|
@ -904,6 +919,7 @@ impl Shaders {
|
|||
brush_blend,
|
||||
brush_mix_blend,
|
||||
brush_yuv_image,
|
||||
brush_conic_gradient,
|
||||
brush_radial_gradient,
|
||||
brush_linear_gradient,
|
||||
brush_opacity,
|
||||
|
@ -953,6 +969,9 @@ impl Shaders {
|
|||
BrushBatchKind::MixBlend { .. } => {
|
||||
&mut self.brush_mix_blend
|
||||
}
|
||||
BrushBatchKind::ConicGradient => {
|
||||
&mut self.brush_conic_gradient
|
||||
}
|
||||
BrushBatchKind::RadialGradient => {
|
||||
&mut self.brush_radial_gradient
|
||||
}
|
||||
|
@ -990,6 +1009,7 @@ impl Shaders {
|
|||
self.brush_solid.deinit(device);
|
||||
self.brush_blend.deinit(device);
|
||||
self.brush_mix_blend.deinit(device);
|
||||
self.brush_conic_gradient.deinit(device);
|
||||
self.brush_radial_gradient.deinit(device);
|
||||
self.brush_linear_gradient.deinit(device);
|
||||
self.brush_opacity.deinit(device);
|
||||
|
|
|
@ -1175,6 +1175,7 @@ macro_rules! enumerate_interners {
|
|||
line_decoration: LineDecoration,
|
||||
linear_grad: LinearGradient,
|
||||
radial_grad: RadialGradient,
|
||||
conic_grad: ConicGradient,
|
||||
picture: Picture,
|
||||
text_run: TextRun,
|
||||
filter_data: FilterDataIntern,
|
||||
|
|
|
@ -136,6 +136,7 @@ pub enum DisplayItem {
|
|||
PushShadow(PushShadowDisplayItem),
|
||||
Gradient(GradientDisplayItem),
|
||||
RadialGradient(RadialGradientDisplayItem),
|
||||
ConicGradient(ConicGradientDisplayItem),
|
||||
Image(ImageDisplayItem),
|
||||
RepeatingImage(RepeatingImageDisplayItem),
|
||||
YuvImage(YuvImageDisplayItem),
|
||||
|
@ -183,6 +184,7 @@ pub enum DebugDisplayItem {
|
|||
PushShadow(PushShadowDisplayItem),
|
||||
Gradient(GradientDisplayItem),
|
||||
RadialGradient(RadialGradientDisplayItem),
|
||||
ConicGradient(ConicGradientDisplayItem),
|
||||
Image(ImageDisplayItem),
|
||||
RepeatingImage(RepeatingImageDisplayItem),
|
||||
YuvImage(YuvImageDisplayItem),
|
||||
|
@ -444,6 +446,7 @@ pub enum NinePatchBorderSource {
|
|||
Image(ImageKey),
|
||||
Gradient(Gradient),
|
||||
RadialGradient(RadialGradient),
|
||||
ConicGradient(ConicGradient),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
|
@ -633,6 +636,15 @@ pub struct RadialGradient {
|
|||
pub extend_mode: ExtendMode,
|
||||
} // IMPLICIT stops: Vec<GradientStop>
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct ConicGradient {
|
||||
pub center: LayoutPoint,
|
||||
pub angle: f32,
|
||||
pub start_offset: f32,
|
||||
pub end_offset: f32,
|
||||
pub extend_mode: ExtendMode,
|
||||
} // IMPLICIT stops: Vec<GradientStop>
|
||||
|
||||
/// Just an abstraction for bundling up a bunch of clips into a "super clip".
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct ClipChainItem {
|
||||
|
@ -652,6 +664,18 @@ pub struct RadialGradientDisplayItem {
|
|||
pub tile_spacing: LayoutSize,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct ConicGradientDisplayItem {
|
||||
pub common: CommonItemProperties,
|
||||
/// The area to tile the gradient over (first tile starts at origin of this rect)
|
||||
// FIXME: this should ideally just be `tile_origin` here, with the clip_rect
|
||||
// defining the bounds of the item. Needs non-trivial backend changes.
|
||||
pub bounds: LayoutRect,
|
||||
pub gradient: ConicGradient,
|
||||
pub tile_size: LayoutSize,
|
||||
pub tile_spacing: LayoutSize,
|
||||
}
|
||||
|
||||
/// Renders a filtered region of its backdrop
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub struct BackdropFilterDisplayItem {
|
||||
|
@ -1462,6 +1486,7 @@ impl DisplayItem {
|
|||
DisplayItem::HitTest(..) => "hit_test",
|
||||
DisplayItem::Clip(..) => "clip",
|
||||
DisplayItem::ClipChain(..) => "clip_chain",
|
||||
DisplayItem::ConicGradient(..) => "conic_gradient",
|
||||
DisplayItem::Gradient(..) => "gradient",
|
||||
DisplayItem::Iframe(..) => "iframe",
|
||||
DisplayItem::Image(..) => "image",
|
||||
|
|
|
@ -684,6 +684,7 @@ impl Serialize for BuiltDisplayList {
|
|||
Real::BoxShadow(v) => Debug::BoxShadow(v),
|
||||
Real::Gradient(v) => Debug::Gradient(v),
|
||||
Real::RadialGradient(v) => Debug::RadialGradient(v),
|
||||
Real::ConicGradient(v) => Debug::ConicGradient(v),
|
||||
Real::Iframe(v) => Debug::Iframe(v),
|
||||
Real::PushReferenceFrame(v) => Debug::PushReferenceFrame(v),
|
||||
Real::PushStackingContext(v) => Debug::PushStackingContext(v),
|
||||
|
@ -790,6 +791,7 @@ impl<'de> Deserialize<'de> for BuiltDisplayList {
|
|||
Debug::BoxShadow(v) => Real::BoxShadow(v),
|
||||
Debug::Gradient(v) => Real::Gradient(v),
|
||||
Debug::RadialGradient(v) => Real::RadialGradient(v),
|
||||
Debug::ConicGradient(v) => Real::ConicGradient(v),
|
||||
Debug::PushStackingContext(v) => Real::PushStackingContext(v),
|
||||
Debug::PushShadow(v) => Real::PushShadow(v),
|
||||
Debug::BackdropFilter(v) => Real::BackdropFilter(v),
|
||||
|
@ -1205,6 +1207,21 @@ impl DisplayListBuilder {
|
|||
gradient
|
||||
}
|
||||
|
||||
/// NOTE: gradients must be pushed in the order they're created
|
||||
/// because create_gradient stores the stops in anticipation.
|
||||
pub fn create_conic_gradient(
|
||||
&mut self,
|
||||
center: LayoutPoint,
|
||||
angle: f32,
|
||||
stops: Vec<di::GradientStop>,
|
||||
extend_mode: di::ExtendMode,
|
||||
) -> di::ConicGradient {
|
||||
let mut builder = GradientBuilder::with_stops(stops);
|
||||
let gradient = builder.conic_gradient(center, angle, extend_mode);
|
||||
self.push_stops(builder.stops());
|
||||
gradient
|
||||
}
|
||||
|
||||
pub fn push_border(
|
||||
&mut self,
|
||||
common: &di::CommonItemProperties,
|
||||
|
@ -1302,6 +1319,28 @@ impl DisplayListBuilder {
|
|||
self.push_item(&item);
|
||||
}
|
||||
|
||||
/// Pushes a conic gradient to be displayed.
|
||||
///
|
||||
/// See [`push_gradient`](#method.push_gradient) for explanation.
|
||||
pub fn push_conic_gradient(
|
||||
&mut self,
|
||||
common: &di::CommonItemProperties,
|
||||
bounds: LayoutRect,
|
||||
gradient: di::ConicGradient,
|
||||
tile_size: LayoutSize,
|
||||
tile_spacing: LayoutSize,
|
||||
) {
|
||||
let item = di::DisplayItem::ConicGradient(di::ConicGradientDisplayItem {
|
||||
common: *common,
|
||||
bounds,
|
||||
gradient,
|
||||
tile_size,
|
||||
tile_spacing,
|
||||
});
|
||||
|
||||
self.push_item(&item);
|
||||
}
|
||||
|
||||
pub fn push_reference_frame(
|
||||
&mut self,
|
||||
origin: LayoutPoint,
|
||||
|
|
|
@ -99,6 +99,27 @@ impl GradientBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
/// Produce a conic gradient, normalize the stops.
|
||||
pub fn conic_gradient(
|
||||
&mut self,
|
||||
center: LayoutPoint,
|
||||
angle: f32,
|
||||
extend_mode: di::ExtendMode,
|
||||
) -> di::ConicGradient {
|
||||
// XXX(ntim): Possibly handle negative angles ?
|
||||
|
||||
let (start_offset, end_offset) =
|
||||
self.normalize(extend_mode);
|
||||
|
||||
di::ConicGradient {
|
||||
center,
|
||||
angle,
|
||||
start_offset,
|
||||
end_offset,
|
||||
extend_mode,
|
||||
}
|
||||
}
|
||||
|
||||
/// Gradients can be defined with stops outside the range of [0, 1]
|
||||
/// when this happens the gradient needs to be normalized by adjusting
|
||||
/// the gradient stops and gradient line into an equivalent gradient
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
---
|
||||
root:
|
||||
items:
|
||||
- type: clip
|
||||
bounds: [50, 50, 300, 300]
|
||||
complex:
|
||||
- rect: [50, 50, 300, 300]
|
||||
radius: 300
|
||||
items:
|
||||
- type: conic-gradient
|
||||
bounds: 50 50 300 300
|
||||
center: 150 150
|
||||
angle: 0.0
|
||||
stops: [0.0, red, 0.16666, yellow, 0.33333, green, 0.5, [0,255,255,1], 0.66666, blue, 0.83333, [255,0,255,1], 1.0, red]
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
root:
|
||||
items:
|
||||
- type: conic-gradient
|
||||
bounds: 50 50 300 300
|
||||
center: 150 150
|
||||
angle: 0.0
|
||||
stops: [0.0, red, 1.0, yellow]
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
root:
|
||||
items:
|
||||
- type: conic-gradient
|
||||
bounds: 50 50 300 300
|
||||
center: 150 150
|
||||
angle: 0.7853981633974483
|
||||
stops: [0.0, red, 1.0, yellow]
|
|
@ -925,6 +925,33 @@ impl YamlFrameReader {
|
|||
dl.create_radial_gradient(center, radius, stops, extend_mode)
|
||||
}
|
||||
|
||||
fn to_conic_gradient(&mut self, dl: &mut DisplayListBuilder, item: &Yaml) -> ConicGradient {
|
||||
let center = item["center"].as_point().expect("conic gradient must have center");
|
||||
let angle = item["angle"].as_force_f32().expect("conic gradient must have an angle");
|
||||
let stops = item["stops"]
|
||||
.as_vec()
|
||||
.expect("conic gradient must have stops")
|
||||
.chunks(2)
|
||||
.map(|chunk| {
|
||||
GradientStop {
|
||||
offset: chunk[0]
|
||||
.as_force_f32()
|
||||
.expect("gradient stop offset is not f32"),
|
||||
color: chunk[1]
|
||||
.as_colorf()
|
||||
.expect("gradient stop color is not color"),
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let extend_mode = if item["repeat"].as_bool().unwrap_or(false) {
|
||||
ExtendMode::Repeat
|
||||
} else {
|
||||
ExtendMode::Clamp
|
||||
};
|
||||
|
||||
dl.create_conic_gradient(center, angle, stops, extend_mode)
|
||||
}
|
||||
|
||||
fn handle_rect(
|
||||
&mut self,
|
||||
dl: &mut DisplayListBuilder,
|
||||
|
@ -1090,6 +1117,33 @@ impl YamlFrameReader {
|
|||
);
|
||||
}
|
||||
|
||||
fn handle_conic_gradient(
|
||||
&mut self,
|
||||
dl: &mut DisplayListBuilder,
|
||||
item: &Yaml,
|
||||
info: &mut CommonItemProperties,
|
||||
) {
|
||||
let bounds_key = if item["type"].is_badvalue() {
|
||||
"conic-gradient"
|
||||
} else {
|
||||
"bounds"
|
||||
};
|
||||
let bounds = item[bounds_key]
|
||||
.as_rect()
|
||||
.expect("conic gradient must have bounds");
|
||||
let gradient = self.to_conic_gradient(dl, item);
|
||||
let tile_size = item["tile-size"].as_size().unwrap_or(bounds.size);
|
||||
let tile_spacing = item["tile-spacing"].as_size().unwrap_or(LayoutSize::zero());
|
||||
|
||||
dl.push_conic_gradient(
|
||||
&info,
|
||||
bounds,
|
||||
gradient,
|
||||
tile_size,
|
||||
tile_spacing,
|
||||
);
|
||||
}
|
||||
|
||||
fn handle_border(
|
||||
&mut self,
|
||||
dl: &mut DisplayListBuilder,
|
||||
|
@ -1168,7 +1222,7 @@ impl YamlFrameReader {
|
|||
do_aa,
|
||||
}))
|
||||
}
|
||||
"image" | "gradient" | "radial-gradient" => {
|
||||
"image" | "gradient" | "radial-gradient" | "conic-gradient" => {
|
||||
let image_width = item["image-width"]
|
||||
.as_i64()
|
||||
.unwrap_or(bounds.size.width as i64);
|
||||
|
@ -1221,7 +1275,10 @@ impl YamlFrameReader {
|
|||
"radial-gradient" => {
|
||||
let gradient = self.to_radial_gradient(dl, item);
|
||||
NinePatchBorderSource::RadialGradient(gradient)
|
||||
|
||||
}
|
||||
"conic-gradient" => {
|
||||
let gradient = self.to_conic_gradient(dl, item);
|
||||
NinePatchBorderSource::ConicGradient(gradient)
|
||||
}
|
||||
_ => unreachable!("Unexpected border type"),
|
||||
};
|
||||
|
@ -1593,6 +1650,7 @@ impl YamlFrameReader {
|
|||
"border",
|
||||
"gradient",
|
||||
"radial-gradient",
|
||||
"conic-gradient"
|
||||
];
|
||||
|
||||
for shorthand in shorthands.iter() {
|
||||
|
@ -1699,6 +1757,7 @@ impl YamlFrameReader {
|
|||
"border" => self.handle_border(dl, wrench, item, &mut info),
|
||||
"gradient" => self.handle_gradient(dl, item, &mut info),
|
||||
"radial-gradient" => self.handle_radial_gradient(dl, item, &mut info),
|
||||
"conic-gradient" => self.handle_conic_gradient(dl, item, &mut info),
|
||||
"box-shadow" => self.handle_box_shadow(dl, item, &mut info),
|
||||
"iframe" => self.handle_iframe(dl, item, &mut info),
|
||||
"stacking-context" => {
|
||||
|
|
|
@ -526,6 +526,29 @@ fn radial_gradient_to_yaml(
|
|||
bool_node(table, "repeat", gradient.extend_mode == ExtendMode::Repeat);
|
||||
}
|
||||
|
||||
fn conic_gradient_to_yaml(
|
||||
table: &mut Table,
|
||||
gradient: &webrender::api::ConicGradient,
|
||||
stops_range: ItemRange<GradientStop>,
|
||||
) {
|
||||
point_node(table, "center", &gradient.center);
|
||||
f32_node(table, "angle", gradient.angle);
|
||||
|
||||
let first_offset = gradient.start_offset;
|
||||
let last_offset = gradient.end_offset;
|
||||
let stops_delta = last_offset - first_offset;
|
||||
assert!(first_offset <= last_offset);
|
||||
|
||||
let mut denormalized_stops = vec![];
|
||||
for stop in stops_range {
|
||||
let denormalized_stop = (stop.offset * stops_delta) + first_offset;
|
||||
denormalized_stops.push(Yaml::Real(denormalized_stop.to_string()));
|
||||
denormalized_stops.push(Yaml::String(color_to_string(stop.color)));
|
||||
}
|
||||
yaml_node(table, "stops", Yaml::Array(denormalized_stops));
|
||||
bool_node(table, "repeat", gradient.extend_mode == ExtendMode::Repeat);
|
||||
}
|
||||
|
||||
enum CachedFont {
|
||||
Native(NativeFontHandle, Option<PathBuf>),
|
||||
Raw(Option<Vec<u8>>, u32, Option<PathBuf>),
|
||||
|
@ -1191,6 +1214,14 @@ impl YamlFrameWriter {
|
|||
base.gradient_stops(),
|
||||
);
|
||||
}
|
||||
NinePatchBorderSource::ConicGradient(gradient) => {
|
||||
str_node(&mut v, "border-type", "conic-gradient");
|
||||
conic_gradient_to_yaml(
|
||||
&mut v,
|
||||
&gradient,
|
||||
base.gradient_stops(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
i32_node(&mut v, "image-width", details.width);
|
||||
|
@ -1273,6 +1304,18 @@ impl YamlFrameWriter {
|
|||
base.gradient_stops(),
|
||||
);
|
||||
}
|
||||
DisplayItem::ConicGradient(item) => {
|
||||
str_node(&mut v, "type", "conic-gradient");
|
||||
rect_node(&mut v, "bounds", &item.bounds);
|
||||
common_node(&mut v, clip_id_mapper, &item.common);
|
||||
size_node(&mut v, "tile-size", &item.tile_size);
|
||||
size_node(&mut v, "tile-spacing", &item.tile_spacing);
|
||||
conic_gradient_to_yaml(
|
||||
&mut v,
|
||||
&item.gradient,
|
||||
base.gradient_stops(),
|
||||
);
|
||||
}
|
||||
DisplayItem::Iframe(item) => {
|
||||
str_node(&mut v, "type", "iframe");
|
||||
rect_node(&mut v, "bounds", &item.bounds);
|
||||
|
|
Загрузка…
Ссылка в новой задаче