2401 {
2402 std::vector<int> indices;
2403 auto label = "from " + file + ":" + std::to_string(line);
2404 rtree->search(query, &indices);
2405 EXPECT_EQ(indices, expected_indices) << label;
2406 EXPECT_EQ(indices.size(), expected_indices.size()) << label;
2407 std::list<DlRect> rects = rtree->searchAndConsolidateRects(query, false);
2408
2409 auto iterator = rects.cbegin();
2410 for (
int i : expected_indices) {
2411 ASSERT_TRUE(iterator != rects.cend()) << label;
2412 EXPECT_EQ(*iterator++, expected_rects[
i]) << label;
2413 }
2414}
2415
2416TEST_F(DisplayListTest, RTreeOfSimpleScene) {
2417 DisplayListBuilder builder(true);
2418 std::vector<DlRect> rects = {
2419 DlRect::MakeLTRB(10, 10, 20, 20),
2420 DlRect::MakeLTRB(50, 50, 60, 60),
2421 };
2422 builder.DrawRect(rects[0],
DlPaint());
2423 builder.DrawRect(rects[1],
DlPaint());
2424 auto display_list = builder.Build();
2425 auto rtree = display_list->rtree();
2426
2427
2428 TEST_RTREE(rtree, DlRect::MakeLTRB(5, 5, 10, 10), rects, {});
2429 TEST_RTREE(rtree, DlRect::MakeLTRB(20, 20, 25, 25), rects, {});
2430 TEST_RTREE(rtree, DlRect::MakeLTRB(45, 45, 50, 50), rects, {});
2431 TEST_RTREE(rtree, DlRect::MakeLTRB(60, 60, 65, 65), rects, {});
2432
2433
2434 TEST_RTREE(rtree, DlRect::MakeLTRB(5, 5, 11, 11), rects, {0});
2435 TEST_RTREE(rtree, DlRect::MakeLTRB(19, 19, 25, 25), rects, {0});
2436 TEST_RTREE(rtree, DlRect::MakeLTRB(45, 45, 51, 51), rects, {1});
2437 TEST_RTREE(rtree, DlRect::MakeLTRB(59, 59, 65, 65), rects, {1});
2438
2439
2440 TEST_RTREE(rtree, DlRect::MakeLTRB(19, 19, 51, 51), rects,
2441 std::vector<int>({0, 1}));
2442}
2443
2444TEST_F(DisplayListTest, RTreeOfSaveRestoreScene) {
2445 DisplayListBuilder builder(true);
2446 builder.DrawRect(DlRect::MakeLTRB(10, 10, 20, 20),
DlPaint());
2447 builder.Save();
2448 builder.DrawRect(DlRect::MakeLTRB(50, 50, 60, 60),
DlPaint());
2449 builder.Restore();
2450 auto display_list = builder.Build();
2451 auto rtree = display_list->rtree();
2452 std::vector<DlRect> rects = {
2453 DlRect::MakeLTRB(10, 10, 20, 20),
2454 DlRect::MakeLTRB(50, 50, 60, 60),
2455 };
2456
2457
2458 TEST_RTREE(rtree, DlRect::MakeLTRB(5, 5, 10, 10), rects, {});
2459 TEST_RTREE(rtree, DlRect::MakeLTRB(20, 20, 25, 25), rects, {});
2460 TEST_RTREE(rtree, DlRect::MakeLTRB(45, 45, 50, 50), rects, {});
2461 TEST_RTREE(rtree, DlRect::MakeLTRB(60, 60, 65, 65), rects, {});
2462
2463
2464 TEST_RTREE(rtree, DlRect::MakeLTRB(5, 5, 11, 11), rects, {0});
2465 TEST_RTREE(rtree, DlRect::MakeLTRB(19, 19, 25, 25), rects, {0});
2466 TEST_RTREE(rtree, DlRect::MakeLTRB(45, 45, 51, 51), rects, {1});
2467 TEST_RTREE(rtree, DlRect::MakeLTRB(59, 59, 65, 65), rects, {1});
2468
2469
2470 TEST_RTREE(rtree, DlRect::MakeLTRB(19, 19, 51, 51), rects,
2471 std::vector<int>({0, 1}));
2472}
2473
2474TEST_F(DisplayListTest, RTreeOfSaveLayerFilterScene) {
2475 DisplayListBuilder builder(true);
2476
2477 auto filter = DlBlurImageFilter(1.0, 1.0, DlTileMode::kClamp);
2480 builder.DrawRect(DlRect::MakeLTRB(10, 10, 20, 20), default_paint);
2481 builder.SaveLayer(std::nullopt, &filter_paint);
2482
2483
2484 builder.DrawRect(DlRect::MakeLTRB(53, 53, 57, 57), default_paint);
2485 builder.Restore();
2486 auto display_list = builder.Build();
2487 auto rtree = display_list->rtree();
2488 std::vector<DlRect> rects = {
2489 DlRect::MakeLTRB(10, 10, 20, 20),
2490 DlRect::MakeLTRB(50, 50, 60, 60),
2491 };
2492
2493
2494 TEST_RTREE(rtree, DlRect::MakeLTRB(5, 5, 10, 10), rects, {});
2495 TEST_RTREE(rtree, DlRect::MakeLTRB(20, 20, 25, 25), rects, {});
2496 TEST_RTREE(rtree, DlRect::MakeLTRB(45, 45, 50, 50), rects, {});
2497 TEST_RTREE(rtree, DlRect::MakeLTRB(60, 60, 65, 65), rects, {});
2498
2499
2500 TEST_RTREE(rtree, DlRect::MakeLTRB(5, 5, 11, 11), rects, {0});
2501 TEST_RTREE(rtree, DlRect::MakeLTRB(19, 19, 25, 25), rects, {0});
2502 TEST_RTREE(rtree, DlRect::MakeLTRB(45, 45, 51, 51), rects, {1});
2503 TEST_RTREE(rtree, DlRect::MakeLTRB(59, 59, 65, 65), rects, {1});
2504
2505
2506 auto expected_indices = std::vector<int>{0, 1};
2507 TEST_RTREE(rtree, DlRect::MakeLTRB(19, 19, 51, 51), rects, expected_indices);
2508}
2509
2510TEST_F(DisplayListTest, NestedDisplayListRTreesAreSparse) {
2511 DisplayListBuilder nested_dl_builder(true);
2512 nested_dl_builder.DrawRect(DlRect::MakeLTRB(10, 10, 20, 20),
DlPaint());
2513 nested_dl_builder.DrawRect(DlRect::MakeLTRB(50, 50, 60, 60),
DlPaint());
2514 auto nested_display_list = nested_dl_builder.Build();
2515
2516 DisplayListBuilder builder(true);
2517 builder.DrawDisplayList(nested_display_list);
2518 auto display_list = builder.Build();
2519
2520 auto rtree = display_list->rtree();
2521 std::vector<DlRect> rects = {
2522 DlRect::MakeLTRB(10, 10, 20, 20),
2523 DlRect::MakeLTRB(50, 50, 60, 60),
2524 };
2525
2526
2527 TEST_RTREE(rtree, DlRect::MakeLTRB(19, 19, 51, 51), rects,
2528 std::vector<int>({0, 1}));
2529}
2530
2531TEST_F(DisplayListTest, RemoveUnnecessarySaveRestorePairs) {
2532 {
2533 DisplayListBuilder builder;
2534 builder.DrawRect(DlRect::MakeLTRB(10, 10, 20, 20),
DlPaint());
2535 builder.Save();
2536 builder.DrawRect(DlRect::MakeLTRB(50, 50, 60, 60),
DlPaint());
2537 builder.Restore();
2538
2539 DisplayListBuilder builder2;
2540 builder2.DrawRect(DlRect::MakeLTRB(10, 10, 20, 20),
DlPaint());
2541 builder2.DrawRect(DlRect::MakeLTRB(50, 50, 60, 60),
DlPaint());
2543 }
2544
2545 {
2546 DisplayListBuilder builder;
2547 builder.DrawRect(DlRect::MakeLTRB(10, 10, 20, 20),
DlPaint());
2548 builder.Save();
2549 {
2550 builder.Translate(1.0, 1.0);
2551 builder.Save();
2552 {
2553 builder.DrawRect(DlRect::MakeLTRB(50, 50, 60, 60),
DlPaint());
2554 }
2555 builder.Restore();
2556 }
2557 builder.Restore();
2558
2559 DisplayListBuilder builder2;
2560 builder2.DrawRect(DlRect::MakeLTRB(10, 10, 20, 20),
DlPaint());
2561 builder2.Save();
2562 {
2563 builder2.Translate(1.0, 1.0);
2564 {
2565 builder2.DrawRect(DlRect::MakeLTRB(50, 50, 60, 60),
DlPaint());
2566 }
2567 }
2568 builder2.Restore();
2570 }
2571}
2572
2573TEST_F(DisplayListTest, CollapseMultipleNestedSaveRestore) {
2574 DisplayListBuilder builder1;
2575 builder1.Save();
2576 {
2577 builder1.Save();
2578 {
2579 builder1.Save();
2580 {
2581 builder1.Translate(10, 10);
2582 builder1.Scale(2, 2);
2583 builder1.ClipRect(DlRect::MakeLTRB(10, 10, 20, 20),
2584 DlClipOp::kIntersect, false);
2585 builder1.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
2586 }
2587 builder1.Restore();
2588 }
2589 builder1.Restore();
2590 }
2591 builder1.Restore();
2592 auto display_list1 = builder1.Build();
2593
2594 DisplayListBuilder builder2;
2595 builder2.Save();
2596 {
2597 builder2.Translate(10, 10);
2598 builder2.Scale(2, 2);
2599 builder2.ClipRect(DlRect::MakeLTRB(10, 10, 20, 20), DlClipOp::kIntersect,
2600 false);
2601 builder2.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
2602 }
2603 builder2.Restore();
2604 auto display_list2 = builder2.Build();
2605
2607}
2608
2609TEST_F(DisplayListTest, CollapseNestedSaveAndSaveLayerRestore) {
2610 DisplayListBuilder builder1;
2611 builder1.Save();
2612 {
2613 builder1.SaveLayer(std::nullopt, nullptr);
2614 {
2615 builder1.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
2616 builder1.Scale(2, 2);
2617 }
2618 builder1.Restore();
2619 }
2620 builder1.Restore();
2621 auto display_list1 = builder1.Build();
2622
2623 DisplayListBuilder builder2;
2624 builder2.SaveLayer(std::nullopt, nullptr);
2625 {
2626 builder2.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
2627 builder2.Scale(2, 2);
2628 }
2629 builder2.Restore();
2630 auto display_list2 = builder2.Build();
2631
2633}
2634
2635TEST_F(DisplayListTest, RemoveUnnecessarySaveRestorePairsInSetPaint) {
2636 DlRect build_bounds = DlRect::MakeLTRB(-100, -100, 200, 200);
2637 DlRect rect = DlRect::MakeLTRB(30, 30, 70, 70);
2638
2639 const float alpha_matrix[] = {
2640 0, 0, 0, 0, 0,
2641 0, 1, 0, 0, 0,
2642 0, 0, 1, 0, 0,
2643 0, 0, 0, 0, 1,
2644 };
2645
2646 auto alpha_color_filter = DlColorFilter::MakeMatrix(alpha_matrix);
2647
2648
2649
2650 DlColorFilterImageFilter color_filter_image_filter(alpha_color_filter);
2651 {
2652 DisplayListBuilder builder(build_bounds);
2653 builder.Save();
2656 builder.DrawRect(rect, paint);
2657 builder.Restore();
2658 sk_sp<DisplayList> display_list1 = builder.Build();
2659
2660 DisplayListBuilder builder2(build_bounds);
2663 builder2.DrawRect(rect, paint2);
2664 sk_sp<DisplayList> display_list2 = builder2.Build();
2666 }
2667
2668 {
2669 DisplayListBuilder builder(build_bounds);
2670 builder.Save();
2671 builder.SaveLayer(build_bounds);
2674 builder.DrawRect(rect, paint);
2675 builder.Restore();
2676 builder.Restore();
2677 sk_sp<DisplayList> display_list1 = builder.Build();
2678
2679 DisplayListBuilder builder2(build_bounds);
2680 builder2.SaveLayer(build_bounds);
2683 builder2.DrawRect(rect, paint2);
2684 builder2.Restore();
2685 sk_sp<DisplayList> display_list2 = builder2.Build();
2687 }
2688}
2689
2690TEST_F(DisplayListTest, TransformTriggersDeferredSave) {
2691 DisplayListBuilder builder1;
2692 builder1.Save();
2693 {
2694 builder1.Save();
2695 {
2696 builder1.TransformFullPerspective(1, 0, 0, 10,
2697 0, 1, 0, 100,
2698 0, 0, 1, 0,
2699 0, 0, 0, 1);
2700 builder1.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
2701 }
2702 builder1.Restore();
2703 builder1.TransformFullPerspective(1, 0, 0, 10,
2704 0, 1, 0, 100,
2705 0, 0, 1, 0,
2706 0, 0, 0, 1);
2707 builder1.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
2708 }
2709 builder1.Restore();
2710 auto display_list1 = builder1.Build();
2711
2712 DisplayListBuilder builder2;
2713 builder2.Save();
2714 {
2715 builder2.TransformFullPerspective(1, 0, 0, 10,
2716 0, 1, 0, 100,
2717 0, 0, 1, 0,
2718 0, 0, 0, 1);
2719 builder2.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
2720 }
2721 builder2.Restore();
2722 builder2.Save();
2723 {
2724 builder2.TransformFullPerspective(1, 0, 0, 10,
2725 0, 1, 0, 100,
2726 0, 0, 1, 0,
2727 0, 0, 0, 1);
2728 builder2.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
2729 }
2730 builder2.Restore();
2731 auto display_list2 = builder2.Build();
2732
2734}
2735
2736TEST_F(DisplayListTest, Transform2DTriggersDeferredSave) {
2737 DisplayListBuilder builder1;
2738 builder1.Save();
2739 {
2740 builder1.Save();
2741 {
2742 builder1.Transform2DAffine(0, 1, 12, 1, 0, 33);
2743 builder1.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
2744 }
2745 builder1.Restore();
2746 }
2747 builder1.Restore();
2748 auto display_list1 = builder1.Build();
2749
2750 DisplayListBuilder builder2;
2751 builder2.Save();
2752 {
2753 builder2.Transform2DAffine(0, 1, 12, 1, 0, 33);
2754 builder2.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
2755 }
2756 builder2.Restore();
2757 auto display_list2 = builder2.Build();
2758
2760}
2761
2762TEST_F(DisplayListTest, TransformPerspectiveTriggersDeferredSave) {
2763 DisplayListBuilder builder1;
2764 builder1.Save();
2765 {
2766 builder1.Save();
2767 {
2768 builder1.TransformFullPerspective(0, 1, 0, 12,
2769 1, 0, 0, 33,
2770 3, 2, 5, 29,
2771 0, 0, 0, 12);
2772 builder1.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
2773 }
2774 builder1.Restore();
2775 }
2776 builder1.Restore();
2777 auto display_list1 = builder1.Build();
2778
2779 DisplayListBuilder builder2;
2780 builder2.Save();
2781 {
2782 builder2.TransformFullPerspective(0, 1, 0, 12,
2783 1, 0, 0, 33,
2784 3, 2, 5, 29,
2785 0, 0, 0, 12);
2786 builder2.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
2787 }
2788 builder2.Restore();
2789 auto display_list2 = builder2.Build();
2790
2792}
2793
2794TEST_F(DisplayListTest, ResetTransformTriggersDeferredSave) {
2795 DisplayListBuilder builder1;
2796 builder1.Save();
2797 {
2798 builder1.Save();
2799 {
2800 builder1.TransformReset();
2801 builder1.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
2802 }
2803 builder1.Restore();
2804 }
2805 builder1.Restore();
2806 auto display_list1 = builder1.Build();
2807
2808 DisplayListBuilder builder2;
2809 builder2.Save();
2810 {
2811 builder2.TransformReset();
2812 builder2.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
2813 }
2814 builder2.Restore();
2815 auto display_list2 = builder2.Build();
2816
2818}
2819
2820TEST_F(DisplayListTest, SkewTriggersDeferredSave) {
2821 DisplayListBuilder builder1;
2822 builder1.Save();
2823 {
2824 builder1.Save();
2825 {
2826 builder1.Skew(10, 10);
2827 builder1.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
2828 }
2829 builder1.Restore();
2830 }
2831 builder1.Restore();
2832 auto display_list1 = builder1.Build();
2833
2834 DisplayListBuilder builder2;
2835 builder2.Save();
2836 {
2837 builder2.Skew(10, 10);
2838 builder2.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
2839 }
2840 builder2.Restore();
2841 auto display_list2 = builder2.Build();
2842
2844}
2845
2846TEST_F(DisplayListTest, TranslateTriggersDeferredSave) {
2847 DisplayListBuilder builder1;
2848 builder1.Save();
2849 {
2850 builder1.Save();
2851 {
2852 builder1.Translate(10, 10);
2853 builder1.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
2854 }
2855 builder1.Restore();
2856 }
2857 builder1.Restore();
2858 auto display_list1 = builder1.Build();
2859
2860 DisplayListBuilder builder2;
2861 builder2.Save();
2862 {
2863 builder2.Translate(10, 10);
2864 builder2.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
2865 }
2866 builder2.Restore();
2867 auto display_list2 = builder2.Build();
2868
2870}
2871
2872TEST_F(DisplayListTest, ScaleTriggersDeferredSave) {
2873 DisplayListBuilder builder1;
2874 builder1.Save();
2875 {
2876 builder1.Save();
2877 {
2878 builder1.Scale(0.5, 0.5);
2879 builder1.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
2880 }
2881 builder1.Restore();
2882 }
2883 builder1.Restore();
2884 auto display_list1 = builder1.Build();
2885
2886 DisplayListBuilder builder2;
2887 builder2.Save();
2888 {
2889 builder2.Scale(0.5, 0.5);
2890 builder2.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
2891 }
2892 builder2.Restore();
2893 auto display_list2 = builder2.Build();
2894
2896}
2897
2898TEST_F(DisplayListTest, ClipRectTriggersDeferredSave) {
2899 DisplayListBuilder builder1;
2900 builder1.Save();
2901 {
2902 builder1.Save();
2903 {
2904 builder1.ClipRect(DlRect::MakeLTRB(0, 0, 100, 100), DlClipOp::kIntersect,
2905 true);
2906 builder1.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
2907 }
2908 builder1.Restore();
2909 builder1.TransformFullPerspective(1, 0, 0, 0,
2910 0, 1, 0, 0,
2911 0, 0, 1, 0,
2912 0, 0, 0, 1);
2913 builder1.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
2914 }
2915 builder1.Restore();
2916 auto display_list1 = builder1.Build();
2917
2918 DisplayListBuilder builder2;
2919 builder2.Save();
2920 {
2921 builder2.ClipRect(DlRect::MakeLTRB(0, 0, 100, 100), DlClipOp::kIntersect,
2922 true);
2923 builder2.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
2924 }
2925 builder2.Restore();
2926 builder2.TransformFullPerspective(1, 0, 0, 0,
2927 0, 1, 0, 0,
2928 0, 0, 1, 0,
2929 0, 0, 0, 1);
2930 builder2.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
2931 auto display_list2 = builder2.Build();
2932
2934}
2935
2936TEST_F(DisplayListTest, ClipRRectTriggersDeferredSave) {
2937 DisplayListBuilder builder1;
2938 builder1.Save();
2939 {
2940 builder1.Save();
2941 {
2942 builder1.ClipRoundRect(kTestRRect, DlClipOp::kIntersect, true);
2943
2944 builder1.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
2945 }
2946 builder1.Restore();
2947 builder1.TransformFullPerspective(1, 0, 0, 0,
2948 0, 1, 0, 0,
2949 0, 0, 1, 0,
2950 0, 0, 0, 1);
2951 builder1.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
2952 }
2953 builder1.Restore();
2954 auto display_list1 = builder1.Build();
2955
2956 DisplayListBuilder builder2;
2957 builder2.Save();
2958 builder2.ClipRoundRect(kTestRRect, DlClipOp::kIntersect, true);
2959
2960 builder2.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
2961 builder2.Restore();
2962 builder2.TransformFullPerspective(1, 0, 0, 0,
2963 0, 1, 0, 0,
2964 0, 0, 1, 0,
2965 0, 0, 0, 1);
2966 builder2.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
2967 auto display_list2 = builder2.Build();
2968
2970}
2971
2972TEST_F(DisplayListTest, ClipPathTriggersDeferredSave) {
2973 DisplayListBuilder builder1;
2974 builder1.Save();
2975 {
2976 builder1.Save();
2977 {
2978 builder1.ClipPath(kTestPath1, DlClipOp::kIntersect, true);
2979 builder1.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
2980 }
2981 builder1.Restore();
2982 builder1.TransformFullPerspective(1, 0, 0, 0,
2983 0, 1, 0, 0,
2984 0, 0, 1, 0,
2985 0, 0, 0, 1);
2986 builder1.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
2987 }
2988 builder1.Restore();
2989 auto display_list1 = builder1.Build();
2990
2991 DisplayListBuilder builder2;
2992 builder2.Save();
2993 {
2994 builder2.ClipPath(kTestPath1, DlClipOp::kIntersect, true);
2995 builder2.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
2996 }
2997 builder2.Restore();
2998 builder2.TransformFullPerspective(1, 0, 0, 0,
2999 0, 1, 0, 0,
3000 0, 0, 1, 0,
3001 0, 0, 0, 1);
3002 builder2.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
3003 auto display_list2 = builder2.Build();
3004
3006}
3007
3008TEST_F(DisplayListTest, NOPTranslateDoesNotTriggerDeferredSave) {
3009 DisplayListBuilder builder1;
3010 builder1.Save();
3011 {
3012 builder1.Save();
3013 {
3014 builder1.Translate(0, 0);
3015 builder1.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
3016 }
3017 builder1.Restore();
3018 builder1.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
3019 }
3020 builder1.Restore();
3021 auto display_list1 = builder1.Build();
3022
3023 DisplayListBuilder builder2;
3024 builder2.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
3025 builder2.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
3026 auto display_list2 = builder2.Build();
3027
3029}
3030
3031TEST_F(DisplayListTest, NOPScaleDoesNotTriggerDeferredSave) {
3032 DisplayListBuilder builder1;
3033 builder1.Save();
3034 {
3035 builder1.Save();
3036 {
3037 builder1.Scale(1.0, 1.0);
3038 builder1.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
3039 }
3040 builder1.Restore();
3041 builder1.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
3042 }
3043 builder1.Restore();
3044 auto display_list1 = builder1.Build();
3045
3046 DisplayListBuilder builder2;
3047 builder2.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
3048 builder2.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
3049 auto display_list2 = builder2.Build();
3050
3052}
3053
3054TEST_F(DisplayListTest, NOPRotationDoesNotTriggerDeferredSave) {
3055 DisplayListBuilder builder1;
3056 builder1.Save();
3057 {
3058 builder1.Save();
3059 {
3060 builder1.Rotate(360);
3061 builder1.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
3062 }
3063 builder1.Restore();
3064 builder1.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
3065 }
3066 builder1.Restore();
3067 auto display_list1 = builder1.Build();
3068
3069 DisplayListBuilder builder2;
3070 builder2.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
3071 builder2.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
3072 auto display_list2 = builder2.Build();
3073
3075}
3076
3077TEST_F(DisplayListTest, NOPSkewDoesNotTriggerDeferredSave) {
3078 DisplayListBuilder builder1;
3079 builder1.Save();
3080 {
3081 builder1.Save();
3082 {
3083 builder1.Skew(0, 0);
3084 builder1.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
3085 }
3086 builder1.Restore();
3087 builder1.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
3088 }
3089 builder1.Restore();
3090 auto display_list1 = builder1.Build();
3091
3092 DisplayListBuilder builder2;
3093 builder2.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
3094 builder2.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
3095 auto display_list2 = builder2.Build();
3096
3098}
3099
3100TEST_F(DisplayListTest, NOPTransformDoesNotTriggerDeferredSave) {
3101 DisplayListBuilder builder1;
3102 builder1.Save();
3103 {
3104 builder1.Save();
3105 {
3106 builder1.TransformFullPerspective(1, 0, 0, 0,
3107 0, 1, 0, 0,
3108 0, 0, 1, 0,
3109 0, 0, 0, 1);
3110 builder1.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
3111 }
3112 builder1.Restore();
3113 builder1.TransformFullPerspective(1, 0, 0, 0,
3114 0, 1, 0, 0,
3115 0, 0, 1, 0,
3116 0, 0, 0, 1);
3117 builder1.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
3118 }
3119 builder1.Restore();
3120 auto display_list1 = builder1.Build();
3121
3122 DisplayListBuilder builder2;
3123 builder2.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
3124 builder2.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
3125 auto display_list2 = builder2.Build();
3126
3128}
3129
3130TEST_F(DisplayListTest, NOPTransform2DDoesNotTriggerDeferredSave) {
3131 DisplayListBuilder builder1;
3132 builder1.Save();
3133 {
3134 builder1.Save();
3135 {
3136 builder1.Transform2DAffine(1, 0, 0, 0, 1, 0);
3137 builder1.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
3138 }
3139 builder1.Restore();
3140 builder1.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
3141 }
3142 builder1.Restore();
3143 auto display_list1 = builder1.Build();
3144
3145 DisplayListBuilder builder2;
3146 builder2.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
3147 builder2.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
3148 auto display_list2 = builder2.Build();
3149
3151}
3152
3153TEST_F(DisplayListTest, NOPTransformFullPerspectiveDoesNotTriggerDeferredSave) {
3154 {
3155 DisplayListBuilder builder1;
3156 builder1.Save();
3157 {
3158 builder1.Save();
3159 {
3160 builder1.TransformFullPerspective(1, 0, 0, 0,
3161 0, 1, 0, 0,
3162 0, 0, 1, 0,
3163 0, 0, 0, 1);
3164 builder1.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
3165 }
3166 builder1.Restore();
3167 builder1.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
3168 }
3169 builder1.Restore();
3170 auto display_list1 = builder1.Build();
3171
3172 DisplayListBuilder builder2;
3173 builder2.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
3174 builder2.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
3175 auto display_list2 = builder2.Build();
3176
3178 }
3179
3180 {
3181 DisplayListBuilder builder1;
3182 builder1.Save();
3183 {
3184 builder1.Save();
3185 {
3186 builder1.TransformFullPerspective(1, 0, 0, 0,
3187 0, 1, 0, 0,
3188 0, 0, 1, 0,
3189 0, 0, 0, 1);
3190 builder1.TransformReset();
3191 builder1.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
3192 }
3193 builder1.Restore();
3194 builder1.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
3195 }
3196 builder1.Restore();
3197 auto display_list1 = builder1.Build();
3198
3199 DisplayListBuilder builder2;
3200 builder2.Save();
3201 {
3202 builder2.TransformReset();
3203 builder2.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
3204 }
3205 builder2.Restore();
3206 builder2.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
3207 auto display_list2 = builder2.Build();
3208
3210 }
3211}
3212
3213TEST_F(DisplayListTest, NOPClipDoesNotTriggerDeferredSave) {
3214 DlScalar NaN = std::numeric_limits<DlScalar>::quiet_NaN();
3215 DisplayListBuilder builder1;
3216 builder1.Save();
3217 {
3218 builder1.Save();
3219 {
3220 builder1.ClipRect(DlRect::MakeLTRB(0, NaN, NaN, 0), DlClipOp::kIntersect,
3221 true);
3222 builder1.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
3223 }
3224 builder1.Restore();
3225 builder1.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
3226 }
3227 builder1.Restore();
3228 auto display_list1 = builder1.Build();
3229
3230 DisplayListBuilder builder2;
3231 builder2.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
3232 builder2.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100),
DlPaint());
3233 auto display_list2 = builder2.Build();
3234
3236}
3237
3238TEST_F(DisplayListTest, RTreeOfClippedSaveLayerFilterScene) {
3239 DisplayListBuilder builder(true);
3240
3241 auto filter = DlBlurImageFilter(10.0, 10.0, DlTileMode::kClamp);
3244 builder.DrawRect(DlRect::MakeLTRB(10, 10, 20, 20), default_paint);
3245 builder.ClipRect(DlRect::MakeLTRB(50, 50, 60, 60), DlClipOp::kIntersect,
3246 false);
3247 builder.SaveLayer(std::nullopt, &filter_paint);
3248
3249
3250
3251 builder.DrawRect(DlRect::MakeLTRB(53, 53, 57, 57), default_paint);
3252 builder.Restore();
3253 auto display_list = builder.Build();
3254 auto rtree = display_list->rtree();
3255 std::vector<DlRect> rects = {
3256 DlRect::MakeLTRB(10, 10, 20, 20),
3257 DlRect::MakeLTRB(50, 50, 60, 60),
3258 };
3259
3260
3261 TEST_RTREE(rtree, DlRect::MakeLTRB(5, 5, 10, 10), rects, {});
3262 TEST_RTREE(rtree, DlRect::MakeLTRB(20, 20, 25, 25), rects, {});
3263 TEST_RTREE(rtree, DlRect::MakeLTRB(45, 45, 50, 50), rects, {});
3264 TEST_RTREE(rtree, DlRect::MakeLTRB(60, 60, 65, 65), rects, {});
3265
3266
3267 TEST_RTREE(rtree, DlRect::MakeLTRB(5, 5, 11, 11), rects, {0});
3268 TEST_RTREE(rtree, DlRect::MakeLTRB(19, 19, 25, 25), rects, {0});
3269 TEST_RTREE(rtree, DlRect::MakeLTRB(45, 45, 51, 51), rects, {1});
3270 TEST_RTREE(rtree, DlRect::MakeLTRB(59, 59, 65, 65), rects, {1});
3271
3272
3273 TEST_RTREE(rtree, DlRect::MakeLTRB(19, 19, 51, 51), rects,
3274 std::vector<int>({0, 1}));
3275}
3276
3277TEST_F(DisplayListTest, RTreeRenderCulling) {
3278 DlRect rect1 = DlRect::MakeLTRB(0, 0, 10, 10);
3279 DlRect rect2 = DlRect::MakeLTRB(20, 0, 30, 10);
3280 DlRect rect3 = DlRect::MakeLTRB(0, 20, 10, 30);
3281 DlRect rect4 = DlRect::MakeLTRB(20, 20, 30, 30);
3286
3287 DisplayListBuilder main_builder(true);
3288 main_builder.DrawRect(rect1, paint1);
3289 main_builder.DrawRect(rect2, paint2);
3290 main_builder.DrawRect(rect3, paint3);
3291 main_builder.DrawRect(rect4, paint4);
3292 auto main = main_builder.Build();
3293
3294 auto test = [
main](
DlIRect cull_rect,
const sk_sp<DisplayList>& expected,
3295 const std::string& label) {
3296 DlRect cull_rectf = DlRect::Make(cull_rect);
3297
3298 {
3299 DisplayListBuilder culling_builder;
3300 main->Dispatch(ToReceiver(culling_builder), cull_rect);
3301
3303 << "using cull rect " << cull_rect
3304 << " where " << label;
3305 }
3306
3307 {
3308 DisplayListBuilder culling_builder;
3309 main->Dispatch(ToReceiver(culling_builder), cull_rectf);
3310
3312 << "using cull rect " << cull_rectf
3313 << " where " << label;
3314 }
3315
3316 {
3317 DisplayListBuilder culling_builder;
3318 DlOpReceiver& receiver = ToReceiver(culling_builder);
3319 auto indices =
main->GetCulledIndices(cull_rectf);
3320 for (DlIndex
i : indices) {
3321 EXPECT_TRUE(
main->Dispatch(receiver,
i));
3322 }
3323
3325 << "using culled indices on cull rect " << cull_rectf
3326 << " where " << label;
3327 }
3328 };
3329
3330 {
3331 DlIRect cull_rect = DlIRect::MakeLTRB(11, 11, 19, 19);
3332
3333 DisplayListBuilder expected_builder;
3334 auto expected = expected_builder.Build();
3335
3336 test(cull_rect, expected, "no rects intersect");
3337 }
3338
3339 {
3340 DlIRect cull_rect = DlIRect::MakeLTRB(9, 9, 19, 19);
3341
3342 DisplayListBuilder expected_builder;
3343 expected_builder.DrawRect(rect1, paint1);
3344 auto expected = expected_builder.Build();
3345
3346 test(cull_rect, expected, "rect 1 intersects");
3347 }
3348
3349 {
3350 DlIRect cull_rect = DlIRect::MakeLTRB(11, 9, 21, 19);
3351
3352 DisplayListBuilder expected_builder;
3353
3354
3355 ToReceiver(expected_builder).setColor(paint1.getColor());
3356 expected_builder.DrawRect(rect2, paint2);
3357 auto expected = expected_builder.Build();
3358
3359 test(cull_rect, expected, "rect 2 intersects");
3360 }
3361
3362 {
3363 DlIRect cull_rect = DlIRect::MakeLTRB(9, 11, 19, 21);
3364
3365 DisplayListBuilder expected_builder;
3366
3367
3368 ToReceiver(expected_builder).setColor(paint1.getColor());
3369 ToReceiver(expected_builder).setColor(paint2.getColor());
3370 expected_builder.DrawRect(rect3, paint3);
3371 auto expected = expected_builder.Build();
3372
3373 test(cull_rect, expected, "rect 3 intersects");
3374 }
3375
3376 {
3377 DlIRect cull_rect = DlIRect::MakeLTRB(11, 11, 21, 21);
3378
3379 DisplayListBuilder expected_builder;
3380
3381
3382 ToReceiver(expected_builder).setColor(paint1.getColor());
3383 ToReceiver(expected_builder).setColor(paint2.getColor());
3384 ToReceiver(expected_builder).setColor(paint3.getColor());
3385 expected_builder.DrawRect(rect4, paint4);
3386 auto expected = expected_builder.Build();
3387
3388 test(cull_rect, expected, "rect 4 intersects");
3389 }
3390
3391 {
3392 DlIRect cull_rect = DlIRect::MakeLTRB(9, 9, 21, 21);
3393
3394 test(cull_rect,
main,
"all rects intersect");
3395 }
3396}
3397
3398TEST_F(DisplayListTest, DrawSaveDrawCannotInheritOpacity) {
3399 DisplayListBuilder builder;
3401 builder.Save();
3402 builder.ClipRect(DlRect::MakeLTRB(0, 0, 20, 20), DlClipOp::kIntersect, false);
3403 builder.DrawRect(DlRect::MakeLTRB(5, 5, 15, 15),
DlPaint());
3404 builder.Restore();
3405 auto display_list = builder.Build();
3406
3407 ASSERT_FALSE(display_list->can_apply_group_opacity());
3408}
3409
3410TEST_F(DisplayListTest, DrawUnorderedRect) {
3412 canvas.DrawRect(rect, paint);
3413 };
3414 check_inverted_bounds(renderer, "DrawRect");
3415}
3416
3417TEST_F(DisplayListTest, DrawUnorderedRoundRect) {
3419 canvas.DrawRoundRect(DlRoundRect::MakeRectXY(rect, 2.0f, 2.0f), paint);
3420 };
3421 check_inverted_bounds(renderer, "DrawRoundRect");
3422}
3423
3424TEST_F(DisplayListTest, DrawUnorderedOval) {
3426 canvas.DrawOval(rect, paint);
3427 };
3428 check_inverted_bounds(renderer, "DrawOval");
3429}
3430
3431TEST_F(DisplayListTest, DrawUnorderedRectangularPath) {
3433 canvas.DrawPath(DlPath::MakeRect(rect), paint);
3434 };
3435 check_inverted_bounds(renderer, "DrawRectangularPath");
3436}
3437
3438TEST_F(DisplayListTest, DrawUnorderedOvalPath) {
3440 canvas.DrawPath(DlPath::MakeOval(rect), paint);
3441 };
3442 check_inverted_bounds(renderer, "DrawOvalPath");
3443}
3444
3445TEST_F(DisplayListTest, DrawUnorderedRoundRectPathCW) {
3447 DlPath path = DlPath::MakeRoundRectXY(rect, 2.0f, 2.0f,
false);
3448 canvas.DrawPath(path, paint);
3449 };
3450 check_inverted_bounds(renderer, "DrawRoundRectPath Clockwise");
3451}
3452
3453TEST_F(DisplayListTest, DrawUnorderedRoundRectPathCCW) {
3455 DlPath path = DlPath::MakeRoundRectXY(rect, 2.0f, 2.0f,
true);
3456 canvas.DrawPath(path, paint);
3457 };
3458 check_inverted_bounds(renderer, "DrawRoundRectPath Counter-Clockwise");
3459}
3460
3461TEST_F(DisplayListTest, NopOperationsOmittedFromRecords) {
3462 auto run_tests = [](
const std::string&
name,
3463 void init(DisplayListBuilder & builder, DlPaint & paint),
3464 uint32_t expected_op_count = 0u,
3465 uint32_t expected_total_depth = 0u) {
3466 auto run_one_test =
3467 [init](
const std::string&
name,
3468 void build(DisplayListBuilder & builder, DlPaint & paint),
3469 uint32_t expected_op_count = 0u,
3470 uint32_t expected_total_depth = 0u) {
3471 DisplayListBuilder builder;
3473 init(builder, paint);
3474 build(builder, paint);
3475 auto list = builder.Build();
3476 if (list->op_count() != expected_op_count) {
3478 }
3479 ASSERT_EQ(list->op_count(), expected_op_count) <<
name;
3480 EXPECT_EQ(list->total_depth(), expected_total_depth) <<
name;
3481 ASSERT_TRUE(list->GetBounds().IsEmpty()) <<
name;
3482 };
3483 run_one_test(
3484 name +
" DrawColor",
3485 [](DisplayListBuilder& builder, DlPaint& paint) {
3486 builder.DrawColor(paint.getColor(), paint.getBlendMode());
3487 },
3488 expected_op_count, expected_total_depth);
3489 run_one_test(
3490 name +
" DrawPaint",
3491 [](DisplayListBuilder& builder, DlPaint& paint) {
3492 builder.DrawPaint(paint);
3493 },
3494 expected_op_count, expected_total_depth);
3495 run_one_test(
3497 [](DisplayListBuilder& builder, DlPaint& paint) {
3498 builder.DrawRect(DlRect::MakeLTRB(10, 10, 20, 20), paint);
3499 },
3500 expected_op_count, expected_total_depth);
3501 run_one_test(
3502 name +
" Other Draw Ops",
3503 [](DisplayListBuilder& builder, DlPaint& paint) {
3505 builder.DrawOval(DlRect::MakeLTRB(10, 10, 20, 20), paint);
3506 builder.DrawCircle(
DlPoint(50, 50), 20, paint);
3507 builder.DrawRoundRect(
3508 DlRoundRect::MakeRectXY(DlRect::MakeLTRB(10, 10, 20, 20), 5, 5),
3509 paint);
3510 builder.DrawDiffRoundRect(
3511 DlRoundRect::MakeRectXY(DlRect::MakeLTRB(5, 5, 100, 100), 5, 5),
3512 DlRoundRect::MakeRectXY(DlRect::MakeLTRB(10, 10, 20, 20), 5, 5),
3513 paint);
3514 builder.DrawPath(kTestPath1, paint);
3515 builder.DrawArc(DlRect::MakeLTRB(10, 10, 20, 20), 45, 90, true,
3516 paint);
3518 builder.DrawPoints(DlPointMode::kLines, 2, pts, paint);
3519 builder.DrawVertices(kTestVertices1, DlBlendMode::kSrcOver, paint);
3520 builder.DrawImage(kTestImage1,
DlPoint(10, 10),
3521 DlImageSampling::kLinear, &paint);
3522 builder.DrawImageRect(kTestImage1,
3523 DlRect::MakeLTRB(0.0f, 0.0f, 10.0f, 10.0f),
3524 DlRect::MakeLTRB(10.0f, 10.0f, 25.0f, 25.0f),
3525 DlImageSampling::kLinear, &paint);
3526 builder.DrawImageNine(kTestImage1, DlIRect::MakeLTRB(10, 10, 20, 20),
3527 DlRect::MakeLTRB(10, 10, 100, 100),
3528 DlFilterMode::kLinear, &paint);
3530 DlRSTransform::Make({10.0f, 10.0f}, 1.0f,
DlDegrees(0)),
3531 DlRSTransform::Make({10.0f, 10.0f}, 1.0f,
DlDegrees(90)),
3532 };
3534 DlRect::MakeLTRB(10, 10, 20, 20),
3535 DlRect::MakeLTRB(10, 20, 30, 20),
3536 };
3537 builder.DrawAtlas(kTestImage1, xforms, rects, nullptr, 2,
3538 DlBlendMode::kSrcOver, DlImageSampling::kLinear,
3539 nullptr, &paint);
3540 builder.DrawText(DlTextSkia::Make(
GetTestTextBlob(1)), 10, 10, paint);
3541#if IMPELLER_SUPPORTS_RENDERING
3542 builder.DrawText(DlTextImpeller::Make(GetTestTextFrame(1)), 10, 10,
3543 paint);
3544#endif
3545
3546
3547
3548 if (paint.getBlendMode() != DlBlendMode::kDst) {
3549 builder.DrawDisplayList(TestDisplayList1, paint.getOpacity());
3550 builder.DrawShadow(kTestPath1, paint.getColor(), 1, true, 1);
3551 }
3552 },
3553 expected_op_count, expected_total_depth);
3554 run_one_test(
3555 name +
" SaveLayer",
3556 [](DisplayListBuilder& builder, DlPaint& paint) {
3557 builder.SaveLayer(std::nullopt, &paint, nullptr);
3558 builder.DrawRect(DlRect::MakeLTRB(10, 10, 20, 20),
DlPaint());
3559 builder.Restore();
3560 },
3561 expected_op_count, expected_total_depth);
3562 run_one_test(
3563 name +
" inside Save",
3564 [](DisplayListBuilder& builder, DlPaint& paint) {
3565 builder.Save();
3566 builder.DrawRect(DlRect::MakeLTRB(10, 10, 20, 20), paint);
3567 builder.Restore();
3568 },
3569 expected_op_count, expected_total_depth);
3570 };
3571 run_tests("transparent color",
3572 [](DisplayListBuilder& builder, DlPaint& paint) {
3573 paint.setColor(DlColor::kTransparent());
3574 });
3575 run_tests("0 alpha",
3576 [](DisplayListBuilder& builder, DlPaint& paint) {
3577
3578
3579
3580 paint.setColor(DlColor::kWhite());
3581 paint.setAlpha(0);
3582 });
3583 run_tests("BlendMode::kDst",
3584 [](DisplayListBuilder& builder, DlPaint& paint) {
3585 paint.setBlendMode(DlBlendMode::kDst);
3586 });
3587 run_tests("Empty rect clip",
3588 [](DisplayListBuilder& builder, DlPaint& paint) {
3589 builder.ClipRect(
DlRect(), DlClipOp::kIntersect,
false);
3590 });
3591 run_tests("Empty rrect clip",
3592 [](DisplayListBuilder& builder, DlPaint& paint) {
3593 builder.ClipRoundRect(
DlRoundRect(), DlClipOp::kIntersect,
false);
3594 });
3595 run_tests("Empty path clip",
3596 [](DisplayListBuilder& builder, DlPaint& paint) {
3597 builder.ClipPath(
DlPath(), DlClipOp::kIntersect,
false);
3598 });
3599 run_tests("Transparent SaveLayer",
3600 [](DisplayListBuilder& builder, DlPaint& paint) {
3602 save_paint.
setColor(DlColor::kTransparent());
3603 builder.SaveLayer(std::nullopt, &save_paint);
3604 });
3605 run_tests("0 alpha SaveLayer",
3606 [](DisplayListBuilder& builder, DlPaint& paint) {
3608
3609
3610
3611 save_paint.
setColor(DlColor::kWhite());
3613 builder.SaveLayer(std::nullopt, &save_paint);
3614 });
3615 run_tests("Dst blended SaveLayer",
3616 [](DisplayListBuilder& builder, DlPaint& paint) {
3619 builder.SaveLayer(std::nullopt, &save_paint);
3620 });
3621 run_tests(
3622 "Nop inside SaveLayer",
3623 [](DisplayListBuilder& builder, DlPaint& paint) {
3624 builder.SaveLayer(std::nullopt, nullptr);
3625 paint.setBlendMode(DlBlendMode::kDst);
3626 },
3627 2u, 1u);
3628 run_tests("DrawImage inside Culled SaveLayer",
3629 [](DisplayListBuilder& builder, DlPaint& paint) {
3631 save_paint.
setColor(DlColor::kTransparent());
3632 builder.SaveLayer(std::nullopt, &save_paint);
3633 builder.DrawImage(kTestImage1,
DlPoint(10, 10),
3634 DlImageSampling::kLinear);
3635 });
3636}
3637
3638class SaveLayerBoundsExpector : public virtual DlOpReceiver,
3639 public IgnoreAttributeDispatchHelper,
3640 public IgnoreClipDispatchHelper,
3641 public IgnoreTransformDispatchHelper,
3642 public IgnoreDrawDispatchHelper {
3643 public:
3644 explicit SaveLayerBoundsExpector() {}
3645
3646 SaveLayerBoundsExpector& addComputedExpectation(const DlRect& bounds) {
3647 expected_.emplace_back(BoundsExpectation{
3648 .bounds = bounds,
3650 });
3651 return *this;
3652 }
3653
3654 SaveLayerBoundsExpector& addSuppliedExpectation(const DlRect& bounds,
3655 bool clipped = false) {
3658 if (clipped) {
3660 }
3661 expected_.emplace_back(BoundsExpectation{
3662 .bounds = bounds,
3663 .options = options,
3664 });
3665 return *this;
3666 }
3667
3668 void saveLayer(const DlRect& bounds,
3669 const SaveLayerOptions options,
3670 const DlImageFilter* backdrop,
3671 std::optional<int64_t> backdrop_id) override {
3672 ASSERT_LT(save_layer_count_, expected_.size());
3673 auto expected = expected_[save_layer_count_];
3674 EXPECT_EQ(options.bounds_from_caller(),
3675 expected.options.bounds_from_caller())
3676 << "expected bounds index " << save_layer_count_;
3677 EXPECT_EQ(options.content_is_clipped(),
3678 expected.options.content_is_clipped())
3679 << "expected bounds index " << save_layer_count_;
3684 EXPECT_EQ(bounds, expected.bounds)
3685 << "expected bounds index " << save_layer_count_;
3686 }
3687 save_layer_count_++;
3688 }
3689
3690 bool all_bounds_checked() const {
3691 return save_layer_count_ == expected_.size();
3692 }
3693
3694 private:
3695 struct BoundsExpectation {
3698 };
3699
3700 std::vector<BoundsExpectation> expected_;
3701 size_t save_layer_count_ = 0;
3702};
3703
3704TEST_F(DisplayListTest, SaveLayerBoundsComputationOfSimpleRect) {
3705 DlRect rect = DlRect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f);
3706
3707 DisplayListBuilder builder;
3708 builder.SaveLayer(std::nullopt, nullptr);
3709 {
3710 builder.DrawRect(rect,
DlPaint());
3711 }
3712 builder.Restore();
3713 auto display_list = builder.Build();
3714
3715 SaveLayerBoundsExpector expector;
3716 expector.addComputedExpectation(rect);
3717 display_list->Dispatch(expector);
3718 EXPECT_TRUE(expector.all_bounds_checked());
3719}
3720
3721TEST_F(DisplayListTest, SaveLayerBoundsComputationOfMaskBlurredRect) {
3722 DlRect rect = DlRect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f);
3724 auto mask_filter = DlBlurMaskFilter::Make(DlBlurStyle::kNormal, 2.0f);
3725 draw_paint.setMaskFilter(mask_filter);
3726
3727 DisplayListBuilder builder;
3728 builder.SaveLayer(std::nullopt, nullptr);
3729 {
3730 builder.DrawRect(rect, draw_paint);
3731 }
3732 builder.Restore();
3733 auto display_list = builder.Build();
3734
3735 SaveLayerBoundsExpector expector;
3736 expector.addComputedExpectation(rect.Expand(6.0f, 6.0f));
3737 display_list->Dispatch(expector);
3738 EXPECT_TRUE(expector.all_bounds_checked());
3739}
3740
3741TEST_F(DisplayListTest, SaveLayerBoundsComputationOfImageBlurredRect) {
3742 DlRect rect = DlRect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f);
3744 auto image_filter = DlImageFilter::MakeBlur(2.0f, 3.0f, DlTileMode::kDecal);
3745 draw_paint.setImageFilter(image_filter);
3746
3747 DisplayListBuilder builder;
3748 builder.SaveLayer(std::nullopt, nullptr);
3749 {
3750 builder.DrawRect(rect, draw_paint);
3751 }
3752 builder.Restore();
3753 auto display_list = builder.Build();
3754
3755 SaveLayerBoundsExpector expector;
3756 expector.addComputedExpectation(rect.Expand(6.0f, 9.0f));
3757 display_list->Dispatch(expector);
3758 EXPECT_TRUE(expector.all_bounds_checked());
3759}
3760
3761TEST_F(DisplayListTest, SaveLayerBoundsComputationOfStrokedRect) {
3762 DlRect rect = DlRect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f);
3766
3767 DisplayListBuilder builder;
3768 builder.SaveLayer(std::nullopt, nullptr);
3769 {
3770 builder.DrawRect(rect, draw_paint);
3771 }
3772 builder.Restore();
3773 auto display_list = builder.Build();
3774
3775 SaveLayerBoundsExpector expector;
3776 expector.addComputedExpectation(rect.Expand(2.5f, 2.5f));
3777 display_list->Dispatch(expector);
3778 EXPECT_TRUE(expector.all_bounds_checked());
3779}
3780
3781TEST_F(DisplayListTest, TranslatedSaveLayerBoundsComputationOfSimpleRect) {
3782 DlRect rect = DlRect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f);
3783
3784 DisplayListBuilder builder;
3785 builder.Translate(10.0f, 10.0f);
3786 builder.SaveLayer(std::nullopt, nullptr);
3787 {
3788 builder.DrawRect(rect,
DlPaint());
3789 }
3790 builder.Restore();
3791 auto display_list = builder.Build();
3792
3793 SaveLayerBoundsExpector expector;
3794 expector.addComputedExpectation(rect);
3795 display_list->Dispatch(expector);
3796 EXPECT_TRUE(expector.all_bounds_checked());
3797}
3798
3799TEST_F(DisplayListTest, ScaledSaveLayerBoundsComputationOfSimpleRect) {
3800 DlRect rect = DlRect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f);
3801
3802 DisplayListBuilder builder;
3803 builder.Scale(10.0f, 10.0f);
3804 builder.SaveLayer(std::nullopt, nullptr);
3805 {
3806 builder.DrawRect(rect,
DlPaint());
3807 }
3808 builder.Restore();
3809 auto display_list = builder.Build();
3810
3811 SaveLayerBoundsExpector expector;
3812 expector.addComputedExpectation(rect);
3813 display_list->Dispatch(expector);
3814 EXPECT_TRUE(expector.all_bounds_checked());
3815}
3816
3817TEST_F(DisplayListTest, RotatedSaveLayerBoundsComputationOfSimpleRect) {
3818 DlRect rect = DlRect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f);
3819
3820 DisplayListBuilder builder;
3821 builder.Rotate(45.0f);
3822 builder.SaveLayer(std::nullopt, nullptr);
3823 {
3824 builder.DrawRect(rect,
DlPaint());
3825 }
3826 builder.Restore();
3827 auto display_list = builder.Build();
3828
3829 SaveLayerBoundsExpector expector;
3830 expector.addComputedExpectation(rect);
3831 display_list->Dispatch(expector);
3832 EXPECT_TRUE(expector.all_bounds_checked());
3833}
3834
3835TEST_F(DisplayListTest, TransformResetSaveLayerBoundsComputationOfSimpleRect) {
3836 DlRect rect = DlRect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f);
3837 DlRect rect_doubled = DlRect::MakeLTRB(200.0f, 200.0f, 400.0f, 400.0f);
3838
3839 DisplayListBuilder builder;
3840 builder.Scale(10.0f, 10.0f);
3841 builder.SaveLayer(std::nullopt, nullptr);
3842 builder.TransformReset();
3843 builder.Scale(20.0f, 20.0f);
3844
3845 {
3846 builder.DrawRect(rect,
DlPaint());
3847 }
3848 builder.Restore();
3849 auto display_list = builder.Build();
3850
3851 SaveLayerBoundsExpector expector;
3852 expector.addComputedExpectation(rect_doubled);
3853 display_list->Dispatch(expector);
3854 EXPECT_TRUE(expector.all_bounds_checked());
3855}
3856
3857TEST_F(DisplayListTest, SaveLayerBoundsComputationOfTranslatedSimpleRect) {
3858 DlRect rect = DlRect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f);
3859
3860 DisplayListBuilder builder;
3861 builder.SaveLayer(std::nullopt, nullptr);
3862 {
3863 builder.Translate(10.0f, 10.0f);
3864 builder.DrawRect(rect,
DlPaint());
3865 }
3866 builder.Restore();
3867 auto display_list = builder.Build();
3868
3869 SaveLayerBoundsExpector expector;
3870 expector.addComputedExpectation(rect.Shift(10.0f, 10.0f));
3871 display_list->Dispatch(expector);
3872 EXPECT_TRUE(expector.all_bounds_checked());
3873}
3874
3875TEST_F(DisplayListTest, SaveLayerBoundsComputationOfScaledSimpleRect) {
3876 DlRect rect = DlRect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f);
3877
3878 DisplayListBuilder builder;
3879 builder.SaveLayer(std::nullopt, nullptr);
3880 {
3881 builder.Scale(10.0f, 10.0f);
3882 builder.DrawRect(rect,
DlPaint());
3883 }
3884 builder.Restore();
3885 auto display_list = builder.Build();
3886
3887 SaveLayerBoundsExpector expector;
3888 expector.addComputedExpectation(
3889 DlRect::MakeLTRB(1000.0f, 1000.0f, 2000.0f, 2000.0f));
3890 display_list->Dispatch(expector);
3891 EXPECT_TRUE(expector.all_bounds_checked());
3892}
3893
3894TEST_F(DisplayListTest, SaveLayerBoundsComputationOfRotatedSimpleRect) {
3895 DlRect rect = DlRect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f);
3896
3897 DisplayListBuilder builder;
3898 builder.SaveLayer(std::nullopt, nullptr);
3899 {
3900 builder.Rotate(45.0f);
3901 builder.DrawRect(rect,
DlPaint());
3902 }
3903 builder.Restore();
3904 auto display_list = builder.Build();
3905
3907 SaveLayerBoundsExpector expector;
3908 expector.addComputedExpectation(rect.TransformAndClipBounds(matrix));
3909 display_list->Dispatch(expector);
3910 EXPECT_TRUE(expector.all_bounds_checked());
3911}
3912
3913TEST_F(DisplayListTest, SaveLayerBoundsComputationOfNestedSimpleRect) {
3914 DlRect rect = DlRect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f);
3915
3916 DisplayListBuilder builder;
3917 builder.SaveLayer(std::nullopt, nullptr);
3918 {
3919 builder.SaveLayer(std::nullopt, nullptr);
3920 {
3921 builder.DrawRect(rect,
DlPaint());
3922 }
3923 builder.Restore();
3924 }
3925 builder.Restore();
3926 auto display_list = builder.Build();
3927
3928 SaveLayerBoundsExpector expector;
3929 expector.addComputedExpectation(rect);
3930 expector.addComputedExpectation(rect);
3931 display_list->Dispatch(expector);
3932 EXPECT_TRUE(expector.all_bounds_checked());
3933}
3934
3935TEST_F(DisplayListTest, FloodingSaveLayerBoundsComputationOfSimpleRect) {
3936 DlRect rect = DlRect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f);
3938 auto color_filter =
3939 DlColorFilter::MakeBlend(DlColor::kRed(), DlBlendMode::kSrc);
3940 ASSERT_TRUE(color_filter->modifies_transparent_black());
3941 save_paint.setColorFilter(color_filter);
3943 ASSERT_NE(clip_rect, rect);
3944 ASSERT_TRUE(clip_rect.Contains(rect));
3945
3946 DisplayListBuilder builder;
3947 builder.ClipRect(clip_rect);
3948 builder.SaveLayer(std::nullopt, &save_paint);
3949 {
3950 builder.DrawRect(rect,
DlPaint());
3951 }
3952 builder.Restore();
3953 auto display_list = builder.Build();
3954
3955 SaveLayerBoundsExpector expector;
3956 expector.addComputedExpectation(rect);
3957 display_list->Dispatch(expector);
3958 EXPECT_TRUE(expector.all_bounds_checked());
3959}
3960
3961TEST_F(DisplayListTest, NestedFloodingSaveLayerBoundsComputationOfSimpleRect) {
3962 DlRect rect = DlRect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f);
3964 auto color_filter =
3965 DlColorFilter::MakeBlend(DlColor::kRed(), DlBlendMode::kSrc);
3966 ASSERT_TRUE(color_filter->modifies_transparent_black());
3967 save_paint.setColorFilter(color_filter);
3969 ASSERT_NE(clip_rect, rect);
3970 ASSERT_TRUE(clip_rect.Contains(rect));
3971
3972 DisplayListBuilder builder;
3973 builder.ClipRect(clip_rect);
3974 builder.SaveLayer(std::nullopt, nullptr);
3975 {
3976 builder.SaveLayer(std::nullopt, &save_paint);
3977 {
3978 builder.DrawRect(rect,
DlPaint());
3979 }
3980 builder.Restore();
3981 }
3982 builder.Restore();
3983 auto display_list = builder.Build();
3984
3985 EXPECT_EQ(display_list->GetBounds(), clip_rect);
3986
3987 SaveLayerBoundsExpector expector;
3988 expector.addComputedExpectation(clip_rect);
3989 expector.addComputedExpectation(rect);
3990 display_list->Dispatch(expector);
3991 EXPECT_TRUE(expector.all_bounds_checked());
3992}
3993
3994TEST_F(DisplayListTest, SaveLayerBoundsComputationOfFloodingImageFilter) {
3995 DlRect rect = DlRect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f);
3997 auto color_filter =
3998 DlColorFilter::MakeBlend(DlColor::kRed(), DlBlendMode::kSrc);
3999 ASSERT_TRUE(color_filter->modifies_transparent_black());
4000 auto image_filter = DlImageFilter::MakeColorFilter(color_filter);
4001 draw_paint.setImageFilter(image_filter);
4003 ASSERT_NE(clip_rect, rect);
4004 ASSERT_TRUE(clip_rect.Contains(rect));
4005
4006 DisplayListBuilder builder;
4007 builder.ClipRect(clip_rect);
4008 builder.SaveLayer(std::nullopt, nullptr);
4009 {
4010 builder.DrawRect(rect, draw_paint);
4011 }
4012 builder.Restore();
4013 auto display_list = builder.Build();
4014
4015 SaveLayerBoundsExpector expector;
4016 expector.addComputedExpectation(clip_rect);
4017 display_list->Dispatch(expector);
4018 EXPECT_TRUE(expector.all_bounds_checked());
4019}
4020
4021TEST_F(DisplayListTest, SaveLayerBoundsComputationOfFloodingColorFilter) {
4022 DlRect rect = DlRect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f);
4024 auto color_filter =
4025 DlColorFilter::MakeBlend(DlColor::kRed(), DlBlendMode::kSrc);
4026 ASSERT_TRUE(color_filter->modifies_transparent_black());
4027 draw_paint.setColorFilter(color_filter);
4029 ASSERT_NE(clip_rect, rect);
4030 ASSERT_TRUE(clip_rect.Contains(rect));
4031
4032 DisplayListBuilder builder;
4033 builder.ClipRect(clip_rect);
4034 builder.SaveLayer(std::nullopt, nullptr);
4035 {
4036 builder.DrawRect(rect, draw_paint);
4037 }
4038 builder.Restore();
4039 auto display_list = builder.Build();
4040
4041
4042
4043 SaveLayerBoundsExpector expector;
4044 expector.addComputedExpectation(rect);
4045 display_list->Dispatch(expector);
4046 EXPECT_TRUE(expector.all_bounds_checked());
4047}
4048
4049TEST_F(DisplayListTest, SaveLayerBoundsClipDetectionSimpleUnclippedRect) {
4050 DlRect rect = DlRect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f);
4051 DlRect save_rect = DlRect::MakeLTRB(50.0f, 50.0f, 250.0f, 250.0f);
4052
4053 DisplayListBuilder builder;
4054 builder.SaveLayer(save_rect, nullptr);
4055 {
4056 builder.DrawRect(rect,
DlPaint());
4057 }
4058 builder.Restore();
4059 auto display_list = builder.Build();
4060
4061 SaveLayerBoundsExpector expector;
4062 expector.addSuppliedExpectation(rect);
4063 display_list->Dispatch(expector);
4064 EXPECT_TRUE(expector.all_bounds_checked());
4065}
4066
4067TEST_F(DisplayListTest, SaveLayerBoundsClipDetectionSimpleClippedRect) {
4068 DlRect rect = DlRect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f);
4069 DlRect save_rect = DlRect::MakeLTRB(50.0f, 50.0f, 110.0f, 110.0f);
4070 DlRect content_rect = DlRect::MakeLTRB(100.0f, 100.0f, 110.0f, 110.0f);
4071
4072 DisplayListBuilder builder;
4073 builder.SaveLayer(save_rect, nullptr);
4074 {
4075 builder.DrawRect(rect,
DlPaint());
4076 }
4077 builder.Restore();
4078 auto display_list = builder.Build();
4079
4080 SaveLayerBoundsExpector expector;
4081 expector.addSuppliedExpectation(content_rect, true);
4082 display_list->Dispatch(expector);
4083 EXPECT_TRUE(expector.all_bounds_checked());
4084}
4085
4086TEST_F(DisplayListTest, DisjointSaveLayerBoundsProduceEmptySuppliedBounds) {
4087
4088
4089
4090
4091
4092
4093
4094 DlRect layer_bounds = DlRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
4095 DlRect draw_rect = DlRect::MakeLTRB(50.0f, 50.0f, 100.0f, 100.0f);
4096 ASSERT_FALSE(layer_bounds.IntersectsWithRect(draw_rect));
4097 ASSERT_FALSE(layer_bounds.IsEmpty());
4098 ASSERT_FALSE(draw_rect.IsEmpty());
4099
4100 DisplayListBuilder builder;
4101 builder.SaveLayer(layer_bounds, nullptr);
4102 builder.DrawRect(draw_rect,
DlPaint());
4103 builder.Restore();
4104 auto display_list = builder.Build();
4105
4106 SaveLayerBoundsExpector expector;
4107 expector.addSuppliedExpectation(
DlRect(),
false);
4108 display_list->Dispatch(expector);
4109 EXPECT_TRUE(expector.all_bounds_checked());
4110}
4111
4112class DepthExpector : public virtual DlOpReceiver,
4113 virtual IgnoreAttributeDispatchHelper,
4114 virtual IgnoreTransformDispatchHelper,
4115 virtual IgnoreClipDispatchHelper,
4116 virtual IgnoreDrawDispatchHelper {
4117 public:
4118 explicit DepthExpector(std::vector<uint32_t> expectations)
4119 : depth_expectations_(
std::move(expectations)) {}
4120
4121 void save() override {
4122
4123
4124 FAIL() << "save(no depth parameter) method should not be called";
4125 }
4126
4127 void save(uint32_t total_content_depth) override {
4128 ASSERT_LT(index_, depth_expectations_.size());
4129 EXPECT_EQ(depth_expectations_[index_], total_content_depth)
4130 << "at index " << index_;
4131 index_++;
4132 }
4133
4134 void saveLayer(const DlRect& bounds,
4135 SaveLayerOptions options,
4136 const DlImageFilter* backdrop,
4137 std::optional<int64_t> backdrop_id) override {
4138
4139
4140 FAIL() << "saveLayer(no depth parameter) method should not be called";
4141 }
4142
4143 void saveLayer(const DlRect& bounds,
4144 const SaveLayerOptions& options,
4145 uint32_t total_content_depth,
4146 DlBlendMode max_content_mode,
4147 const DlImageFilter* backdrop,
4148 std::optional<int64_t> backdrop_id) override {
4149 ASSERT_LT(index_, depth_expectations_.size());
4150 EXPECT_EQ(depth_expectations_[index_], total_content_depth)
4151 << "at index " << index_;
4152 index_++;
4153 }
4154
4155 bool all_depths_checked() const {
4156 return index_ == depth_expectations_.size();
4157 }
4158
4159 private:
4160 size_t index_ = 0;
4161 std::vector<uint32_t> depth_expectations_;
4162};
4163
4164TEST_F(DisplayListTest, SaveContentDepthTest) {
4165 DisplayListBuilder child_builder;
4166 child_builder.DrawRect(DlRect::MakeLTRB(10, 10, 20, 20),
4168 auto child = child_builder.Build();
4169
4170 DisplayListBuilder builder;
4171 builder.DrawRect(DlRect::MakeLTRB(10, 10, 20, 20),
DlPaint());
4172
4173 builder.Save();
4174 {
4175 builder.Translate(5, 5);
4176 builder.DrawRect(DlRect::MakeLTRB(10, 10, 20, 20),
DlPaint());
4177
4178 builder.DrawDisplayList(child, 1.0f);
4179
4180 builder.SaveLayer(std::nullopt, nullptr);
4181 {
4182 builder.DrawRect(DlRect::MakeLTRB(12, 12, 22, 22),
DlPaint());
4183 builder.DrawRect(DlRect::MakeLTRB(14, 14, 24, 24),
DlPaint());
4184 }
4185 builder.Restore();
4186
4187 builder.DrawRect(DlRect::MakeLTRB(16, 16, 26, 26),
DlPaint());
4188 builder.DrawRect(DlRect::MakeLTRB(18, 18, 28, 28),
DlPaint());
4189 }
4190 builder.Restore();
4191
4192 builder.DrawRect(DlRect::MakeLTRB(16, 16, 26, 26),
DlPaint());
4193 builder.DrawRect(DlRect::MakeLTRB(18, 18, 28, 28),
DlPaint());
4194 auto display_list = builder.Build();
4195
4196 EXPECT_EQ(display_list->total_depth(), 11u);
4197
4198 DepthExpector expector({8, 2});
4199 display_list->Dispatch(expector);
4200}
4201
4202TEST_F(DisplayListTest, FloodingFilteredLayerPushesRestoreOpIndex) {
4203 DisplayListBuilder builder(true);
4204 builder.ClipRect(DlRect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f));
4205
4206
4208
4209 const float matrix[] = {
4210 0.5f, 0.0f, 0.0f, 0.0f, 0.5f,
4211 0.5f, 0.0f, 0.0f, 0.0f, 0.5f,
4212 0.5f, 0.0f, 0.0f, 0.0f, 0.5f,
4213 0.5f, 0.0f, 0.0f, 0.0f, 0.5f
4214 };
4215
4216 auto color_filter = DlColorFilter::MakeMatrix(matrix);
4217 save_paint.setImageFilter(DlImageFilter::MakeColorFilter(color_filter));
4218 builder.SaveLayer(std::nullopt, &save_paint);
4220
4221 builder.DrawRect(DlRect::MakeLTRB(120.0f, 120.0f, 125.0f, 125.0f),
DlPaint());
4223
4224 builder.Restore();
4226
4227 auto dl = builder.Build();
4228 std::vector<int> indices;
4229 dl->rtree()->search(DlRect::MakeLTRB(0.0f, 0.0f, 500.0f, 500.0f), &indices);
4230 ASSERT_EQ(indices.size(), 3u);
4231 EXPECT_EQ(dl->rtree()->id(indices[0]), save_layer_id);
4232 EXPECT_EQ(dl->rtree()->id(indices[1]), draw_rect_id);
4233 EXPECT_EQ(dl->rtree()->id(indices[2]), restore_id);
4234}
4235
4236TEST_F(DisplayListTest, TransformingFilterSaveLayerSimpleContentBounds) {
4237 DisplayListBuilder builder;
4238 builder.ClipRect(DlRect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f));
4239
4241 auto image_filter =
4242 DlImageFilter::MakeMatrix(DlMatrix::MakeTranslation({100.0f, 100.0f}),
4243 DlImageSampling::kNearestNeighbor);
4244 save_paint.setImageFilter(image_filter);
4245 builder.SaveLayer(std::nullopt, &save_paint);
4246
4247 builder.DrawRect(DlRect::MakeLTRB(20.0f, 20.0f, 25.0f, 25.0f),
DlPaint());
4248
4249 builder.Restore();
4250
4251 auto dl = builder.Build();
4252 EXPECT_EQ(dl->GetBounds(), DlRect::MakeLTRB(120.0f, 120.0f, 125.0f, 125.0f));
4253}
4254
4255TEST_F(DisplayListTest, TransformingFilterSaveLayerFloodedContentBounds) {
4256 DisplayListBuilder builder;
4257 builder.ClipRect(DlRect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f));
4258
4260 auto image_filter =
4261 DlImageFilter::MakeMatrix(DlMatrix::MakeTranslation({100.0f, 100.0f}),
4262 DlImageSampling::kNearestNeighbor);
4263 save_paint.setImageFilter(image_filter);
4264 builder.SaveLayer(std::nullopt, &save_paint);
4265
4266 builder.DrawColor(DlColor::kBlue(), DlBlendMode::kSrcOver);
4267
4268 builder.Restore();
4269
4270 auto dl = builder.Build();
4271 EXPECT_EQ(dl->GetBounds(), DlRect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f));
4272}
4273
4274TEST_F(DisplayListTest, OpacityIncompatibleRenderOpInsideDeferredSave) {
4275 {
4276
4277 DisplayListBuilder builder;
4278 builder.DrawRect(DlRect::MakeLTRB(0, 0, 10, 10),
4279 DlPaint().setBlendMode(DlBlendMode::kClear));
4280 EXPECT_FALSE(builder.Build()->can_apply_group_opacity());
4281 }
4282
4283 {
4284
4285 DisplayListBuilder builder;
4286 builder.Save();
4287 {
4288
4289 builder.DrawRect(DlRect::MakeLTRB(0, 0, 10, 10),
4290 DlPaint().setBlendMode(DlBlendMode::kClear));
4291 }
4292
4293
4294 builder.Restore();
4295 EXPECT_FALSE(builder.Build()->can_apply_group_opacity());
4296 }
4297}
4298
4299TEST_F(DisplayListTest, MaxBlendModeEmptyDisplayList) {
4300 DisplayListBuilder builder;
4301 EXPECT_EQ(builder.Build()->max_root_blend_mode(), DlBlendMode::kClear);
4302}
4303
4304TEST_F(DisplayListTest, MaxBlendModeSimpleRect) {
4306 DisplayListBuilder builder;
4307 builder.DrawRect(DlRect::MakeLTRB(0, 0, 10, 10),
4310 (
mode == DlBlendMode::kDst) ? DlBlendMode::kClear :
mode;
4311 EXPECT_EQ(builder.Build()->max_root_blend_mode(), expect)
4312 <<
"testing " <<
mode;
4313 };
4314
4315 for (
int i = 0; i < static_cast<int>(DlBlendMode::kLastMode);
i++) {
4317 }
4318}
4319
4320TEST_F(DisplayListTest, MaxBlendModeInsideNonDeferredSave) {
4321 DisplayListBuilder builder;
4322 builder.Save();
4323 {
4324
4325 builder.Scale(2.0f, 2.0f);
4326 builder.DrawRect(DlRect::MakeLTRB(0, 0, 10, 10),
4327 DlPaint().setBlendMode(DlBlendMode::kModulate));
4328 }
4329
4330 builder.Restore();
4331 EXPECT_EQ(builder.Build()->max_root_blend_mode(), DlBlendMode::kModulate);
4332}
4333
4334TEST_F(DisplayListTest, MaxBlendModeInsideDeferredSave) {
4335 DisplayListBuilder builder;
4336 builder.Save();
4337 {
4338
4339 builder.DrawRect(DlRect::MakeLTRB(0, 0, 10, 10),
4340 DlPaint().setBlendMode(DlBlendMode::kModulate));
4341 }
4342
4343 builder.Restore();
4344 EXPECT_EQ(builder.Build()->max_root_blend_mode(), DlBlendMode::kModulate);
4345}
4346
4347TEST_F(DisplayListTest, MaxBlendModeInsideSaveLayer) {
4348 DisplayListBuilder builder;
4349 builder.SaveLayer(std::nullopt, nullptr);
4350 {
4351 builder.DrawRect(DlRect::MakeLTRB(0, 0, 10, 10),
4352 DlPaint().setBlendMode(DlBlendMode::kModulate));
4353 }
4354 builder.Restore();
4355 auto dl = builder.Build();
4356 EXPECT_EQ(dl->max_root_blend_mode(), DlBlendMode::kSrcOver);
4358 expector.addExpectation(DlBlendMode::kModulate);
4359 dl->Dispatch(expector);
4360 EXPECT_TRUE(expector.all_expectations_checked());
4361}
4362
4363TEST_F(DisplayListTest, MaxBlendModeInsideNonDefaultBlendedSaveLayer) {
4364 DisplayListBuilder builder;
4367 builder.SaveLayer(std::nullopt, &save_paint);
4368 {
4369 builder.DrawRect(DlRect::MakeLTRB(0, 0, 10, 10),
4370 DlPaint().setBlendMode(DlBlendMode::kModulate));
4371 }
4372 builder.Restore();
4373 auto dl = builder.Build();
4374 EXPECT_EQ(dl->max_root_blend_mode(), DlBlendMode::kScreen);
4376 expector.addExpectation(DlBlendMode::kModulate);
4377 dl->Dispatch(expector);
4378 EXPECT_TRUE(expector.all_expectations_checked());
4379}
4380
4381TEST_F(DisplayListTest, MaxBlendModeInsideComplexDeferredSaves) {
4382 DisplayListBuilder builder;
4383 builder.Save();
4384 {
4385 builder.DrawRect(DlRect::MakeLTRB(0, 0, 10, 10),
4386 DlPaint().setBlendMode(DlBlendMode::kModulate));
4387 builder.Save();
4388 {
4389
4390 ASSERT_GT(DlBlendMode::kScreen, DlBlendMode::kModulate);
4391 builder.DrawRect(DlRect::MakeLTRB(0, 0, 10, 10),
4392 DlPaint().setBlendMode(DlBlendMode::kScreen));
4393 }
4394 builder.Restore();
4395
4396
4397 ASSERT_LT(DlBlendMode::kSrc, DlBlendMode::kModulate);
4398 builder.DrawRect(DlRect::MakeLTRB(0, 0, 10, 10),
4399 DlPaint().setBlendMode(DlBlendMode::kSrc));
4400 }
4401 builder.Restore();
4402
4403
4404 auto expect = std::max(DlBlendMode::kModulate, DlBlendMode::kScreen);
4405 expect = std::max(expect, DlBlendMode::kSrc);
4406 ASSERT_EQ(expect, DlBlendMode::kScreen);
4407
4408 EXPECT_EQ(builder.Build()->max_root_blend_mode(), DlBlendMode::kScreen);
4409}
4410
4411TEST_F(DisplayListTest, MaxBlendModeInsideComplexSaveLayers) {
4412 DisplayListBuilder builder;
4413 builder.SaveLayer(std::nullopt, nullptr);
4414 {
4415
4416 builder.DrawRect(DlRect::MakeLTRB(0, 0, 10, 10),
4417 DlPaint().setBlendMode(DlBlendMode::kModulate));
4418 builder.SaveLayer(std::nullopt, nullptr);
4419 {
4420
4421 builder.DrawRect(DlRect::MakeLTRB(0, 0, 10, 10),
4422 DlPaint().setBlendMode(DlBlendMode::kScreen));
4423 }
4424 builder.Restore();
4425
4426
4427 ASSERT_LT(DlBlendMode::kSrc, DlBlendMode::kModulate);
4428 builder.DrawRect(DlRect::MakeLTRB(0, 0, 10, 10),
4429 DlPaint().setBlendMode(DlBlendMode::kSrc));
4430 }
4431 builder.Restore();
4432
4433
4434
4435 auto expect = std::max(DlBlendMode::kModulate, DlBlendMode::kSrc);
4436 ASSERT_EQ(expect, DlBlendMode::kModulate);
4437
4438 auto dl = builder.Build();
4439 EXPECT_EQ(dl->max_root_blend_mode(), DlBlendMode::kSrcOver);
4441 expector
4442 .addExpectation(DlBlendMode::kModulate)
4443 .addExpectation(DlBlendMode::kScreen);
4444 dl->Dispatch(expector);
4445 EXPECT_TRUE(expector.all_expectations_checked());
4446}
4447
4448TEST_F(DisplayListTest, BackdropDetectionEmptyDisplayList) {
4449 DisplayListBuilder builder;
4450 EXPECT_FALSE(builder.Build()->root_has_backdrop_filter());
4451}
4452
4453TEST_F(DisplayListTest, BackdropDetectionSimpleRect) {
4454 DisplayListBuilder builder;
4455 builder.DrawRect(DlRect::MakeLTRB(0, 0, 10, 10),
DlPaint());
4456 EXPECT_FALSE(builder.Build()->root_has_backdrop_filter());
4457}
4458
4459TEST_F(DisplayListTest, BackdropDetectionSimpleSaveLayer) {
4460 DisplayListBuilder builder;
4461 builder.SaveLayer(std::nullopt, nullptr, &kTestBlurImageFilter1);
4462 {
4463
4464 builder.DrawRect(DlRect::MakeLTRB(0, 0, 10, 10),
DlPaint());
4465 }
4466 builder.Restore();
4467 auto dl = builder.Build();
4468
4469 EXPECT_TRUE(dl->root_has_backdrop_filter());
4470
4471
4473 expector.addExpectation(
4474 SaveLayerOptions::kNoAttributes.with_can_distribute_opacity());
4475 dl->Dispatch(expector);
4476 EXPECT_TRUE(expector.all_expectations_checked());
4477}
4478
4479TEST_F(DisplayListTest, BackdropDetectionNestedSaveLayer) {
4480 DisplayListBuilder builder;
4481 builder.SaveLayer(std::nullopt, nullptr);
4482 {
4483
4484 builder.DrawRect(DlRect::MakeLTRB(0, 0, 10, 10),
DlPaint());
4485 builder.SaveLayer(std::nullopt, nullptr, &kTestBlurImageFilter1);
4486 {
4487
4488 builder.DrawRect(DlRect::MakeLTRB(10, 10, 20, 20),
DlPaint());
4489 }
4490 builder.Restore();
4491 }
4492 builder.Restore();
4493 auto dl = builder.Build();
4494
4495 EXPECT_FALSE(dl->root_has_backdrop_filter());
4497 expector
4498 .addExpectation(SaveLayerOptions::kNoAttributes
4499 .with_contains_backdrop_filter()
4500 .with_content_is_unbounded())
4501 .addExpectation(
4502 SaveLayerOptions::kNoAttributes.with_can_distribute_opacity());
4503 dl->Dispatch(expector);
4504 EXPECT_TRUE(expector.all_expectations_checked());
4505}
4506
4507TEST_F(DisplayListTest, DrawDisplayListForwardsMaxBlend) {
4508 DisplayListBuilder child_builder;
4509 child_builder.DrawRect(DlRect::MakeLTRB(0, 0, 10, 10),
4510 DlPaint().setBlendMode(DlBlendMode::kMultiply));
4511 auto child_dl = child_builder.Build();
4512 EXPECT_EQ(child_dl->max_root_blend_mode(), DlBlendMode::kMultiply);
4513 EXPECT_FALSE(child_dl->root_has_backdrop_filter());
4514
4515 DisplayListBuilder parent_builder;
4516 parent_builder.DrawDisplayList(child_dl);
4517 auto parent_dl = parent_builder.Build();
4518 EXPECT_EQ(parent_dl->max_root_blend_mode(), DlBlendMode::kMultiply);
4519 EXPECT_FALSE(parent_dl->root_has_backdrop_filter());
4520}
4521
4522TEST_F(DisplayListTest, DrawDisplayListForwardsBackdropFlag) {
4523 DisplayListBuilder child_builder;
4524 DlBlurImageFilter backdrop(2.0f, 2.0f, DlTileMode::kDecal);
4525 child_builder.SaveLayer(std::nullopt, nullptr, &backdrop);
4526 child_builder.DrawRect(DlRect::MakeLTRB(0, 0, 10, 10),
4527 DlPaint().setBlendMode(DlBlendMode::kMultiply));
4528 child_builder.Restore();
4529 auto child_dl = child_builder.Build();
4530 EXPECT_EQ(child_dl->max_root_blend_mode(), DlBlendMode::kSrcOver);
4531 EXPECT_TRUE(child_dl->root_has_backdrop_filter());
4532
4533 DisplayListBuilder parent_builder;
4534 parent_builder.DrawDisplayList(child_dl);
4535 auto parent_dl = parent_builder.Build();
4536 EXPECT_EQ(parent_dl->max_root_blend_mode(), DlBlendMode::kSrcOver);
4537 EXPECT_TRUE(parent_dl->root_has_backdrop_filter());
4538}
4539
4540#define CLIP_EXPECTOR(name) ClipExpector name(__FILE__, __LINE__)
4541
4542struct ClipExpectation {
4543 std::variant<DlRect, DlRoundRect, DlRoundSuperellipse, DlPath> shape;
4544 bool is_oval;
4546 bool is_aa;
4547
4548 std::string shape_name() {
4549 switch (shape.index()) {
4550 case 0:
4551 return is_oval ? "Oval" : "Rect";
4552 case 1:
4553 return "DlRoundRect";
4554 case 2:
4555 return "DlRoundSuperellipse";
4556 case 3:
4557 return "DlPath";
4558 default:
4559 return "Unknown";
4560 }
4561 }
4562};
4563
4564::std::ostream&
operator<<(::std::ostream& os,
const ClipExpectation& expect) {
4565 os << "Expectation(";
4566 switch (expect.shape.index()) {
4567 case 0:
4568 os << std::get<DlRect>(expect.shape);
4569 if (expect.is_oval) {
4570 os << " (oval)";
4571 }
4572 break;
4573 case 1:
4574 os << std::get<DlRoundRect>(expect.shape);
4575 break;
4576 case 2:
4577 os << std::get<DlPath>(expect.shape).GetSkPath();
4578 break;
4579 case 3:
4580 os << "Unknown";
4581 }
4582 os << ", " << expect.clip_op;
4583 os << ", " << expect.is_aa;
4584 os << ")";
4585 return os;
4586}
4587
4588class ClipExpector : public virtual DlOpReceiver,
4589 virtual IgnoreAttributeDispatchHelper,
4590 virtual IgnoreTransformDispatchHelper,
4591 virtual IgnoreDrawDispatchHelper {
4592 public:
4593
4594 explicit ClipExpector(const std::string& file, int line)
4595 : file_(file), line_(line) {}
4596
4597 ~ClipExpector() {
4598 EXPECT_EQ(index_, clip_expectations_.size()) << label();
4599 while (index_ < clip_expectations_.size()) {
4600 auto expect = clip_expectations_[index_];
4601 FML_LOG(ERROR) <<
"leftover clip shape[" << index_ <<
"] = " << expect;
4602 index_++;
4603 }
4604 }
4605
4606 ClipExpector& addExpectation(const DlRect& rect,
4607 DlClipOp clip_op = DlClipOp::kIntersect,
4608 bool is_aa = false) {
4609 clip_expectations_.push_back({
4610 .shape = rect,
4611 .is_oval = false,
4612 .clip_op = clip_op,
4613 .is_aa = is_aa,
4614 });
4615 return *this;
4616 }
4617
4618 ClipExpector& addOvalExpectation(const DlRect& rect,
4619 DlClipOp clip_op = DlClipOp::kIntersect,
4620 bool is_aa = false) {
4621 clip_expectations_.push_back({
4622 .shape = rect,
4623 .is_oval = true,
4624 .clip_op = clip_op,
4625 .is_aa = is_aa,
4626 });
4627 return *this;
4628 }
4629
4630 ClipExpector& addExpectation(const DlRoundRect& rrect,
4631 DlClipOp clip_op = DlClipOp::kIntersect,
4632 bool is_aa = false) {
4633 clip_expectations_.push_back({
4634 .shape = rrect,
4635 .is_oval = false,
4636 .clip_op = clip_op,
4637 .is_aa = is_aa,
4638 });
4639 return *this;
4640 }
4641
4642 ClipExpector& addExpectation(const DlPath& path,
4643 DlClipOp clip_op = DlClipOp::kIntersect,
4644 bool is_aa = false) {
4645 clip_expectations_.push_back({
4647 .is_oval = false,
4648 .clip_op = clip_op,
4649 .is_aa = is_aa,
4650 });
4651 return *this;
4652 }
4653
4654 void clipRect(const DlRect& rect, DlClipOp clip_op, bool is_aa) override {
4655 check(rect, clip_op, is_aa);
4656 }
4657 void clipOval(const DlRect& bounds, DlClipOp clip_op, bool is_aa) override {
4658 check(bounds, clip_op, is_aa, true);
4659 }
4660 void clipRoundRect(const DlRoundRect& rrect,
4661 DlClipOp clip_op,
4662 bool is_aa) override {
4663 check(rrect, clip_op, is_aa);
4664 }
4665 void clipRoundSuperellipse(const DlRoundSuperellipse& rse,
4666 DlClipOp clip_op,
4667 bool is_aa) override {
4668 check(rse, clip_op, is_aa);
4669 }
4670 void clipPath(const DlPath& path, DlClipOp clip_op, bool is_aa) override {
4671 check(path, clip_op, is_aa);
4672 }
4673
4674 private:
4675 size_t index_ = 0;
4676 std::vector<ClipExpectation> clip_expectations_;
4677
4678 template <typename T>
4679 void check(const T& shape,
4680 DlClipOp clip_op,
4681 bool is_aa,
4682 bool is_oval = false) {
4683 ASSERT_LT(index_, clip_expectations_.size())
4684 << label() << std::endl
4685 << "extra clip shape = " << shape << (is_oval ? " (oval)" : "");
4686 auto expected = clip_expectations_[index_];
4687 if (!std::holds_alternative<T>(expected.shape)) {
4688 EXPECT_TRUE(std::holds_alternative<T>(expected.shape))
4689 << label() << ", expected type: " << expected.shape_name();
4690 } else {
4691 EXPECT_EQ(std::get<T>(expected.shape), shape) << label();
4692 }
4693 EXPECT_EQ(expected.is_oval, is_oval) << label();
4694 EXPECT_EQ(expected.clip_op, clip_op) << label();
4695 EXPECT_EQ(expected.is_aa, is_aa) << label();
4696 index_++;
4697 }
4698
4699 const std::string file_;
4700 const int line_;
4701
4702 std::string label() {
4703 return "at index " + std::to_string(index_) +
4704 ", from " + file_ +
4705 ":" + std::to_string(line_);
4706 }
4707};
4708
4709TEST_F(DisplayListTest, ClipRectCullingPixel6a) {
4710
4711
4712
4713
4714
4715
4716
4717
4718 auto frame = DlRect::MakeLTRB(0.0f, 0.0f, 1080.0f, 2400.0f);
4720 auto clip = DlRect::MakeLTRB(0.0f, 0.0f, 1080.0f / DPR, 2400.0f / DPR);
4721
4722 DisplayListBuilder cull_builder;
4723 cull_builder.ClipRect(frame, DlClipOp::kIntersect, false);
4724 cull_builder.Scale(DPR, DPR);
4725 cull_builder.ClipRect(clip, DlClipOp::kIntersect, false);
4726 auto cull_dl = cull_builder.Build();
4727
4729 expector.addExpectation(frame, DlClipOp::kIntersect, false);
4730 cull_dl->Dispatch(expector);
4731}
4732
4733TEST_F(DisplayListTest, ClipRectCulling) {
4734 auto clip = DlRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
4735
4736 DisplayListBuilder cull_builder;
4737 cull_builder.ClipRect(clip, DlClipOp::kIntersect, false);
4738 cull_builder.ClipRect(clip.Expand(1.0f, 1.0f), DlClipOp::kIntersect, false);
4739 auto cull_dl = cull_builder.Build();
4740
4742 expector.addExpectation(clip, DlClipOp::kIntersect, false);
4743 cull_dl->Dispatch(expector);
4744}
4745
4746TEST_F(DisplayListTest, ClipRectNonCulling) {
4747 auto clip = DlRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
4748 auto smaller_clip = clip.Expand(-1.0f, -1.0f);
4749
4750 DisplayListBuilder cull_builder;
4751 cull_builder.ClipRect(clip, DlClipOp::kIntersect, false);
4752 cull_builder.ClipRect(smaller_clip, DlClipOp::kIntersect, false);
4753 auto cull_dl = cull_builder.Build();
4754
4756 expector.addExpectation(clip, DlClipOp::kIntersect, false);
4757 expector.addExpectation(smaller_clip, DlClipOp::kIntersect, false);
4758 cull_dl->Dispatch(expector);
4759}
4760
4761TEST_F(DisplayListTest, ClipRectNestedCulling) {
4762 auto clip = DlRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
4763 auto larger_clip = clip.Expand(1.0f, 1.0f);
4764
4765 DisplayListBuilder cull_builder;
4766 cull_builder.ClipRect(clip, DlClipOp::kIntersect, false);
4767 cull_builder.Save();
4768 cull_builder.ClipRect(larger_clip, DlClipOp::kIntersect, false);
4769 cull_builder.Restore();
4770 auto cull_dl = cull_builder.Build();
4771
4773 expector.addExpectation(clip, DlClipOp::kIntersect, false);
4774 cull_dl->Dispatch(expector);
4775}
4776
4777TEST_F(DisplayListTest, ClipRectNestedNonCulling) {
4778 auto clip = DlRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
4779 auto larger_clip = clip.Expand(1.0f, 1.0f);
4780
4781 DisplayListBuilder cull_builder;
4782 cull_builder.Save();
4783 cull_builder.ClipRect(clip, DlClipOp::kIntersect, false);
4784 cull_builder.Restore();
4785
4786 cull_builder.ClipRect(larger_clip, DlClipOp::kIntersect, false);
4787 auto cull_dl = cull_builder.Build();
4788
4790 expector.addExpectation(clip, DlClipOp::kIntersect, false);
4791 expector.addExpectation(larger_clip, DlClipOp::kIntersect, false);
4792 cull_dl->Dispatch(expector);
4793}
4794
4795TEST_F(DisplayListTest, ClipRectNestedCullingComplex) {
4796 auto clip = DlRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
4797 auto smaller_clip = clip.Expand(-1.0f, -1.0f);
4798 auto smallest_clip = clip.Expand(-2.0f, -2.0f);
4799
4800 DisplayListBuilder cull_builder;
4801 cull_builder.ClipRect(clip, DlClipOp::kIntersect, false);
4802 cull_builder.Save();
4803 cull_builder.ClipRect(smallest_clip, DlClipOp::kIntersect, false);
4804 cull_builder.ClipRect(smaller_clip, DlClipOp::kIntersect, false);
4805 cull_builder.Restore();
4806 auto cull_dl = cull_builder.Build();
4807
4809 expector.addExpectation(clip, DlClipOp::kIntersect, false);
4810 expector.addExpectation(smallest_clip, DlClipOp::kIntersect, false);
4811 cull_dl->Dispatch(expector);
4812}
4813
4814TEST_F(DisplayListTest, ClipRectNestedNonCullingComplex) {
4815 auto clip = DlRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
4816 auto smaller_clip = clip.Expand(-1.0f, -1.0f);
4817 auto smallest_clip = clip.Expand(-2.0f, -2.0f);
4818
4819 DisplayListBuilder cull_builder;
4820 cull_builder.ClipRect(clip, DlClipOp::kIntersect, false);
4821 cull_builder.Save();
4822 cull_builder.ClipRect(smallest_clip, DlClipOp::kIntersect, false);
4823 cull_builder.Restore();
4824
4825 cull_builder.ClipRect(smaller_clip, DlClipOp::kIntersect, false);
4826 auto cull_dl = cull_builder.Build();
4827
4829 expector.addExpectation(clip, DlClipOp::kIntersect, false);
4830 expector.addExpectation(smallest_clip, DlClipOp::kIntersect, false);
4831 expector.addExpectation(smaller_clip, DlClipOp::kIntersect, false);
4832 cull_dl->Dispatch(expector);
4833}
4834
4835TEST_F(DisplayListTest, ClipOvalCulling) {
4836 auto clip = DlRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
4837
4838
4839
4840
4841 auto encompassing_oval = clip.Expand(2.072f, 2.072f);
4842
4843 DisplayListBuilder cull_builder;
4844 cull_builder.ClipRect(clip, DlClipOp::kIntersect, false);
4845 cull_builder.ClipOval(encompassing_oval, DlClipOp::kIntersect, false);
4846 auto cull_dl = cull_builder.Build();
4847
4849 expector.addExpectation(clip, DlClipOp::kIntersect, false);
4850 cull_dl->Dispatch(expector);
4851}
4852
4853TEST_F(DisplayListTest, ClipOvalNonCulling) {
4854 auto clip = DlRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
4855
4856
4857
4858
4859 auto non_encompassing_oval = clip.Expand(2.071f, 2.071f);
4860
4861 DisplayListBuilder cull_builder;
4862 cull_builder.ClipRect(clip, DlClipOp::kIntersect, false);
4863 cull_builder.ClipOval(non_encompassing_oval, DlClipOp::kIntersect, false);
4864 auto cull_dl = cull_builder.Build();
4865
4867 expector.addExpectation(clip, DlClipOp::kIntersect, false);
4868 expector.addOvalExpectation(non_encompassing_oval, DlClipOp::kIntersect,
4869 false);
4870 cull_dl->Dispatch(expector);
4871}
4872
4873TEST_F(DisplayListTest, ClipRRectCulling) {
4874 auto clip = DlRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
4875 auto rrect = DlRoundRect::MakeRectXY(clip.Expand(2.0f, 2.0f), 2.0f, 2.0f);
4876 ASSERT_FALSE(rrect.IsOval());
4877
4878 DisplayListBuilder cull_builder;
4879 cull_builder.ClipRect(clip, DlClipOp::kIntersect, false);
4880 cull_builder.ClipRoundRect(rrect, DlClipOp::kIntersect, false);
4881 auto cull_dl = cull_builder.Build();
4882
4884 expector.addExpectation(clip, DlClipOp::kIntersect, false);
4885 cull_dl->Dispatch(expector);
4886}
4887
4888TEST_F(DisplayListTest, ClipRRectNonCulling) {
4889 auto clip = DlRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
4890 auto rrect = DlRoundRect::MakeRectXY(clip.Expand(1.0f, 1.0f), 4.0f, 4.0f);
4891 ASSERT_FALSE(rrect.IsOval());
4892
4893 DisplayListBuilder cull_builder;
4894 cull_builder.ClipRect(clip, DlClipOp::kIntersect, false);
4895 cull_builder.ClipRoundRect(rrect, DlClipOp::kIntersect, false);
4896 auto cull_dl = cull_builder.Build();
4897
4899 expector.addExpectation(clip, DlClipOp::kIntersect, false);
4900 expector.addExpectation(rrect, DlClipOp::kIntersect, false);
4901 cull_dl->Dispatch(expector);
4902}
4903
4904TEST_F(DisplayListTest, ClipPathNonCulling) {
4905 auto clip = DlRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
4906 DlPathBuilder path_builder;
4907 path_builder.MoveTo({0.0f, 0.0f});
4908 path_builder.LineTo({1000.0f, 0.0f});
4909 path_builder.LineTo({0.0f, 1000.0f});
4910 path_builder.Close();
4912
4913
4914
4915
4916
4917
4918 ASSERT_TRUE(
path.Contains(clip.GetLeftTop()));
4919 ASSERT_TRUE(
path.Contains(clip.GetRightTop()));
4920 ASSERT_TRUE(
path.Contains(clip.GetRightBottom()));
4921 ASSERT_TRUE(
path.Contains(clip.GetLeftBottom()));
4922
4923 DisplayListBuilder cull_builder;
4924 cull_builder.ClipRect(clip, DlClipOp::kIntersect, false);
4925 cull_builder.ClipPath(path, DlClipOp::kIntersect, false);
4926 auto cull_dl = cull_builder.Build();
4927
4929 expector.addExpectation(clip, DlClipOp::kIntersect, false);
4930 expector.addExpectation(path, DlClipOp::kIntersect, false);
4931 cull_dl->Dispatch(expector);
4932}
4933
4934TEST_F(DisplayListTest, ClipPathRectCulling) {
4935 auto clip = DlRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
4936 DlPath path = DlPath::MakeRect(clip.Expand(1.0f, 1.0f));
4937
4938 DisplayListBuilder cull_builder;
4939 cull_builder.ClipRect(clip, DlClipOp::kIntersect, false);
4940 cull_builder.ClipPath(path, DlClipOp::kIntersect, false);
4941 auto cull_dl = cull_builder.Build();
4942
4944 expector.addExpectation(clip, DlClipOp::kIntersect, false);
4945 cull_dl->Dispatch(expector);
4946}
4947
4948TEST_F(DisplayListTest, ClipPathRectNonCulling) {
4949 auto clip = DlRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
4950 auto smaller_clip = clip.Expand(-1.0f, -1.0f);
4951 DlPath path = DlPath::MakeRect(smaller_clip);
4952
4953 DisplayListBuilder cull_builder;
4954 cull_builder.ClipRect(clip, DlClipOp::kIntersect, false);
4955 cull_builder.ClipPath(path, DlClipOp::kIntersect, false);
4956 auto cull_dl = cull_builder.Build();
4957
4959 expector.addExpectation(clip, DlClipOp::kIntersect, false);
4960
4961 expector.addExpectation(smaller_clip, DlClipOp::kIntersect, false);
4962 cull_dl->Dispatch(expector);
4963}
4964
4965TEST_F(DisplayListTest, ClipPathOvalCulling) {
4966 auto clip = DlRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
4967
4968
4969
4970
4971 auto encompassing_oval = clip.Expand(2.072f, 2.072f);
4972 DlPath path = DlPath::MakeOval(encompassing_oval);
4973
4974 DisplayListBuilder cull_builder;
4975 cull_builder.ClipRect(clip, DlClipOp::kIntersect, false);
4976 cull_builder.ClipPath(path, DlClipOp::kIntersect, false);
4977 auto cull_dl = cull_builder.Build();
4978
4980 expector.addExpectation(clip, DlClipOp::kIntersect, false);
4981 cull_dl->Dispatch(expector);
4982}
4983
4984TEST_F(DisplayListTest, ClipPathOvalNonCulling) {
4985 auto clip = DlRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
4986
4987
4988
4989
4990 auto non_encompassing_oval = clip.Expand(2.071f, 2.071f);
4991 DlPath path = DlPath::MakeOval(non_encompassing_oval);
4992
4993 DisplayListBuilder cull_builder;
4994 cull_builder.ClipRect(clip, DlClipOp::kIntersect, false);
4995 cull_builder.ClipPath(path, DlClipOp::kIntersect, false);
4996 auto cull_dl = cull_builder.Build();
4997
4999 expector.addExpectation(clip, DlClipOp::kIntersect, false);
5000
5001 expector.addOvalExpectation(non_encompassing_oval, DlClipOp::kIntersect,
5002 false);
5003 cull_dl->Dispatch(expector);
5004}
5005
5006TEST_F(DisplayListTest, ClipPathRRectCulling) {
5007 auto clip = DlRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
5008 DlPath path = DlPath::MakeRoundRectXY(clip.Expand(2.0f, 2.0f), 2.0f, 2.0f);
5009 ASSERT_FALSE(
path.IsOval());
5010
5011 DisplayListBuilder cull_builder;
5012 cull_builder.ClipRect(clip, DlClipOp::kIntersect, false);
5013 cull_builder.ClipPath(path, DlClipOp::kIntersect, false);
5014 auto cull_dl = cull_builder.Build();
5015
5017 expector.addExpectation(clip, DlClipOp::kIntersect, false);
5018 cull_dl->Dispatch(expector);
5019}
5020
5021TEST_F(DisplayListTest, ClipPathRRectNonCulling) {
5022 auto clip = DlRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
5023 auto rrect = DlRoundRect::MakeRectXY(clip.Expand(1.0f, 1.0f), 4.0f, 4.0f);
5024 ASSERT_FALSE(rrect.IsOval());
5026
5027 DisplayListBuilder cull_builder;
5028 cull_builder.ClipRect(clip, DlClipOp::kIntersect, false);
5029 cull_builder.ClipPath(path, DlClipOp::kIntersect, false);
5030 auto cull_dl = cull_builder.Build();
5031
5033 expector.addExpectation(clip, DlClipOp::kIntersect, false);
5034
5035 expector.addExpectation(rrect, DlClipOp::kIntersect, false);
5036 cull_dl->Dispatch(expector);
5037}
5038
5039TEST_F(DisplayListTest, RecordLargeVertices) {
5040 constexpr size_t vertex_count = 2000000;
5041 auto points = std::vector<DlPoint>();
5042 points.reserve(vertex_count);
5043 auto colors = std::vector<DlColor>();
5044 colors.reserve(vertex_count);
5045 for (
size_t i = 0;
i < vertex_count;
i++) {
5048 }
5049 ASSERT_EQ(
points.size(), vertex_count);
5050 ASSERT_EQ(colors.size(), vertex_count);
5051 auto vertices = DlVertices::Make(DlVertexMode::kTriangleStrip, vertex_count,
5053 ASSERT_GT(vertices->size(), 1u << 24);
5054 auto backdrop = DlImageFilter::MakeBlur(5.0f, 5.0f, DlTileMode::kDecal);
5055
5056 for (
int i = 0;
i < 1000;
i++) {
5057 DisplayListBuilder builder;
5058 for (int j = 0; j < 16; j++) {
5059 builder.SaveLayer(std::nullopt, nullptr, backdrop.get());
5060 builder.DrawVertices(vertices, DlBlendMode::kSrcOver,
DlPaint());
5061 builder.Restore();
5062 }
5063 auto dl = builder.Build();
5064 }
5065}
5066
5067TEST_F(DisplayListTest, DrawRectRRectPromoteToDrawRect) {
5068 DlRect rect = DlRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
5069
5070 DisplayListBuilder builder;
5071 builder.DrawRoundRect(DlRoundRect::MakeRect(rect),
DlPaint());
5072 auto dl = builder.Build();
5073
5074 DisplayListBuilder expected;
5075 expected.DrawRect(rect,
DlPaint());
5076 auto expect_dl = expected.Build();
5077
5079}
5080
5081TEST_F(DisplayListTest, DrawOvalRRectPromoteToDrawOval) {
5082 DlRect rect = DlRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
5083
5084 DisplayListBuilder builder;
5085 builder.DrawRoundRect(DlRoundRect::MakeOval(rect),
DlPaint());
5086 auto dl = builder.Build();
5087
5088 DisplayListBuilder expected;
5089 expected.DrawOval(rect,
DlPaint());
5090 auto expect_dl = expected.Build();
5091
5093}
5094
5095
5096TEST_F(DisplayListTest, DrawDiffRoundRectPromoteToDrawRoundRect) {
5097 DlRect outer_rect = DlRect::MakeLTRB(10.0f, 10.0f, 110.0f, 110.0f);
5099 .top_right =
DlSize(10.0f),
5100 .bottom_left =
DlSize(20.0f),
5101 .bottom_right =
DlSize(50.0f)};
5102 DlRoundRect outer_rrect = DlRoundRect::MakeRectRadii(outer_rect, outer_radii);
5103
5108 .top_right =
DlSize(outer_radii.top_right.width - inner_inset),
5109 .bottom_left =
DlSize(outer_radii.bottom_left.width - inner_inset),
5110 .bottom_right =
DlSize(outer_radii.bottom_right.width - inner_inset)};
5111 DlRoundRect inner_rrect = DlRoundRect::MakeRectRadii(inner_rect, inner_radii);
5112
5114
5115 DisplayListBuilder builder;
5116 builder.DrawDiffRoundRect(outer_rrect, inner_rrect, paint);
5117 auto dl = builder.Build();
5118
5119 EXPECT_EQ(CountOps(dl, DisplayListOpType::kDrawDiffRoundRect), 0);
5120 EXPECT_EQ(CountOps(dl, DisplayListOpType::kDrawRoundRect), 1);
5121
5122 DlScalar expected_stroke_width = inner_inset;
5123 DlScalar half_width = expected_stroke_width * 0.5f;
5124 DlRoundRect expected_round_rect = DlRoundRect::MakeRectRadii(
5125 inner_rect.Expand(half_width),
5126 {.top_left = DlSize(inner_radii.top_left.width + half_width),
5127 .top_right = DlSize(inner_radii.top_right.width + half_width),
5128 .bottom_left = DlSize(inner_radii.bottom_left.width + half_width),
5129 .bottom_right = DlSize(inner_radii.bottom_right.width + half_width)});
5133
5134 DisplayListBuilder expected;
5135 expected.DrawRoundRect(expected_round_rect, expected_paint);
5136 auto expect_dl = expected.Build();
5137
5139}
5140
5141
5142
5143TEST_F(DisplayListTest, DrawStrokedDiffRoundRectDoesNotPromoteToDrawRoundRect) {
5144
5145
5146 DlRect outer_rect = DlRect::MakeLTRB(10.0f, 10.0f, 110.0f, 110.0f);
5148 .top_right =
DlSize(10.0f),
5149 .bottom_left =
DlSize(20.0f),
5150 .bottom_right =
DlSize(50.0f)};
5151 DlRoundRect outer_rrect = DlRoundRect::MakeRectRadii(outer_rect, outer_radii);
5152
5157 .top_right =
DlSize(outer_radii.top_right.width - inner_inset),
5158 .bottom_left =
DlSize(outer_radii.bottom_left.width - inner_inset),
5159 .bottom_right =
DlSize(outer_radii.bottom_right.width - inner_inset)};
5160 DlRoundRect inner_rrect = DlRoundRect::MakeRectRadii(inner_rect, inner_radii);
5161
5163
5164 DisplayListBuilder builder;
5165 builder.DrawDiffRoundRect(outer_rrect, inner_rrect, paint);
5166 auto dl = builder.Build();
5167
5168 EXPECT_EQ(CountOps(dl, DisplayListOpType::kDrawDiffRoundRect), 1);
5169 EXPECT_EQ(CountOps(dl, DisplayListOpType::kDrawRoundRect), 0);
5170}
5171
5172
5173
5175 DrawDiffRoundRectWithUnequalSidesDoesNotPromoteToDrawRoundRect) {
5176
5177
5178
5179 DlRect outer_rect = DlRect::MakeLTRB(10.0f, 10.0f, 110.0f, 110.0f);
5181 .top_right =
DlSize(10.0f),
5182 .bottom_left =
DlSize(20.0f),
5183 .bottom_right =
DlSize(50.0f)};
5184 DlRoundRect outer_rrect = DlRoundRect::MakeRectRadii(outer_rect, outer_radii);
5185
5188 DlRect inner_rect = outer_rect.
Expand(-inner_inset_x, -inner_inset_y);
5191 .top_right =
DlSize(outer_radii.top_right.width - inner_inset_x),
5192 .bottom_left =
DlSize(outer_radii.bottom_left.width - inner_inset_x),
5193 .bottom_right =
DlSize(outer_radii.bottom_right.width - inner_inset_x)};
5194 DlRoundRect inner_rrect = DlRoundRect::MakeRectRadii(inner_rect, inner_radii);
5195
5197
5198 DisplayListBuilder builder;
5199 builder.DrawDiffRoundRect(outer_rrect, inner_rrect, paint);
5200 auto dl = builder.Build();
5201
5202 EXPECT_EQ(CountOps(dl, DisplayListOpType::kDrawDiffRoundRect), 1);
5203 EXPECT_EQ(CountOps(dl, DisplayListOpType::kDrawRoundRect), 0);
5204}
5205
5206TEST_F(DisplayListTest, DrawRectPathPromoteToDrawRect) {
5207 DlRect rect = DlRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
5208
5209 DisplayListBuilder builder;
5210 builder.DrawPath(DlPath::MakeRect(rect),
DlPaint());
5211 auto dl = builder.Build();
5212
5213 DisplayListBuilder expected;
5214 expected.DrawRect(rect,
DlPaint());
5215 auto expect_dl = expected.Build();
5216
5218}
5219
5220TEST_F(DisplayListTest, DrawFilledRectangularLinesPromoteToDrawRect) {
5221 DlRect rect = DlRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
5222
5223
5225 .MoveTo(rect.GetLeftBottom())
5226 .LineTo(rect.GetLeftTop())
5227 .LineTo(rect.GetRightTop())
5228 .LineTo(rect.GetRightBottom())
5229 .TakePath();
5231
5232 DisplayListBuilder builder;
5233 builder.DrawPath(path, paint);
5234 auto dl = builder.Build();
5235
5236 DisplayListBuilder expected;
5237 expected.DrawRect(rect, paint);
5238 auto expect_dl = expected.Build();
5239
5241}
5242
5244 DrawStrokedUnclosedRectangularLinesDoesNotPromoteToDrawRect) {
5245 DlRect rect = DlRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
5246
5247
5249 .MoveTo(rect.GetLeftBottom())
5250 .LineTo(rect.GetLeftTop())
5251 .LineTo(rect.GetRightTop())
5252 .LineTo(rect.GetRightBottom())
5253 .TakePath();
5255
5256 DisplayListBuilder builder;
5257 builder.DrawPath(path, paint);
5258 auto dl = builder.Build();
5259
5260 DisplayListBuilder rect_dl_builder;
5261 rect_dl_builder.DrawRect(rect, paint);
5262 auto rect_dl = rect_dl_builder.Build();
5263
5265}
5266
5267TEST_F(DisplayListTest, DrawStrokedRectangularLinesPromoteToDrawRect) {
5268 DlRect rect = DlRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
5269
5270
5272 .MoveTo(rect.GetLeftBottom())
5273 .LineTo(rect.GetLeftTop())
5274 .LineTo(rect.GetRightTop())
5275 .LineTo(rect.GetRightBottom())
5276 .Close()
5277 .TakePath();
5279
5280 DisplayListBuilder builder;
5281 builder.DrawPath(path, paint);
5282 auto dl = builder.Build();
5283
5284 DisplayListBuilder expected;
5285 expected.DrawRect(rect, paint);
5286 auto expect_dl = expected.Build();
5287
5289}
5290
5291TEST_F(DisplayListTest, DrawOvalPathPromoteToDrawOval) {
5292 DlRect rect = DlRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
5293
5294 DisplayListBuilder builder;
5295 builder.DrawPath(DlPath::MakeOval(rect),
DlPaint());
5296 auto dl = builder.Build();
5297
5298 DisplayListBuilder expected;
5299 expected.DrawOval(rect,
DlPaint());
5300 auto expect_dl = expected.Build();
5301
5303}
5304
5305TEST_F(DisplayListTest, DrawRRectPathPromoteToDrawRoundRect) {
5306 DlRect rect = DlRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
5307 DlRoundRect rrect = DlRoundRect::MakeRectXY(rect, 2.0f, 2.0f);
5308
5309 DisplayListBuilder builder;
5310 builder.DrawPath(DlPath::MakeRoundRect(rrect),
DlPaint());
5311 auto dl = builder.Build();
5312
5313 DisplayListBuilder expected;
5314 expected.DrawRoundRect(rrect,
DlPaint());
5315 auto expect_dl = expected.Build();
5316
5318}
5319
5320TEST_F(DisplayListTest, DrawRRectPathUnequalRadiiPromoteToDrawRoundRect) {
5321 DlRect rect = DlRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
5323 DlRoundRect::MakeRectRadii(rect, {
5328 });
5329
5330 DisplayListBuilder builder;
5331 builder.DrawPath(DlPath::MakeRoundRect(rrect),
DlPaint());
5332 auto dl = builder.Build();
5333
5334 DisplayListBuilder expected;
5335 expected.DrawRoundRect(rrect,
DlPaint());
5336 auto expect_dl = expected.Build();
5337
5339}
5340
5341TEST_F(DisplayListTest, DrawRRectPathPromoteToDrawRect) {
5342 DlRect rect = DlRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
5344
5345 DisplayListBuilder builder;
5346 builder.DrawPath(DlPath::MakeRoundRect(rrect),
DlPaint());
5347 auto dl = builder.Build();
5348
5349 DisplayListBuilder expected;
5350 expected.DrawRect(rect,
DlPaint());
5351 auto expect_dl = expected.Build();
5352
5354}
5355
5356TEST_F(DisplayListTest, DrawLinePathPromoteToDrawLine) {
5359
5360 DisplayListBuilder builder;
5361 builder.DrawPath(DlPath::MakeLine(start,
end),
DlPaint());
5362 auto dl = builder.Build();
5363
5364 DisplayListBuilder expected;
5366 auto expect_dl = expected.Build();
5367
5369}
5370
5371TEST_F(DisplayListTest, DrawOvalRRectPathPromoteToDrawOval) {
5372 DlRect rect = DlRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
5374
5375 DisplayListBuilder builder;
5376 builder.DrawPath(DlPath::MakeRoundRect(rrect),
DlPaint());
5377 auto dl = builder.Build();
5378
5379 DisplayListBuilder expected;
5380 expected.DrawOval(rect,
DlPaint());
5381 auto expect_dl = expected.Build();
5382
5384}
5385
5386TEST_F(DisplayListTest, ClipRectRRectPromoteToClipRect) {
5387 DlRect clip_rect = DlRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
5389
5390 DisplayListBuilder builder;
5391 builder.ClipRoundRect(DlRoundRect::MakeRect(clip_rect), DlClipOp::kIntersect,
5392 false);
5393
5394 builder.DrawRect(draw_rect,
DlPaint());
5395 auto dl = builder.Build();
5396
5397 DisplayListBuilder expected;
5398 expected.ClipRect(clip_rect, DlClipOp::kIntersect, false);
5399 expected.DrawRect(draw_rect,
DlPaint());
5400 auto expect_dl = expected.Build();
5401
5403}
5404
5405TEST_F(DisplayListTest, ClipOvalRRectPromoteToClipOval) {
5406 DlRect clip_rect = DlRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
5408
5409 DisplayListBuilder builder;
5410 builder.ClipRoundRect(DlRoundRect::MakeOval(clip_rect), DlClipOp::kIntersect,
5411 false);
5412
5413 builder.DrawRect(draw_rect,
DlPaint());
5414 auto dl = builder.Build();
5415
5416 DisplayListBuilder expected;
5417 expected.ClipOval(clip_rect, DlClipOp::kIntersect, false);
5418 expected.DrawRect(draw_rect,
DlPaint());
5419 auto expect_dl = expected.Build();
5420
5422}
5423
5424TEST_F(DisplayListTest, ClipRectPathPromoteToClipRect) {
5425 DlRect clip_rect = DlRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
5427 DlPath clip_path = DlPath::MakeRect(clip_rect);
5428 ASSERT_TRUE(clip_path.IsRect(nullptr));
5429
5430 DisplayListBuilder builder;
5431 builder.ClipPath(clip_path, DlClipOp::kIntersect, false);
5432
5433 builder.DrawRect(draw_rect,
DlPaint());
5434 auto dl = builder.Build();
5435
5436 DisplayListBuilder expected;
5437 expected.ClipRect(clip_rect, DlClipOp::kIntersect, false);
5438 expected.DrawRect(draw_rect,
DlPaint());
5439 auto expect_dl = expected.Build();
5440
5442}
5443
5444TEST_F(DisplayListTest, ClipOvalPathPromoteToClipOval) {
5445 DlRect clip_rect = DlRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
5447 DlPath clip_path = DlPath::MakeOval(clip_rect);
5448 ASSERT_TRUE(clip_path.IsOval(nullptr));
5449
5450 DisplayListBuilder builder;
5451 builder.ClipPath(clip_path, DlClipOp::kIntersect, false);
5452
5453 builder.DrawRect(draw_rect,
DlPaint());
5454 auto dl = builder.Build();
5455
5456 DisplayListBuilder expected;
5457 expected.ClipOval(clip_rect, DlClipOp::kIntersect, false);
5458 expected.DrawRect(draw_rect,
DlPaint());
5459 auto expect_dl = expected.Build();
5460
5462}
5463
5464TEST_F(DisplayListTest, ClipRRectPathPromoteToClipRRect) {
5465 DlRect clip_rect = DlRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
5466 DlRoundRect clip_rrect = DlRoundRect::MakeRectXY(clip_rect, 2.0f, 2.0f);
5468 DlPath clip_path = DlPath::MakeRoundRect(clip_rrect);
5469 ASSERT_TRUE(clip_path.IsRoundRect());
5470
5471 DisplayListBuilder builder;
5472 builder.ClipPath(clip_path, DlClipOp::kIntersect, false);
5473
5474 builder.DrawRect(draw_rect,
DlPaint());
5475 auto dl = builder.Build();
5476
5477 DisplayListBuilder expected;
5478 expected.ClipRoundRect(clip_rrect, DlClipOp::kIntersect, false);
5479 expected.DrawRect(draw_rect,
DlPaint());
5480 auto expect_dl = expected.Build();
5481
5483}
5484
5485TEST_F(DisplayListTest, ClipRectRRectPathPromoteToClipRect) {
5486 DlRect clip_rect = DlRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
5487 DlRoundRect clip_rrect = DlRoundRect::MakeRect(clip_rect);
5489 DlPath clip_path = DlPath::MakeRoundRect(clip_rrect);
5490
5491 DisplayListBuilder builder;
5492 builder.ClipPath(clip_path, DlClipOp::kIntersect, false);
5493
5494 builder.DrawRect(draw_rect,
DlPaint());
5495 auto dl = builder.Build();
5496
5497 DisplayListBuilder expected;
5498 expected.ClipRect(clip_rect, DlClipOp::kIntersect, false);
5499 expected.DrawRect(draw_rect,
DlPaint());
5500 auto expect_dl = expected.Build();
5501
5503}
5504
5505TEST_F(DisplayListTest, ClipOvalRRectPathPromoteToClipOval) {
5506 DlRect clip_rect = DlRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
5507 DlRoundRect clip_rrect = DlRoundRect::MakeOval(clip_rect);
5509 DlPath clip_path = DlPath::MakeRoundRect(clip_rrect);
5510
5511 DisplayListBuilder builder;
5512 builder.ClipPath(clip_path, DlClipOp::kIntersect, false);
5513
5514 builder.DrawRect(draw_rect,
DlPaint());
5515 auto dl = builder.Build();
5516
5517 DisplayListBuilder expected;
5518 expected.ClipOval(clip_rect, DlClipOp::kIntersect, false);
5519 expected.DrawRect(draw_rect,
DlPaint());
5520 auto expect_dl = expected.Build();
5521
5523}
5524
5525TEST_F(DisplayListTest, BoundedRenderOpsDoNotReportUnbounded) {
5526 static const DlRect root_cull = DlRect::MakeLTRB(100, 100, 200, 200);
5527 static const DlRect draw_rect = DlRect::MakeLTRB(110, 110, 190, 190);
5528
5529 using Renderer = const std::function<void(DlCanvas&)>;
5530 auto test_bounded = [](const std::string& label, const Renderer& renderer) {
5531 {
5532 DisplayListBuilder builder(root_cull);
5533 renderer(builder);
5534 auto display_list = builder.Build();
5535
5536 EXPECT_EQ(display_list->GetBounds(), draw_rect) << label;
5537 EXPECT_FALSE(display_list->root_is_unbounded()) << label;
5538 }
5539
5540 {
5541 DisplayListBuilder builder(root_cull);
5542 builder.SaveLayer(std::nullopt, nullptr);
5543 renderer(builder);
5544 builder.Restore();
5545 auto display_list = builder.Build();
5546
5547 EXPECT_EQ(display_list->GetBounds(), draw_rect) << label;
5548 EXPECT_FALSE(display_list->root_is_unbounded()) << label;
5549
5551 expector
5552 .addDetail(label)
5553 .addExpectation([](const SaveLayerOptions& options) {
5554 return !options.content_is_unbounded();
5555 });
5556 display_list->Dispatch(expector);
5557 }
5558 };
5559
5560 test_bounded("DrawLine", [](DlCanvas& builder) {
5561 builder.DrawLine(
5562 DlPoint(draw_rect.GetLeft() + 1.0f, draw_rect.GetTop() + 1.0f),
5563 DlPoint(draw_rect.GetRight() - 1.0f, draw_rect.GetTop() + 1.0f),
5564 DlPaint().setStrokeWidth(2.0f).setStrokeCap(DlStrokeCap::kSquare));
5565 builder.DrawLine(
5566 DlPoint(draw_rect.GetLeft() + 1.0f, draw_rect.GetBottom() - 1.0f),
5567 DlPoint(draw_rect.GetRight() - 1.0f, draw_rect.GetBottom() - 1.0f),
5568 DlPaint().setStrokeWidth(2.0f).setStrokeCap(DlStrokeCap::kSquare));
5569 });
5570
5571 test_bounded("DrawDashedLine", [](DlCanvas& builder) {
5572 builder.DrawDashedLine(
5573 DlPoint(draw_rect.GetLeft() + 1.0f, draw_rect.GetTop() + 1.0f),
5574 DlPoint(draw_rect.GetRight() - 1.0f, draw_rect.GetTop() + 1.0f),
5575
5576
5577
5578 40.0f, 25.0f,
5579 DlPaint().setStrokeWidth(2.0f).setStrokeCap(DlStrokeCap::kSquare));
5580 builder.DrawDashedLine(
5581 DlPoint(draw_rect.GetLeft() + 1.0f, draw_rect.GetBottom() - 1.0f),
5582 DlPoint(draw_rect.GetRight() - 1.0f, draw_rect.GetBottom() - 1.0f),
5583
5584
5585
5586 40.0f, 25.0f,
5587 DlPaint().setStrokeWidth(2.0f).setStrokeCap(DlStrokeCap::kSquare));
5588 });
5589
5590 test_bounded("DrawRect", [](DlCanvas& builder) {
5591 builder.DrawRect(draw_rect,
DlPaint());
5592 });
5593
5594 test_bounded("DrawOval", [](DlCanvas& builder) {
5595 builder.DrawOval(draw_rect,
DlPaint());
5596 });
5597
5598 test_bounded("DrawCircle", [](DlCanvas& builder) {
5599 builder.DrawCircle(draw_rect.GetCenter(), draw_rect.GetWidth() * 0.5f,
5601 });
5602
5603 test_bounded("DrawRoundRect", [](DlCanvas& builder) {
5604 builder.DrawRoundRect(DlRoundRect::MakeRectXY(draw_rect, 5.0f, 5.0f),
5606 });
5607
5608 test_bounded("DrawDiffRoundRect", [](DlCanvas& builder) {
5609 builder.DrawDiffRoundRect(
5610 DlRoundRect::MakeRectXY(draw_rect, 5.0f, 5.0f),
5611 DlRoundRect::MakeRectXY(draw_rect.Expand(-10.0f, -10.0f), 5.0f, 5.0f),
5613 });
5614
5615 test_bounded("DrawArc", [](DlCanvas& builder) {
5616 builder.DrawArc(draw_rect, 45.0f, 355.0f,
false,
DlPaint());
5617 });
5618
5619 test_bounded("DrawPathEvenOdd", [](DlCanvas& builder) {
5621 DlPath::MakeRect(draw_rect).WithFillType(DlPathFillType::kOdd);
5622 builder.DrawPath(path,
DlPaint());
5623 });
5624
5625 test_bounded("DrawPathWinding", [](DlCanvas& builder) {
5627 DlPath::MakeRect(draw_rect).WithFillType(DlPathFillType::kNonZero);
5628 builder.DrawPath(path,
DlPaint());
5629 });
5630
5632 std::stringstream ss;
5633 ss <<
"DrawPoints(" <<
mode <<
")";
5634 test_bounded(ss.str(), [mode](DlCanvas& builder) {
5635 DlPoint points[4] = {
5636 DlPoint(draw_rect.GetLeft() + 1.0f, draw_rect.GetTop() + 1.0f),
5637 DlPoint(draw_rect.GetRight() - 1.0f, draw_rect.GetTop() + 1.0f),
5638 DlPoint(draw_rect.GetRight() - 1.0f, draw_rect.GetBottom() - 1.0f),
5639 DlPoint(draw_rect.GetLeft() + 1.0f, draw_rect.GetBottom() - 1.0f),
5640 };
5644
5645
5646
5648
5649 builder.DrawPoints(mode, 4,
points, paint);
5650 });
5651 };
5652
5653 test_draw_points(DlPointMode::kPoints);
5654 test_draw_points(DlPointMode::kLines);
5655 test_draw_points(DlPointMode::kPolygon);
5656
5657 test_bounded("DrawVerticesTriangles", [](DlCanvas& builder) {
5659 DlPoint(draw_rect.GetLeft(), draw_rect.GetTop()),
5660 DlPoint(draw_rect.GetRight(), draw_rect.GetTop()),
5661 DlPoint(draw_rect.GetRight(), draw_rect.GetBottom()),
5662 DlPoint(draw_rect.GetRight(), draw_rect.GetBottom()),
5663 DlPoint(draw_rect.GetLeft(), draw_rect.GetBottom()),
5664 DlPoint(draw_rect.GetLeft(), draw_rect.GetTop()),
5665 };
5666 DlVertices::Builder vertices(DlVertexMode::kTriangles, 6,
5667 DlVertices::Builder::kNone, 0);
5668 vertices.store_vertices(
points);
5669 builder.DrawVertices(vertices.build(), DlBlendMode::kSrcOver,
DlPaint());
5670 });
5671
5672 test_bounded("DrawVerticesTriangleStrip", [](DlCanvas& builder) {
5674 DlPoint(draw_rect.GetLeft(), draw_rect.GetTop()),
5675 DlPoint(draw_rect.GetRight(), draw_rect.GetTop()),
5676 DlPoint(draw_rect.GetRight(), draw_rect.GetBottom()),
5677 DlPoint(draw_rect.GetLeft(), draw_rect.GetBottom()),
5678 DlPoint(draw_rect.GetLeft(), draw_rect.GetTop()),
5679 DlPoint(draw_rect.GetRight(), draw_rect.GetTop()),
5680 };
5681 DlVertices::Builder vertices(DlVertexMode::kTriangleStrip, 6,
5682 DlVertices::Builder::kNone, 0);
5683 vertices.store_vertices(
points);
5684 builder.DrawVertices(vertices.build(), DlBlendMode::kSrcOver,
DlPaint());
5685 });
5686
5687 test_bounded("DrawVerticesTriangleFan", [](DlCanvas& builder) {
5689 draw_rect.GetCenter(),
5690 DlPoint(draw_rect.GetLeft(), draw_rect.GetTop()),
5691 DlPoint(draw_rect.GetRight(), draw_rect.GetTop()),
5692 DlPoint(draw_rect.GetRight(), draw_rect.GetBottom()),
5693 DlPoint(draw_rect.GetLeft(), draw_rect.GetBottom()),
5694 };
5695 DlVertices::Builder vertices(DlVertexMode::kTriangleFan, 5,
5696 DlVertices::Builder::kNone, 0);
5697 vertices.store_vertices(
points);
5698 builder.DrawVertices(vertices.build(), DlBlendMode::kSrcOver,
DlPaint());
5699 });
5700
5701 test_bounded("DrawImage", [](DlCanvas& builder) {
5703 builder.DrawImage(
image,
DlPoint(draw_rect.GetLeft(), draw_rect.GetTop()),
5704 DlImageSampling::kLinear);
5705 });
5706
5707 test_bounded("DrawImageRect", [](DlCanvas& builder) {
5709 builder.DrawImageRect(
image, draw_rect, DlImageSampling::kLinear);
5710 });
5711
5712 test_bounded("DrawImageNine", [](DlCanvas& builder) {
5715 builder.DrawImageNine(
image, center, draw_rect, DlFilterMode::kLinear);
5716 });
5717
5718 test_bounded("DrawTextBlob", [](DlCanvas& builder) {
5720
5721
5722 ASSERT_LT(blob->bounds().width(), draw_rect.GetWidth());
5723 ASSERT_LT(blob->bounds().height(), draw_rect.GetHeight());
5724
5725 auto text = DlTextSkia::Make(blob);
5726
5727 builder.DrawText(
text, draw_rect.GetLeft() - blob->bounds().left(),
5728 draw_rect.GetTop() - blob->bounds().top(),
DlPaint());
5729 builder.DrawText(
text, draw_rect.GetRight() - blob->bounds().right(),
5730 draw_rect.GetBottom() - blob->bounds().bottom(),
5732 });
5733
5734#if IMPELLER_SUPPORTS_RENDERING
5735 test_bounded("DrawTextFrame", [](DlCanvas& builder) {
5737
5738
5739 ASSERT_LT(blob->bounds().width(), draw_rect.GetWidth());
5740 ASSERT_LT(blob->bounds().height(), draw_rect.GetHeight());
5741
5742 auto text = DlTextImpeller::MakeFromBlob(blob);
5743
5744
5745 builder.DrawText(
text, draw_rect.GetLeft() - blob->bounds().left(),
5746 draw_rect.GetTop() - blob->bounds().top(),
DlPaint());
5747 builder.DrawText(
text, draw_rect.GetRight() - blob->bounds().right(),
5748 draw_rect.GetBottom() - blob->bounds().bottom(),
5750 });
5751#endif
5752
5753 test_bounded("DrawBoundedDisplayList", [](DlCanvas& builder) {
5754 DisplayListBuilder nested_builder(root_cull);
5755 nested_builder.DrawRect(draw_rect,
DlPaint());
5756 auto nested_display_list = nested_builder.Build();
5757
5758 EXPECT_EQ(nested_display_list->GetBounds(), draw_rect);
5759 ASSERT_FALSE(nested_display_list->root_is_unbounded());
5760
5761 builder.DrawDisplayList(nested_display_list);
5762 });
5763
5764 test_bounded("DrawShadow", [](DlCanvas& builder) {
5765 DlPath path = DlPath::MakeRect(draw_rect.Expand(-20, -20));
5768 auto shadow_bounds =
5769 DlCanvas::ComputeShadowBounds(path, elevation, dpr,
DlMatrix());
5770
5771
5772 ASSERT_LT(shadow_bounds.GetWidth(), draw_rect.GetWidth());
5773 ASSERT_LT(shadow_bounds.GetHeight(), draw_rect.GetHeight());
5774
5775
5777 path.WithOffset(draw_rect.GetLeftTop() - shadow_bounds.GetLeftTop());
5778 builder.DrawShadow(pathUL, DlColor::kMagenta(), elevation, true, dpr);
5779 DlPath pathLR =
path.WithOffset(draw_rect.GetRightBottom() -
5780 shadow_bounds.GetRightBottom());
5781 builder.DrawShadow(pathLR, DlColor::kMagenta(), elevation, true, dpr);
5782 });
5783
5784 for (
int i = 0; i <= static_cast<int>(DlBlendMode::kLastMode);
i++) {
5786 if (mode == DlBlendMode::kDst) {
5787
5788 continue;
5789 }
5790 std::stringstream ss;
5791 ss <<
"DrawRectWith" <<
mode;
5792 test_bounded(ss.str(), [mode](DlCanvas& builder) {
5793
5794 builder.DrawRect(draw_rect, DlPaint().setBlendMode(mode).setAlpha(0x7f));
5795 });
5796 }
5797}
5798
5799TEST_F(DisplayListTest, UnboundedRenderOpsAreReportedUnlessClipped) {
5800 static const DlRect root_cull = DlRect::MakeLTRB(100, 100, 200, 200);
5801 static const DlRect clip_rect = DlRect::MakeLTRB(120, 120, 180, 180);
5802 static const DlRect draw_rect = DlRect::MakeLTRB(110, 110, 190, 190);
5803
5804 using Renderer = const std::function<void(DlCanvas&)>;
5805 auto test_unbounded = [](const std::string& label,
5806 const Renderer& renderer,
5807 int extra_save_layers = 0) {
5808 {
5809 DisplayListBuilder builder(root_cull);
5810 renderer(builder);
5811 auto display_list = builder.Build();
5812
5813 EXPECT_EQ(display_list->GetBounds(), root_cull) << label;
5814 EXPECT_TRUE(display_list->root_is_unbounded()) << label;
5815 }
5816
5817 {
5818 DisplayListBuilder builder(root_cull);
5819 builder.ClipRect(clip_rect);
5820 renderer(builder);
5821 auto display_list = builder.Build();
5822
5823 EXPECT_EQ(display_list->GetBounds(), clip_rect) << label;
5824 EXPECT_FALSE(display_list->root_is_unbounded()) << label;
5825 }
5826
5827 {
5828 DisplayListBuilder builder(root_cull);
5829 builder.SaveLayer(std::nullopt, nullptr);
5830 renderer(builder);
5831 builder.Restore();
5832 auto display_list = builder.Build();
5833
5834 EXPECT_EQ(display_list->GetBounds(), root_cull) << label;
5835 EXPECT_FALSE(display_list->root_is_unbounded()) << label;
5836
5838 expector
5839 .addDetail(label)
5840 .addExpectation([](const SaveLayerOptions& options) {
5841 return options.content_is_unbounded();
5842 });
5843 for (
int i = 0;
i < extra_save_layers;
i++) {
5844 expector.addOpenExpectation();
5845 }
5846 display_list->Dispatch(expector);
5847 }
5848
5849 {
5850 DisplayListBuilder builder(root_cull);
5851 builder.SaveLayer(std::nullopt, nullptr);
5852 builder.ClipRect(clip_rect);
5853 renderer(builder);
5854 builder.Restore();
5855 auto display_list = builder.Build();
5856
5857 EXPECT_EQ(display_list->GetBounds(), clip_rect) << label;
5858 EXPECT_FALSE(display_list->root_is_unbounded()) << label;
5859
5861 expector
5862 .addDetail(label)
5863 .addExpectation([](const SaveLayerOptions& options) {
5864 return !options.content_is_unbounded();
5865 });
5866 for (
int i = 0;
i < extra_save_layers;
i++) {
5867 expector.addOpenExpectation();
5868 }
5869 display_list->Dispatch(expector);
5870 }
5871 };
5872
5873 test_unbounded("DrawPaint", [](DlCanvas& builder) {
5875 });
5876
5877 test_unbounded("DrawColor", [](DlCanvas& builder) {
5878 builder.DrawColor(DlColor::kMagenta(), DlBlendMode::kSrc);
5879 });
5880
5881 test_unbounded("Clear", [](DlCanvas& builder) {
5882 builder.Clear(DlColor::kMagenta());
5883 });
5884
5885 test_unbounded("DrawUnboundedDisplayList", [](DlCanvas& builder) {
5886 DisplayListBuilder nested_builder(root_cull);
5887 nested_builder.DrawPaint(
DlPaint());
5888 auto nested_display_list = nested_builder.Build();
5889
5890 EXPECT_EQ(nested_display_list->GetBounds(), root_cull);
5891 ASSERT_TRUE(nested_display_list->root_is_unbounded());
5892
5893 builder.DrawDisplayList(nested_display_list);
5894 });
5895
5896 test_unbounded("DrawRectWithUnboundedImageFilter", [](DlCanvas& builder) {
5897
5899 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
5900 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
5901 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
5902 0.0f, 0.0f, 0.0f, 0.0f, 1.0f,
5903 };
5904
5905 auto unbounded_cf = DlColorFilter::MakeMatrix(matrix);
5906
5907 ASSERT_TRUE(unbounded_cf->modifies_transparent_black());
5908 auto unbounded_if = DlImageFilter::MakeColorFilter(unbounded_cf);
5910
5911 ASSERT_EQ(unbounded_if->map_local_bounds(draw_rect, output_bounds),
5912 nullptr);
5913
5914 builder.DrawRect(draw_rect,
DlPaint().setImageFilter(unbounded_if));
5915 });
5916
5917 test_unbounded(
5918 "SaveLayerWithBackdropFilter",
5919 [](DlCanvas& builder) {
5920 auto filter = DlImageFilter::MakeBlur(3.0f, 3.0f, DlTileMode::kMirror);
5921 builder.SaveLayer(std::nullopt, nullptr, filter.get());
5922 builder.Restore();
5923 },
5924 1);
5925}
5926
5927TEST_F(DisplayListTest, BackdropFilterCulledAlongsideClipAndTransform) {
5928 DlRect frame_bounds = DlRect::MakeWH(100.0f, 100.0f);
5930
5931 DlRect clip_rect = DlRect::MakeLTRB(40.0f, 40.0f, 60.0f, 60.0f);
5932 DlRect draw_rect1 = DlRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
5933 DlRect draw_rect2 = DlRect::MakeLTRB(45.0f, 20.0f, 55.0f, 55.0f);
5934 DlRect cull_rect = DlRect::MakeLTRB(1.0f, 1.0f, 99.0f, 30.0f);
5935 auto bdf_filter = DlImageFilter::MakeBlur(5.0f, 5.0f, DlTileMode::kClamp);
5936
5937 ASSERT_TRUE(frame_bounds.Contains(clip_rect));
5938 ASSERT_TRUE(frame_bounds.Contains(draw_rect1));
5939 ASSERT_TRUE(frame_bounds.Contains(draw_rect2));
5940 ASSERT_TRUE(frame_bounds.Contains(cull_rect));
5941
5942 ASSERT_TRUE(frame_clip.Contains(clip_rect));
5943 ASSERT_TRUE(frame_clip.Contains(draw_rect1));
5944 ASSERT_TRUE(frame_clip.Contains(draw_rect2));
5945 ASSERT_TRUE(frame_clip.Contains(cull_rect));
5946
5947 ASSERT_FALSE(clip_rect.IntersectsWithRect(draw_rect1));
5948 ASSERT_TRUE(clip_rect.IntersectsWithRect(draw_rect2));
5949
5950 ASSERT_FALSE(cull_rect.IntersectsWithRect(clip_rect));
5951 ASSERT_TRUE(cull_rect.IntersectsWithRect(draw_rect1));
5952 ASSERT_TRUE(cull_rect.IntersectsWithRect(draw_rect2));
5953
5954 DisplayListBuilder builder(frame_bounds, true);
5955 builder.Save();
5956 {
5957 builder.Translate(0.1f, 0.1f);
5958 builder.ClipRect(frame_clip);
5959 builder.DrawRect(draw_rect1,
DlPaint());
5960
5961 builder.ClipRect(clip_rect);
5962 builder.Translate(0.1f, 0.1f);
5963 builder.SaveLayer(std::nullopt, nullptr, bdf_filter.get());
5964 {
5965 builder.DrawRect(clip_rect,
DlPaint());
5966 }
5967 builder.Restore();
5968
5969 }
5970 builder.Restore();
5971 builder.DrawRect(draw_rect2,
DlPaint());
5972 auto display_list = builder.Build();
5973
5974 {
5975 DisplayListBuilder unculled(frame_bounds);
5976 display_list->Dispatch(ToReceiver(unculled), frame_bounds);
5977 auto unculled_dl = unculled.Build();
5978
5980 }
5981
5982 {
5983 DisplayListBuilder culled(frame_bounds);
5984 display_list->Dispatch(ToReceiver(culled), cull_rect);
5985 auto culled_dl = culled.Build();
5986
5988
5989 DisplayListBuilder expected(frame_bounds);
5990 expected.Save();
5991 {
5992 expected.Translate(0.1f, 0.1f);
5993 expected.ClipRect(frame_clip);
5994 expected.DrawRect(draw_rect1,
DlPaint());
5995 }
5996 expected.Restore();
5997 expected.DrawRect(draw_rect2,
DlPaint());
5998 auto expected_dl = expected.Build();
5999
6001 }
6002}
6003
6004TEST_F(DisplayListTest, RecordManyLargeDisplayListOperations) {
6005 DisplayListBuilder builder;
6006
6007
6008
6009 std::vector<DlPoint>
points(2050);
6010 builder.DrawPoints(DlPointMode::kPoints,
points.size(),
points.data(),
6011 DlPaint{});
6012 builder.DrawPoints(DlPointMode::kPoints,
points.size(),
points.data(),
6013 DlPaint{});
6014 builder.DrawPoints(DlPointMode::kPoints,
points.size(),
points.data(),
6015 DlPaint{});
6016 builder.DrawPoints(DlPointMode::kPoints,
points.size(),
points.data(),
6017 DlPaint{});
6018 builder.DrawPoints(DlPointMode::kPoints,
points.size(),
points.data(),
6019 DlPaint{});
6020 builder.DrawPoints(DlPointMode::kPoints,
points.size(),
points.data(),
6021 DlPaint{});
6022
6023 EXPECT_TRUE(!!builder.Build());
6024}
6025
6026TEST_F(DisplayListTest, RecordSingleLargeDisplayListOperation) {
6027 DisplayListBuilder builder;
6028
6029 std::vector<DlPoint>
points(40000);
6030 builder.DrawPoints(DlPointMode::kPoints,
points.size(),
points.data(),
6031 DlPaint{});
6032
6033 EXPECT_TRUE(!!builder.Build());
6034}
6035
6036TEST_F(DisplayListTest, DisplayListDetectsRuntimeEffect) {
6037 auto color_source = DlColorSource::MakeRuntimeEffect(
6038 kTestRuntimeEffect1, {}, std::make_shared<std::vector<uint8_t>>());
6039 auto image_filter = DlImageFilter::MakeRuntimeEffect(
6040 kTestRuntimeEffect1, {}, std::make_shared<std::vector<uint8_t>>());
6041
6042 {
6043
6044 DisplayListBuilder builder;
6046
6047 builder.DrawRect(DlRect::MakeLTRB(0, 0, 50, 50), paint);
6048 EXPECT_TRUE(builder.Build()->can_apply_group_opacity());
6049 }
6050
6051 {
6052
6053 DisplayListBuilder builder;
6055
6057 builder.DrawRect(DlRect::MakeLTRB(0, 0, 50, 50), paint);
6058
6059 EXPECT_FALSE(builder.Build()->can_apply_group_opacity());
6060 }
6061
6062 {
6063
6064 DisplayListBuilder builder;
6066
6068 builder.DrawRect(DlRect::MakeLTRB(0, 0, 50, 50), paint);
6069
6070 EXPECT_FALSE(builder.Build()->can_apply_group_opacity());
6071 }
6072
6073 {
6074
6075
6076 DisplayListBuilder builder;
6078
6079 builder.SaveLayer(std::nullopt, nullptr);
6081 builder.DrawRect(DlRect::MakeLTRB(0, 0, 50, 50), paint);
6082 builder.Restore();
6083
6084 auto display_list = builder.Build();
6085 EXPECT_TRUE(display_list->can_apply_group_opacity());
6086
6088 expector.addExpectation([](const SaveLayerOptions& options) {
6089 return !options.can_distribute_opacity();
6090 });
6091 display_list->Dispatch(expector);
6092 }
6093
6094 {
6095
6096
6097 DisplayListBuilder builder;
6099
6100 builder.SaveLayer(std::nullopt, nullptr);
6102 builder.DrawRect(DlRect::MakeLTRB(0, 0, 50, 50), paint);
6103 builder.Restore();
6104
6105 auto display_list = builder.Build();
6106 EXPECT_TRUE(display_list->can_apply_group_opacity());
6107
6109 expector.addExpectation([](const SaveLayerOptions& options) {
6110 return !options.can_distribute_opacity();
6111 });
6112 display_list->Dispatch(expector);
6113 }
6114
6115 {
6116
6117
6118
6119 DisplayListBuilder builder;
6121
6122 builder.SaveLayer(std::nullopt, nullptr);
6123
6124 builder.SaveLayer(std::nullopt, nullptr);
6126 builder.DrawRect(DlRect::MakeLTRB(0, 0, 50, 50), paint);
6128 builder.Restore();
6129
6130 builder.SaveLayer(std::nullopt, nullptr);
6132
6133
6134 builder.DrawRect(DlRect::MakeLTRB(60, 60, 100, 100), paint);
6136 builder.Restore();
6137
6138 builder.Restore();
6139 auto display_list = builder.Build();
6140 EXPECT_TRUE(display_list->can_apply_group_opacity());
6141
6143 expector.addExpectation([](const SaveLayerOptions& options) {
6144
6145 return options.can_distribute_opacity();
6146 });
6147 expector.addExpectation([](const SaveLayerOptions& options) {
6148
6149 return !options.can_distribute_opacity();
6150 });
6151 expector.addExpectation([](const SaveLayerOptions& options) {
6152
6153 return !options.can_distribute_opacity();
6154 });
6155 display_list->Dispatch(expector);
6156 }
6157}
6158
6159namespace {
6160typedef void BuilderTransformer(DisplayListBuilder& builder);
6161
6162sk_sp<DisplayList> TestSaveLayerWithMatrix(BuilderTransformer
transform) {
6166
6167 DisplayListBuilder builder;
6168
6169 const auto blur_filter =
6170 DlImageFilter::MakeBlur(sigma, sigma, DlTileMode::kClamp);
6171
6172 builder.Translate(xoffset, yoffset);
6174
6176 builder.DrawImage(kTestImage1,
DlPoint(100.0, 100.0),
6177 DlImageSampling::kNearestNeighbor, &paint);
6178
6181 builder.SaveLayer(std::nullopt, &save_paint, blur_filter.get());
6182 builder.Restore();
6183
6184 return builder.Build();
6185}
6186}
6187
6188TEST_F(DisplayListTest, SaveLayerWithValidScaleDoesNotCrash) {
6189 EXPECT_NE(TestSaveLayerWithMatrix([](DisplayListBuilder& builder) {
6190 builder.Scale(0.7, 0.7);
6191 EXPECT_TRUE(builder.GetMatrix().IsInvertible());
6192 }),
6193 nullptr);
6194}
6195
6196TEST_F(DisplayListTest, SaveLayerWithZeroXScaleDoesNotCrash) {
6197 EXPECT_NE(TestSaveLayerWithMatrix([](DisplayListBuilder& builder) {
6198 builder.Scale(0.0, 0.7);
6199 EXPECT_FALSE(builder.GetMatrix().IsInvertible());
6200 }),
6201 nullptr);
6202}
6203
6204TEST_F(DisplayListTest, SaveLayerWithZeroYScaleDoesNotCrash) {
6205 EXPECT_NE(TestSaveLayerWithMatrix([](DisplayListBuilder& builder) {
6206 builder.Scale(0.7, 0.0);
6207 EXPECT_FALSE(builder.GetMatrix().IsInvertible());
6208 }),
6209 nullptr);
6210}
6211
6212TEST_F(DisplayListTest, SaveLayerWithLinearSkewDoesNotCrash) {
6213 EXPECT_NE(TestSaveLayerWithMatrix([](DisplayListBuilder& builder) {
6214 builder.Skew(1.0f, 1.0f);
6215 EXPECT_FALSE(builder.GetMatrix().IsInvertible());
6216 }),
6217 nullptr);
6218}
6219
6220}
6221}
TEST_F(FlutterDisplayLinkTest, ViewAddedToWindowFirst)
int main(int argc, char **argv)
DlPaint & setColor(DlColor color)
DlPaint & setStrokeCap(DlStrokeCap cap)
DlPaint & setStrokeWidth(float width)
DlPaint & setAlpha(uint8_t alpha)
DlPaint & setBlendMode(DlBlendMode mode)
DlPaint & setImageFilter(std::nullptr_t filter)
DlPaint & setDrawStyle(DlDrawStyle style)
DlPaint & setColorSource(std::nullptr_t source)
SaveLayerOptions with_bounds_from_caller() const
SaveLayerOptions with_content_is_clipped() const
#define CLIP_EXPECTOR(name)
#define SAVE_LAYER_EXPECTOR(name)
#define TEST_RTREE(rtree, query, expected_rects, expected_indices)
std::ostream & operator<<(std::ostream &out, const FlutterPoint &point)
FlutterVulkanImage * image
#define FML_LOG(severity)
bool DisplayListsNE_Verbose(const DisplayList *a, const DisplayList *b)
sk_sp< DlImage > MakeTestImage(int w, int h, int checker_size)
bool DisplayListsEQ_Verbose(const DisplayList *a, const DisplayList *b)
sk_sp< SkTextBlob > GetTestTextBlob(int index)
impeller::Scalar DlScalar
impeller::RoundingRadii DlRoundingRadii
constexpr bool DlScalarNearlyEqual(DlScalar x, DlScalar y, DlScalar tolerance=kEhCloseEnough)
impeller::RoundRect DlRoundRect
impeller::RSTransform DlRSTransform
impeller::Matrix DlMatrix
impeller::Degrees DlDegrees
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
impeller::IRect32 DlIRect
it will be possible to load the file into Perfetto s trace viewer use test Running tests that layout and measure text will not yield consistent results across various platforms Enabling this option will make font resolution default to the Ahem test font on all disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive mode
impeller::BlendMode DlBlendMode
int DisplayListBuilderTestingLastOpIndex(DisplayListBuilder &builder)
flutter::DlCanvas DlCanvas
flutter::SaveLayerOptions SaveLayerOptions
constexpr TRect< T > Expand(T left, T top, T right, T bottom) const
Returns a rectangle with expanded edges. Negative expansion results in shrinking.
std::vector< Point > points