Line | Count | Source |
1 | | // Copyright 2026 Google LLC |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // http://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | |
15 | | #include <cairo.h> |
16 | | #include <cairo-pdf.h> |
17 | | #include <cairo-ps.h> |
18 | | #include <cairo-ft.h> |
19 | | #include <ft2build.h> |
20 | | #include FT_FREETYPE_H |
21 | | #include <stdint.h> |
22 | | #include <stdlib.h> |
23 | | #include <string.h> |
24 | | |
25 | | static cairo_status_t |
26 | | _write_func (void *closure, const uint8_t *data, unsigned int length) |
27 | 186k | { |
28 | 186k | return CAIRO_STATUS_SUCCESS; |
29 | 186k | } |
30 | | |
31 | 129 | int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { |
32 | 129 | if (size < 100) return 0; |
33 | | |
34 | 129 | FT_Library library; |
35 | 129 | if (FT_Init_FreeType(&library)) return 0; |
36 | | |
37 | 129 | FT_Face face; |
38 | 129 | if (FT_New_Memory_Face(library, data, size, 0, &face)) { |
39 | 81 | FT_Done_FreeType(library); |
40 | 81 | return 0; |
41 | 81 | } |
42 | | |
43 | 48 | cairo_font_face_t *font_face = cairo_ft_font_face_create_for_ft_face(face, 0); |
44 | 48 | if (cairo_font_face_status(font_face) != CAIRO_STATUS_SUCCESS) { |
45 | 0 | cairo_font_face_destroy(font_face); |
46 | 0 | FT_Done_Face(face); |
47 | 0 | FT_Done_FreeType(library); |
48 | 0 | return 0; |
49 | 0 | } |
50 | | |
51 | | // 1. Fuzz PDF font subsetting |
52 | 48 | cairo_surface_t *pdf_surface = cairo_pdf_surface_create_for_stream(_write_func, NULL, 100, 100); |
53 | 48 | cairo_t *cr_pdf = cairo_create(pdf_surface); |
54 | 48 | cairo_set_font_face(cr_pdf, font_face); |
55 | 48 | cairo_set_font_size(cr_pdf, 12); |
56 | 48 | cairo_move_to(cr_pdf, 10, 50); |
57 | 48 | cairo_show_text(cr_pdf, "Fuzzing PDF font subsetting"); |
58 | 48 | cairo_show_page(cr_pdf); |
59 | 48 | cairo_destroy(cr_pdf); |
60 | 48 | cairo_surface_finish(pdf_surface); |
61 | 48 | cairo_surface_destroy(pdf_surface); |
62 | | |
63 | | // 2. Fuzz PS font subsetting |
64 | 48 | cairo_surface_t *ps_surface = cairo_ps_surface_create_for_stream(_write_func, NULL, 100, 100); |
65 | 48 | cairo_t *cr_ps = cairo_create(ps_surface); |
66 | 48 | cairo_set_font_face(cr_ps, font_face); |
67 | 48 | cairo_set_font_size(cr_ps, 12); |
68 | 48 | cairo_move_to(cr_ps, 10, 50); |
69 | 48 | cairo_show_text(cr_ps, "Fuzzing PS font subsetting"); |
70 | 48 | cairo_show_page(cr_ps); |
71 | 48 | cairo_destroy(cr_ps); |
72 | 48 | cairo_surface_finish(ps_surface); |
73 | 48 | cairo_surface_destroy(ps_surface); |
74 | | |
75 | | // 3. Fuzz COLR glyph rendering on image surface |
76 | 48 | cairo_surface_t *image_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 100, 100); |
77 | 48 | cairo_t *cr_img = cairo_create(image_surface); |
78 | | |
79 | 48 | cairo_font_options_t *font_options = cairo_font_options_create(); |
80 | 48 | cairo_font_options_set_color_mode(font_options, CAIRO_COLOR_MODE_COLOR); |
81 | 48 | cairo_set_font_options(cr_img, font_options); |
82 | 48 | cairo_font_options_destroy(font_options); |
83 | | |
84 | 48 | cairo_set_font_face(cr_img, font_face); |
85 | 48 | cairo_set_font_size(cr_img, 50); |
86 | | |
87 | | // Try some glyph indices from the input |
88 | 48 | cairo_glyph_t glyphs[8]; |
89 | 48 | int num_glyphs = 0; |
90 | 48 | size_t glyph_data_offset = size > 200 ? 100 : 0; // Use some data for glyph indices if enough |
91 | 48 | if (size >= glyph_data_offset + 8 * sizeof(uint32_t)) { |
92 | 48 | const uint32_t *u32 = (const uint32_t *)(data + glyph_data_offset); |
93 | 432 | for (int i = 0; i < 8; i++) { |
94 | 384 | glyphs[i].index = u32[i] % 65536; |
95 | 384 | glyphs[i].x = (i % 4) * 25; |
96 | 384 | glyphs[i].y = (i / 4) * 50 + 25; |
97 | 384 | num_glyphs++; |
98 | 384 | } |
99 | 48 | cairo_show_glyphs(cr_img, glyphs, num_glyphs); |
100 | 48 | } else { |
101 | 0 | cairo_move_to(cr_img, 10, 50); |
102 | 0 | cairo_show_text(cr_img, "ABC"); |
103 | 0 | } |
104 | | |
105 | 48 | cairo_destroy(cr_img); |
106 | 48 | cairo_surface_destroy(image_surface); |
107 | | |
108 | 48 | cairo_font_face_destroy(font_face); |
109 | 48 | FT_Done_Face(face); |
110 | 48 | FT_Done_FreeType(library); |
111 | | |
112 | 48 | return 0; |
113 | 48 | } |