comparison mupdf-source/source/fitz/outline.c @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
comparison
equal deleted inserted replaced
1:1d09e1dec1d9 2:b50eed0cc0ef
1 // Copyright (C) 2004-2025 Artifex Software, Inc.
2 //
3 // This file is part of MuPDF.
4 //
5 // MuPDF is free software: you can redistribute it and/or modify it under the
6 // terms of the GNU Affero General Public License as published by the Free
7 // Software Foundation, either version 3 of the License, or (at your option)
8 // any later version.
9 //
10 // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY
11 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
13 // details.
14 //
15 // You should have received a copy of the GNU Affero General Public License
16 // along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>
17 //
18 // Alternative licensing terms are available from the licensor.
19 // For commercial licensing, see <https://www.artifex.com/> or contact
20 // Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
21 // CA 94129, USA, for further information.
22
23 #include "mupdf/fitz.h"
24
25 fz_outline_item *fz_outline_iterator_item(fz_context *ctx, fz_outline_iterator *iter)
26 {
27 if (iter->item == NULL)
28 return NULL;
29 return iter->item(ctx, iter);
30 }
31
32 int fz_outline_iterator_next(fz_context *ctx, fz_outline_iterator *iter)
33 {
34 if (iter->next == NULL)
35 return -1;
36 return iter->next(ctx, iter);
37 }
38
39 int fz_outline_iterator_prev(fz_context *ctx, fz_outline_iterator *iter)
40 {
41 if (iter->prev == NULL)
42 return -1;
43 return iter->prev(ctx, iter);
44 }
45
46 int fz_outline_iterator_up(fz_context *ctx, fz_outline_iterator *iter)
47 {
48 if (iter->up == NULL)
49 return -1;
50 return iter->up(ctx, iter);
51 }
52
53 int fz_outline_iterator_down(fz_context *ctx, fz_outline_iterator *iter)
54 {
55 if (iter->down == NULL)
56 return -1;
57 return iter->down(ctx, iter);
58 }
59
60 int fz_outline_iterator_insert(fz_context *ctx, fz_outline_iterator *iter, fz_outline_item *item)
61 {
62 if (iter->insert == NULL)
63 fz_throw(ctx, FZ_ERROR_ARGUMENT, "Document type does not support Outline editing");
64 return iter->insert(ctx, iter, item);
65 }
66
67 int fz_outline_iterator_delete(fz_context *ctx, fz_outline_iterator *iter)
68 {
69 if (iter->del == NULL)
70 fz_throw(ctx, FZ_ERROR_ARGUMENT, "Document type does not support Outline editing");
71 return iter->del(ctx, iter);
72 }
73
74 void fz_outline_iterator_update(fz_context *ctx, fz_outline_iterator *iter, fz_outline_item *item)
75 {
76 if (iter->update == NULL)
77 fz_throw(ctx, FZ_ERROR_ARGUMENT, "Document type does not support Outline editing");
78 iter->update(ctx, iter, item);
79 }
80
81 void fz_drop_outline_iterator(fz_context *ctx, fz_outline_iterator *iter)
82 {
83 if (iter == NULL)
84 return;
85 iter->drop(ctx, iter);
86 fz_drop_document(ctx, iter->doc);
87 fz_free(ctx, iter);
88 }
89
90 static void
91 load_outline_sub(fz_context *ctx, fz_outline_iterator *iter, fz_outline **tail, char **t, char **u)
92 {
93 fz_outline_item *item;
94 fz_outline *node, *onode;
95 int res;
96
97 do {
98 item = fz_outline_iterator_item(ctx, iter);
99 if (item == NULL)
100 return;
101 /* Duplicate title and uri first so we can recurse with limited try/catch. */
102 *t = item->title == NULL ? NULL : fz_strdup(ctx, item->title);
103 *u = item->uri == NULL ? NULL : fz_strdup(ctx, item->uri);
104 node = fz_malloc_struct(ctx, fz_outline);
105 node->is_open = item->is_open;
106 node->refs = 1;
107 node->title = *t;
108 node->uri = *u;
109 node->page.chapter = -1;
110 node->page.page = -1;
111 *t = NULL;
112 *u = NULL;
113 *tail = node;
114 tail = &node->next;
115 onode = node;
116 node = NULL;
117
118 onode->page = fz_resolve_link(ctx, iter->doc, onode->uri, &onode->x, &onode->y);
119
120 res = fz_outline_iterator_down(ctx, iter);
121 if (res == 0)
122 load_outline_sub(ctx, iter, &onode->down, t, u);
123 if (res >= 0)
124 fz_outline_iterator_up(ctx, iter);
125 }
126 while (fz_outline_iterator_next(ctx, iter) == 0);
127 }
128
129 fz_outline *
130 fz_load_outline_from_iterator(fz_context *ctx, fz_outline_iterator *iter)
131 {
132 fz_outline *head = NULL;
133 fz_outline **tail = &head;
134 char *title = NULL;
135 char *uri = NULL;
136
137 if (iter == NULL)
138 return NULL;
139
140 fz_try(ctx)
141 load_outline_sub(ctx, iter, tail, &title, &uri);
142 fz_always(ctx)
143 fz_drop_outline_iterator(ctx, iter);
144 fz_catch(ctx)
145 {
146 fz_drop_outline(ctx, head);
147 fz_free(ctx, title);
148 fz_free(ctx, uri);
149 fz_rethrow(ctx);
150 }
151
152 return head;
153 }
154
155 fz_outline_iterator *fz_new_outline_iterator_of_size(fz_context *ctx, size_t size, fz_document *doc)
156 {
157 fz_outline_iterator *iter = fz_calloc(ctx, size, 1);
158
159 iter->doc = fz_keep_document(ctx, doc);
160
161 return iter;
162 }
163
164 fz_outline *
165 fz_new_outline(fz_context *ctx)
166 {
167 fz_outline *outline = fz_malloc_struct(ctx, fz_outline);
168 outline->refs = 1;
169 return outline;
170 }
171
172 fz_outline *
173 fz_keep_outline(fz_context *ctx, fz_outline *outline)
174 {
175 return fz_keep_imp(ctx, outline, &outline->refs);
176 }
177
178 void
179 fz_drop_outline(fz_context *ctx, fz_outline *outline)
180 {
181 while (fz_drop_imp(ctx, outline, &outline->refs))
182 {
183 fz_outline *next = outline->next;
184 fz_drop_outline(ctx, outline->down);
185 fz_free(ctx, outline->title);
186 fz_free(ctx, outline->uri);
187 fz_free(ctx, outline);
188 outline = next;
189 }
190 }
191
192 typedef struct {
193 fz_outline_iterator super;
194 fz_outline *outline;
195 fz_outline *current;
196 fz_outline_item item;
197 int down_max;
198 int down_len;
199 fz_outline **down_array;
200 } fz_outline_iter_std;
201
202 static int
203 iter_std_down(fz_context *ctx, fz_outline_iterator *iter_)
204 {
205 fz_outline_iter_std *iter = (fz_outline_iter_std *)iter_;
206
207 if (iter->current == NULL)
208 return -1;
209 if (iter->current->down == NULL)
210 return -1;
211
212 if (iter->down_max == iter->down_len)
213 {
214 int new_max = iter->down_max ? iter->down_max * 2 : 32;
215 iter->down_array = fz_realloc_array(ctx, iter->down_array, new_max, fz_outline *);
216 iter->down_max = new_max;
217 }
218 iter->down_array[iter->down_len++] = iter->current;
219
220 iter->current = iter->current->down;
221 return 0;
222 }
223
224 static int
225 iter_std_up(fz_context *ctx, fz_outline_iterator *iter_)
226 {
227 fz_outline_iter_std *iter = (fz_outline_iter_std *)iter_;
228
229 if (iter->current == NULL)
230 return -1;
231 if (iter->down_len == 0)
232 return -1;
233
234 iter->current = iter->down_array[--iter->down_len];
235
236 return 0;
237 }
238
239 static int
240 iter_std_next(fz_context *ctx, fz_outline_iterator *iter_)
241 {
242 fz_outline_iter_std *iter = (fz_outline_iter_std *)iter_;
243
244 if (iter->current == NULL)
245 return -1;
246 if (iter->current->next == NULL)
247 return -1;
248
249 iter->current = iter->current->next;
250
251 return 0;
252 }
253
254 static int
255 iter_std_prev(fz_context *ctx, fz_outline_iterator *iter_)
256 {
257 fz_outline_iter_std *iter = (fz_outline_iter_std *)iter_;
258 fz_outline *first;
259
260 if (iter->current == NULL)
261 return -1;
262 first = iter->down_len == 0 ? iter->outline : iter->down_array[iter->down_len-1];
263 if (iter->current == first)
264 return -1;
265
266 while (first->next != iter->current)
267 first = first->next;
268
269 iter->current = first;
270
271 return 0;
272 }
273
274 static fz_outline_item *
275 iter_std_item(fz_context *ctx, fz_outline_iterator *iter_)
276 {
277 fz_outline_iter_std *iter = (fz_outline_iter_std *)iter_;
278
279 if (iter->current == NULL)
280 return NULL;
281
282 iter->item.is_open = iter->current->is_open;
283 iter->item.title = iter->current->title;
284 iter->item.uri = iter->current->uri;
285 iter->item.r = iter->current->r / 255.0f;
286 iter->item.g = iter->current->g / 255.0f;
287 iter->item.b = iter->current->b / 255.0f;
288 iter->item.flags = iter->current->flags;
289
290 return &iter->item;
291 }
292
293 static void
294 iter_std_drop(fz_context *ctx, fz_outline_iterator *iter_)
295 {
296 fz_outline_iter_std *iter = (fz_outline_iter_std *)iter_;
297
298 if (iter == NULL)
299 return;
300
301 fz_drop_outline(ctx, iter->outline);
302 fz_free(ctx, iter->down_array);
303 }
304
305 fz_outline_iterator *fz_outline_iterator_from_outline(fz_context *ctx, fz_outline *outline)
306 {
307 fz_outline_iter_std *iter;
308
309 fz_try(ctx)
310 {
311 iter = fz_malloc_struct(ctx, fz_outline_iter_std);
312 iter->super.down = iter_std_down;
313 iter->super.up = iter_std_up;
314 iter->super.next = iter_std_next;
315 iter->super.prev = iter_std_prev;
316 iter->super.item = iter_std_item;
317 iter->super.drop = iter_std_drop;
318 iter->outline = outline;
319 iter->current = outline;
320 }
321 fz_catch(ctx)
322 {
323 fz_drop_outline(ctx, outline);
324 fz_rethrow(ctx);
325 }
326
327 return &iter->super;
328 }