Coverage Report

Created: 2026-07-25 06:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/fuzz/font_fuzzer.c
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
}