File: paint_vector_icon_fuzztest.cc

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (132 lines) | stat: -rw-r--r-- 4,579 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <vector>

#include "base/command_line.h"
#include "skia/ext/switches.h"
#include "third_party/fuzztest/src/fuzztest/fuzztest.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/gfx/vector_icon_types.h"
#include "ui/gfx/vector_icon_utils.h"

namespace {

using fuzztest::Arbitrary;
using fuzztest::Domain;
using fuzztest::ElementOf;
using fuzztest::Finite;
using fuzztest::FlatMap;
using fuzztest::InRange;
using fuzztest::Just;
using fuzztest::Map;
using fuzztest::NonEmpty;
using fuzztest::StructOf;
using fuzztest::VariantOf;
using fuzztest::VectorOf;

// Fuzztest does not yet support enums out of the box, but thankfully the
// `gfx::CommandType` enum is defined through a pair of macros that work very
// well for us. `DECLARE_VECTOR_COMMAND(x)` is supposed to be overridden like
// this before `DECLARE_VECTOR_COMMANDS` can be used. Dependency injection!
#define DECLARE_VECTOR_COMMAND(x) gfx::CommandType::x,

// That allows us to define a domain that contains only valid vector commands.
auto AnyCommandType() {
  return ElementOf({DECLARE_VECTOR_COMMANDS});
}

// Each command type has a specific number of args it expects, otherwise the
// command validation code CHECK-fails. We thus make sure to generate only
// valid sequences of `gfx::PathElement`s by packaging commands with the right
// number of arguments.
struct Command {
  gfx::CommandType type;
  std::vector<SkScalar> args;
};

// Returns the domain of all possible arguments for the given command.
//
// We need this to account for the fact that not all arguments are valid for
// all commands, and passing invalid arguments can trigger shallow CHECK
// failures that prevent deeper fuzzing.
Domain<std::vector<SkScalar>> AnyArgsForCommandType(gfx::CommandType type) {
  int args_count = gfx::GetCommandArgumentCount(type);
  switch (type) {
    case gfx::PATH_COLOR_ARGB:
      return VectorOf(InRange(SkScalar(0.0), SkScalar(255.0)))
          .WithSize(args_count);
    case gfx::CANVAS_DIMENSIONS:
      return VectorOf(InRange(SkScalar(1.0), SkScalar(1024.0)))
          .WithSize(args_count);
    default:
      return VectorOf(Finite<SkScalar>()).WithSize(args_count);
  }
}

Domain<Command> AnyCommandWithType(gfx::CommandType type) {
  return StructOf<Command>(Just(type), AnyArgsForCommandType(type));
}

// Returns the domain of all possible commands.
auto AnyCommand() {
  return FlatMap(AnyCommandWithType, AnyCommandType());
}

// Flattens the given `commands` into a sequence of path elements that can be
// passed to `PaintVectorIcon()`.
std::vector<gfx::PathElement> ConvertCommands(
    const std::vector<Command>& commands) {
  std::vector<gfx::PathElement> path;
  for (const auto& command : commands) {
    path.emplace_back(command.type);
    for (SkScalar arg : command.args) {
      path.emplace_back(arg);
    }
  }
  return path;
}

class PaintVectorIconFuzzTest {
 public:
  PaintVectorIconFuzzTest() {
    // `Init()` ignores its arguments on Windows, so init with nothing and add
    // switches later.
    CHECK(base::CommandLine::Init(0, nullptr));

    // Set command-line arguments correctly to avoid check failures down the
    // line.
    base::CommandLine& command_line = *base::CommandLine::ForCurrentProcess();
    command_line.AppendSwitchASCII(switches::kTextContrast, "1.0");
    command_line.AppendSwitchASCII(switches::kTextGamma, "1.0");
  }

  void PaintVectorIcon(std::vector<Command> commands) {
    std::vector<gfx::PathElement> path = ConvertCommands(commands);

    // An icon can contain multiple representations. We do not fuzz the code
    // that chooses which representation to draw based on canvas size and scale,
    // and instead use a single representation.
    gfx::VectorIconRep rep{path};
    gfx::VectorIcon icon(&rep, /*reps_size=*/1u, "icon");

    constexpr float kImageScale = 1.f;
    constexpr bool kIsOpaque = true;
    gfx::Canvas canvas(gfx::Size(1024, 1024), kImageScale, kIsOpaque);

    // The length of a single edge of the square icon, in device-independent
    // pixels.
    constexpr int kDipSize = 1024;
    constexpr SkColor kBlack = SkColorSetARGB(255, 0, 0, 0);
    gfx::PaintVectorIcon(&canvas, icon, kDipSize, kBlack);
  }
};

FUZZ_TEST_F(PaintVectorIconFuzzTest, PaintVectorIcon)
    .WithDomains(NonEmpty(VectorOf(AnyCommand())));

}  // namespace