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