diff 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
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mupdf-source/source/fitz/outline.c	Mon Sep 15 11:43:07 2025 +0200
@@ -0,0 +1,328 @@
+// Copyright (C) 2004-2025 Artifex Software, Inc.
+//
+// This file is part of MuPDF.
+//
+// MuPDF is free software: you can redistribute it and/or modify it under the
+// terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option)
+// any later version.
+//
+// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>
+//
+// Alternative licensing terms are available from the licensor.
+// For commercial licensing, see <https://www.artifex.com/> or contact
+// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
+// CA 94129, USA, for further information.
+
+#include "mupdf/fitz.h"
+
+fz_outline_item *fz_outline_iterator_item(fz_context *ctx, fz_outline_iterator *iter)
+{
+	if (iter->item == NULL)
+		return NULL;
+	return iter->item(ctx, iter);
+}
+
+int fz_outline_iterator_next(fz_context *ctx, fz_outline_iterator *iter)
+{
+	if (iter->next == NULL)
+		return -1;
+	return iter->next(ctx, iter);
+}
+
+int fz_outline_iterator_prev(fz_context *ctx, fz_outline_iterator *iter)
+{
+	if (iter->prev == NULL)
+		return -1;
+	return iter->prev(ctx, iter);
+}
+
+int fz_outline_iterator_up(fz_context *ctx, fz_outline_iterator *iter)
+{
+	if (iter->up == NULL)
+		return -1;
+	return iter->up(ctx, iter);
+}
+
+int fz_outline_iterator_down(fz_context *ctx, fz_outline_iterator *iter)
+{
+	if (iter->down == NULL)
+		return -1;
+	return iter->down(ctx, iter);
+}
+
+int fz_outline_iterator_insert(fz_context *ctx, fz_outline_iterator *iter, fz_outline_item *item)
+{
+	if (iter->insert == NULL)
+		fz_throw(ctx, FZ_ERROR_ARGUMENT, "Document type does not support Outline editing");
+	return iter->insert(ctx, iter, item);
+}
+
+int fz_outline_iterator_delete(fz_context *ctx, fz_outline_iterator *iter)
+{
+	if (iter->del == NULL)
+		fz_throw(ctx, FZ_ERROR_ARGUMENT, "Document type does not support Outline editing");
+	return iter->del(ctx, iter);
+}
+
+void fz_outline_iterator_update(fz_context *ctx, fz_outline_iterator *iter, fz_outline_item *item)
+{
+	if (iter->update == NULL)
+		fz_throw(ctx, FZ_ERROR_ARGUMENT, "Document type does not support Outline editing");
+	iter->update(ctx, iter, item);
+}
+
+void fz_drop_outline_iterator(fz_context *ctx, fz_outline_iterator *iter)
+{
+	if (iter == NULL)
+		return;
+	iter->drop(ctx, iter);
+	fz_drop_document(ctx, iter->doc);
+	fz_free(ctx, iter);
+}
+
+static void
+load_outline_sub(fz_context *ctx, fz_outline_iterator *iter, fz_outline **tail, char **t, char **u)
+{
+	fz_outline_item *item;
+	fz_outline *node, *onode;
+	int res;
+
+	do {
+		item = fz_outline_iterator_item(ctx, iter);
+		if (item == NULL)
+			return;
+		/* Duplicate title and uri first so we can recurse with limited try/catch. */
+		*t = item->title == NULL ? NULL : fz_strdup(ctx, item->title);
+		*u = item->uri == NULL ? NULL : fz_strdup(ctx, item->uri);
+		node = fz_malloc_struct(ctx, fz_outline);
+		node->is_open = item->is_open;
+		node->refs = 1;
+		node->title = *t;
+		node->uri = *u;
+		node->page.chapter = -1;
+		node->page.page = -1;
+		*t = NULL;
+		*u = NULL;
+		*tail = node;
+		tail = &node->next;
+		onode = node;
+		node = NULL;
+
+		onode->page = fz_resolve_link(ctx, iter->doc, onode->uri, &onode->x, &onode->y);
+
+		res = fz_outline_iterator_down(ctx, iter);
+		if (res == 0)
+			load_outline_sub(ctx, iter, &onode->down, t, u);
+		if (res >= 0)
+			fz_outline_iterator_up(ctx, iter);
+	}
+	while (fz_outline_iterator_next(ctx, iter) == 0);
+}
+
+fz_outline *
+fz_load_outline_from_iterator(fz_context *ctx, fz_outline_iterator *iter)
+{
+	fz_outline *head = NULL;
+	fz_outline **tail = &head;
+	char *title = NULL;
+	char *uri = NULL;
+
+	if (iter == NULL)
+		return NULL;
+
+	fz_try(ctx)
+		load_outline_sub(ctx, iter, tail, &title, &uri);
+	fz_always(ctx)
+		fz_drop_outline_iterator(ctx, iter);
+	fz_catch(ctx)
+	{
+		fz_drop_outline(ctx, head);
+		fz_free(ctx, title);
+		fz_free(ctx, uri);
+		fz_rethrow(ctx);
+	}
+
+	return head;
+}
+
+fz_outline_iterator *fz_new_outline_iterator_of_size(fz_context *ctx, size_t size, fz_document *doc)
+{
+	fz_outline_iterator *iter = fz_calloc(ctx, size, 1);
+
+	iter->doc = fz_keep_document(ctx, doc);
+
+	return iter;
+}
+
+fz_outline *
+fz_new_outline(fz_context *ctx)
+{
+	fz_outline *outline = fz_malloc_struct(ctx, fz_outline);
+	outline->refs = 1;
+	return outline;
+}
+
+fz_outline *
+fz_keep_outline(fz_context *ctx, fz_outline *outline)
+{
+	return fz_keep_imp(ctx, outline, &outline->refs);
+}
+
+void
+fz_drop_outline(fz_context *ctx, fz_outline *outline)
+{
+	while (fz_drop_imp(ctx, outline, &outline->refs))
+	{
+		fz_outline *next = outline->next;
+		fz_drop_outline(ctx, outline->down);
+		fz_free(ctx, outline->title);
+		fz_free(ctx, outline->uri);
+		fz_free(ctx, outline);
+		outline = next;
+	}
+}
+
+typedef struct {
+	fz_outline_iterator super;
+	fz_outline *outline;
+	fz_outline *current;
+	fz_outline_item item;
+	int down_max;
+	int down_len;
+	fz_outline **down_array;
+} fz_outline_iter_std;
+
+static int
+iter_std_down(fz_context *ctx, fz_outline_iterator *iter_)
+{
+	fz_outline_iter_std *iter = (fz_outline_iter_std *)iter_;
+
+	if (iter->current == NULL)
+		return -1;
+	if (iter->current->down == NULL)
+		return -1;
+
+	if (iter->down_max == iter->down_len)
+	{
+		int new_max = iter->down_max ? iter->down_max * 2 : 32;
+		iter->down_array = fz_realloc_array(ctx, iter->down_array, new_max, fz_outline *);
+		iter->down_max = new_max;
+	}
+	iter->down_array[iter->down_len++] = iter->current;
+
+	iter->current = iter->current->down;
+	return 0;
+}
+
+static int
+iter_std_up(fz_context *ctx, fz_outline_iterator *iter_)
+{
+	fz_outline_iter_std *iter = (fz_outline_iter_std *)iter_;
+
+	if (iter->current == NULL)
+		return -1;
+	if (iter->down_len == 0)
+		return -1;
+
+	iter->current = iter->down_array[--iter->down_len];
+
+	return 0;
+}
+
+static int
+iter_std_next(fz_context *ctx, fz_outline_iterator *iter_)
+{
+	fz_outline_iter_std *iter = (fz_outline_iter_std *)iter_;
+
+	if (iter->current == NULL)
+		return -1;
+	if (iter->current->next == NULL)
+		return -1;
+
+	iter->current = iter->current->next;
+
+	return 0;
+}
+
+static int
+iter_std_prev(fz_context *ctx, fz_outline_iterator *iter_)
+{
+	fz_outline_iter_std *iter = (fz_outline_iter_std *)iter_;
+	fz_outline *first;
+
+	if (iter->current == NULL)
+		return -1;
+	first = iter->down_len == 0 ? iter->outline : iter->down_array[iter->down_len-1];
+	if (iter->current == first)
+		return -1;
+
+	while (first->next != iter->current)
+		first = first->next;
+
+	iter->current = first;
+
+	return 0;
+}
+
+static fz_outline_item *
+iter_std_item(fz_context *ctx, fz_outline_iterator *iter_)
+{
+	fz_outline_iter_std *iter = (fz_outline_iter_std *)iter_;
+
+	if (iter->current == NULL)
+		return NULL;
+
+	iter->item.is_open = iter->current->is_open;
+	iter->item.title = iter->current->title;
+	iter->item.uri = iter->current->uri;
+	iter->item.r = iter->current->r / 255.0f;
+	iter->item.g = iter->current->g / 255.0f;
+	iter->item.b = iter->current->b / 255.0f;
+	iter->item.flags = iter->current->flags;
+
+	return &iter->item;
+}
+
+static void
+iter_std_drop(fz_context *ctx, fz_outline_iterator *iter_)
+{
+	fz_outline_iter_std *iter = (fz_outline_iter_std *)iter_;
+
+	if (iter == NULL)
+		return;
+
+	fz_drop_outline(ctx, iter->outline);
+	fz_free(ctx, iter->down_array);
+}
+
+fz_outline_iterator *fz_outline_iterator_from_outline(fz_context *ctx, fz_outline *outline)
+{
+	fz_outline_iter_std *iter;
+
+	fz_try(ctx)
+	{
+		iter = fz_malloc_struct(ctx, fz_outline_iter_std);
+		iter->super.down = iter_std_down;
+		iter->super.up = iter_std_up;
+		iter->super.next = iter_std_next;
+		iter->super.prev = iter_std_prev;
+		iter->super.item = iter_std_item;
+		iter->super.drop = iter_std_drop;
+		iter->outline = outline;
+		iter->current = outline;
+	}
+	fz_catch(ctx)
+	{
+		fz_drop_outline(ctx, outline);
+		fz_rethrow(ctx);
+	}
+
+	return &iter->super;
+}