use super::scene_graph_test_support::{
b, black, black_pen, p, replay, rrect, TestBitmapImpl, TestCustomOperation, TestGeometryImpl,
};
use crate::media::{BoxShadow, BoxShadows, EdgeMode, RenderOptions, TextOptions, TextRenderingMode};
use crate::platform::{IBitmapImpl, IDrawingContextImpl, IGlyphRunImpl};
use crate::rendering::composition::drawing::{RenderDataResource, RenderDataStream};
use crate::rendering::testing::{DrawingLog, MockDrawingContextImpl, MockGlyphRunImpl};
use crate::{Matrix, Point, Rect};
#[test]
fn replay_forwards_line() {
let pen = black_pen(1.0);
let mut stream = RenderDataStream::new();
stream.draw_line(p(&pen), p(&pen), Point::new(1.0, 2.0), Point::new(3.0, 4.0));
let calls = replay(&stream);
assert_eq!(calls, ["DrawLine Black@1 1, 2 3, 4"]);
}
#[test]
fn replay_forwards_rectangle_with_box_shadows() {
let brush = black();
let pen = black_pen(1.0);
let rect = rrect(0.0, 0.0, 10.0, 20.0);
let shadows = BoxShadows::with_rest(
BoxShadow { blur: 1.0, ..Default::default() },
&[BoxShadow { blur: 2.0, ..Default::default() }],
);
let mut stream = RenderDataStream::new();
stream.draw_rectangle(b(&brush), p(&pen), p(&pen), rect, &shadows);
let calls = replay(&stream);
assert_eq!(calls, ["DrawRectangle Black Black@1 0, 0, 10, 20 shadows=2"]);
}
#[test]
fn replay_forwards_custom_operation() {
let operation = TestCustomOperation::new();
let mut stream = RenderDataStream::new();
stream.draw_custom(Some(operation.clone()));
replay(&stream);
assert_eq!(operation.render_count.get(), 1);
}
#[test]
fn replay_pop_dispatches_to_matching_pop_in_lifo_order() {
let mut stream = RenderDataStream::new();
stream.push_clip(rrect(0.0, 0.0, 10.0, 10.0));
stream.push_opacity(0.5);
stream.pop();
stream.pop();
let calls = recorded_calls(&stream);
assert_eq!(calls, ["PushClip", "PushOpacity", "PopOpacity", "PopClip"]);
}
#[test]
fn replay_applies_and_restores_transform() {
let mut context = MockDrawingContextImpl::new(DrawingLog::new());
context.set_transform(Matrix::IDENTITY);
let matrix = Matrix::create_translation(5.0, 7.0);
let mut stream = RenderDataStream::new();
stream.push_transform(matrix);
stream.pop();
stream.replay(&mut context);
assert_eq!(Matrix::IDENTITY, context.transform());
}
#[test]
fn replay_skips_opacity_one_push() {
let mut stream = RenderDataStream::new();
stream.push_opacity(1.0);
stream.pop();
let calls = recorded_calls(&stream);
assert!(calls.is_empty());
}
#[test]
fn replay_skips_null_geometry_clip() {
let mut stream = RenderDataStream::new();
stream.push_geometry_clip(None);
stream.pop();
let calls = recorded_calls(&stream);
assert!(calls.is_empty());
}
#[test]
fn replay_walks_nested_pushes_in_order() {
let geometry = TestGeometryImpl::new();
let mut stream = RenderDataStream::new();
stream.push_clip(rrect(0.0, 0.0, 10.0, 10.0));
stream.push_geometry_clip(Some(RenderDataResource::GeometryImpl(geometry)));
stream.pop();
stream.pop();
let calls = recorded_calls(&stream);
assert_eq!(calls, ["PushClip", "PushGeometryClip", "PopGeometryClip", "PopClip"]);
}
#[test]
fn replay_forwards_render_options() {
let options = RenderOptions { edge_mode: EdgeMode::Aliased, ..Default::default() };
let mut stream = RenderDataStream::new();
stream.push_render_options(options);
stream.pop();
let log = DrawingLog::new();
let mut context = MockDrawingContextImpl::new(log.clone());
context.log_transforms = false;
context.log_render_options = true;
stream.replay(&mut context);
assert_eq!(
log.entries(),
["PushRenderOptions Unspecified Unspecified Aliased Unspecified None", "PopRenderOptions"]
);
}
#[test]
fn replay_forwards_text_options() {
let options = TextOptions { text_rendering_mode: TextRenderingMode::Antialias, ..Default::default() };
let mut stream = RenderDataStream::new();
stream.push_text_options(options);
stream.pop();
let calls = replay(&stream);
assert_eq!(calls, ["PushTextOptions Antialias Unspecified Unspecified", "PopTextOptions"]);
}
#[test]
fn dispose_resources_disposes_owned_resources() {
let bitmap = crate::utilities::RefCountable::create(
std::sync::Arc::new(TestBitmapImpl) as std::sync::Arc<crate::platform::SharedBitmapImpl>,
|| {},
);
let glyph_run: std::sync::Arc<dyn IGlyphRunImpl> = MockGlyphRunImpl::new(Rect::default());
let operation = TestCustomOperation::new();
{
let mut stream = RenderDataStream::new();
stream.draw_bitmap(Some(bitmap.clone_ref()), 1.0, Rect::new(0.0, 0.0, 1.0, 1.0), Rect::new(0.0, 0.0, 1.0, 1.0));
stream.draw_glyph_run(None, Some(glyph_run.clone()));
stream.draw_custom(Some(operation.clone()));
assert_eq!(2, bitmap.ref_count());
assert_eq!(2, std::sync::Arc::strong_count(&glyph_run));
stream.dispose_resources();
stream.dispose();
}
assert_eq!(1, bitmap.ref_count());
assert_eq!(1, std::sync::Arc::strong_count(&glyph_run));
assert_eq!(1, operation.dispose_count.get());
}
#[test]
fn replay_handles_deeply_nested_scopes() {
let mut stream = RenderDataStream::new();
for _ in 0..100 {
stream.push_opacity(0.5);
}
stream.draw_rectangle(b(&black()), None, None, rrect(0.0, 0.0, 10.0, 10.0), &BoxShadows::default());
for _ in 0..100 {
stream.pop();
}
let calls = replay(&stream);
assert_eq!(1, calls.iter().filter(|call| call.starts_with("DrawRectangle Black none ")).count());
}
fn recorded_calls(stream: &RenderDataStream) -> Vec<String> {
const RECORDED: [&str; 6] =
["PushClip", "PopClip", "PushGeometryClip", "PopGeometryClip", "PushOpacity", "PopOpacity"];
let log = DrawingLog::new();
let mut context = MockDrawingContextImpl::new(log.clone());
context.log_transforms = false;
stream.replay(&mut context);
log.entries()
.iter()
.map(|entry| entry.split(' ').next().unwrap_or_default())
.map(|name| if name == "PushRoundedClip" { "PushClip" } else { name })
.filter(|name| RECORDED.contains(name))
.map(str::to_owned)
.collect()
}