Пример #1
0
static pdf_font_desc *
load_font_or_hail_mary(fz_context *ctx, pdf_document *doc, pdf_obj *rdb, pdf_obj *font, int depth, fz_cookie *cookie)
{
	pdf_font_desc *desc;

	fz_try(ctx)
	{
		desc = pdf_load_font(ctx, doc, rdb, font, depth);
	}
	fz_catch(ctx)
	{
		if (fz_caught(ctx) == FZ_ERROR_TRYLATER && cookie && cookie->incomplete_ok)
		{
			desc = NULL;
			cookie->incomplete++;
		}
		else
		{
			fz_rethrow(ctx);
		}
	}
	if (desc == NULL)
		desc = pdf_load_hail_mary_font(ctx, doc);
	return desc;
}
Пример #2
0
void
fz_clip_text(fz_device *dev, fz_text *text, fz_matrix ctm, int accumulate)
{
	fz_context *ctx = dev->ctx;

	if (dev->error_depth)
	{
		if (accumulate == 0 || accumulate == 1)
			dev->error_depth++;
		return;
	}

	fz_try(ctx)
	{
		if (dev->clip_text)
			dev->clip_text(dev, text, ctm, accumulate);
	}
	fz_catch(ctx)
	{
		if (accumulate == 2)
			fz_rethrow(ctx);
		dev->error_depth = 1;
		strcpy(dev->errmess, fz_caught(ctx));
		/* Error swallowed */
	}
}
Пример #3
0
void pdfapp_open_progressive(pdfapp_t *app, char *filename, int reload, int bps)
{
	fz_context *ctx = app->ctx;
	char *password = "";

	fz_try(ctx)
	{
		fz_register_document_handlers(ctx);

#ifdef HAVE_CURL
		if (!strncmp(filename, "http://", 7))
		{
			app->stream = fz_stream_from_curl(ctx, filename, pdfapp_more_data, app);
			while (1)
			{
				fz_try(ctx)
				{
					fz_seek(ctx, app->stream, 0, SEEK_SET);
					app->doc = fz_open_document_with_stream(ctx, filename, app->stream);
				}
				fz_catch(ctx)
				{
					if (fz_caught(ctx) == FZ_ERROR_TRYLATER)
					{
						pdfapp_warn(app, "not enough data to open yet");
						continue;
					}
					fz_rethrow(ctx);
				}
				break;
			}
		}
		else
#endif
		if (bps == 0)
Пример #4
0
fz_buffer *
fz_read_best(fz_stream *stm, int initial, int *truncated)
{
	fz_buffer *buf = NULL;
	int n;
	fz_context *ctx = stm->ctx;

	fz_var(buf);

	if (truncated)
		*truncated = 0;

	fz_try(ctx)
	{
		if (initial < 1024)
			initial = 1024;

		buf = fz_new_buffer(ctx, initial+1);

		while (1)
		{
			if (buf->len == buf->cap)
				fz_grow_buffer(ctx, buf);

			if (buf->len >= MIN_BOMB && buf->len / 200 > initial)
			{
				fz_throw(ctx, FZ_ERROR_GENERIC, "compression bomb detected");
			}

			n = fz_read(stm, buf->data + buf->len, buf->cap - buf->len);
			if (n == 0)
				break;

			buf->len += n;
		}
	}
	fz_catch(ctx)
	{
		if (fz_caught(ctx) == FZ_ERROR_TRYLATER)
		{
			fz_drop_buffer(ctx, buf);
			fz_rethrow(ctx);
		}
		if (truncated)
		{
			*truncated = 1;
		}
		else
		{
			fz_drop_buffer(ctx, buf);
			fz_rethrow(ctx);
		}
	}

	return buf;
}
Пример #5
0
void pdf_load_type3_glyphs(pdf_document *xref, pdf_font_desc *fontdesc, int nested_depth)
{
	int i;
	fz_context *ctx = xref->ctx;

	fz_try(ctx)
	{
		for (i = 0; i < 256; i++)
		{
			if (fontdesc->font->t3procs[i])
			{
				fz_prepare_t3_glyph(ctx, fontdesc->font, i, nested_depth);
				fontdesc->size += 0; // TODO: display list size calculation
			}
		}
	}
	fz_catch(ctx)
	{
		fz_warn(ctx, "Type3 glyph load failed: %s", fz_caught(ctx));
	}
}
Пример #6
0
void
fz_clip_stroke_path(fz_device *dev, fz_path *path, fz_rect *rect, fz_stroke_state *stroke, fz_matrix ctm)
{
	fz_context *ctx = dev->ctx;

	if (dev->error_depth)
	{
		dev->error_depth++;
		return;
	}

	fz_try(ctx)
	{
		if (dev->clip_stroke_path)
			dev->clip_stroke_path(dev, path, rect, stroke, ctm);
	}
	fz_catch(ctx)
	{
		dev->error_depth = 1;
		strcpy(dev->errmess, fz_caught(ctx));
		/* Error swallowed */
	}
}
Пример #7
0
void
fz_begin_tile(fz_device *dev, fz_rect area, fz_rect view, float xstep, float ystep, fz_matrix ctm)
{
	fz_context *ctx = dev->ctx;

	if (dev->error_depth)
	{
		dev->error_depth++;
		return;
	}

	fz_try(ctx)
	{
		if (dev->begin_tile)
			dev->begin_tile(dev, area, view, xstep, ystep, ctm);
	}
	fz_catch(ctx)
	{
		dev->error_depth = 1;
		strcpy(dev->errmess, fz_caught(ctx));
		/* Error swallowed */
	}
}
Пример #8
0
void
fz_begin_group(fz_device *dev, fz_rect area, int isolated, int knockout, int blendmode, float alpha)
{
	fz_context *ctx = dev->ctx;

	if (dev->error_depth)
	{
		dev->error_depth++;
		return;
	}

	fz_try(ctx)
	{
		if (dev->begin_group)
			dev->begin_group(dev, area, isolated, knockout, blendmode, alpha);
	}
	fz_catch(ctx)
	{
		dev->error_depth = 1;
		strcpy(dev->errmess, fz_caught(ctx));
		/* Error swallowed */
	}
}
Пример #9
0
void
fz_begin_mask(fz_device *dev, fz_rect area, int luminosity, fz_colorspace *colorspace, float *bc)
{
	fz_context *ctx = dev->ctx;

	if (dev->error_depth)
	{
		dev->error_depth++;
		return;
	}

	fz_try(ctx)
	{
		if (dev->begin_mask)
			dev->begin_mask(dev, area, luminosity, colorspace, bc);
	}
	fz_catch(ctx)
	{
		dev->error_depth = 1;
		strcpy(dev->errmess, fz_caught(ctx));
		/* Error swallowed */
	}
}
Пример #10
0
void
fz_clip_image_mask(fz_device *dev, fz_image *image, fz_rect *rect, fz_matrix ctm)
{
	fz_context *ctx = dev->ctx;

	if (dev->error_depth)
	{
		dev->error_depth++;
		return;
	}

	fz_try(ctx)
	{
		if (dev->clip_image_mask)
			dev->clip_image_mask(dev, image, rect, ctm);
	}
	fz_catch(ctx)
	{
		dev->error_depth = 1;
		strcpy(dev->errmess, fz_caught(ctx));
		/* Error swallowed */
	}
}
Пример #11
0
pdf_page *
pdf_load_page_by_obj(pdf_document *doc, int number, pdf_obj *pageref)
{
	fz_context *ctx = doc->ctx;
	pdf_page *page;
	pdf_annot *annot;
	pdf_obj *pageobj, *obj;
	fz_rect mediabox, cropbox, realbox;
	float userunit;
	fz_matrix mat;

	/* SumatraPDF: allow replacing potentially slow pdf_lookup_page_obj */
	pageobj = pdf_resolve_indirect(pageref);

	page = fz_malloc_struct(ctx, pdf_page);
	page->resources = NULL;
	page->contents = NULL;
	page->transparency = 0;
	page->links = NULL;
	page->annots = NULL;
	page->annot_tailp = &page->annots;
	page->deleted_annots = NULL;
	page->tmp_annots = NULL;
	page->me = pdf_keep_obj(pageobj);
	page->incomplete = 0;

	obj = pdf_dict_gets(pageobj, "UserUnit");
	if (pdf_is_real(obj))
		userunit = pdf_to_real(obj);
	else
		userunit = 1;

	pdf_to_rect(ctx, pdf_lookup_inherited_page_item(doc, pageobj, "MediaBox"), &mediabox);
	if (fz_is_empty_rect(&mediabox))
	{
		fz_warn(ctx, "cannot find page size for page %d", number + 1);
		mediabox.x0 = 0;
		mediabox.y0 = 0;
		mediabox.x1 = 612;
		mediabox.y1 = 792;
	}

	pdf_to_rect(ctx, pdf_lookup_inherited_page_item(doc, pageobj, "CropBox"), &cropbox);
	if (!fz_is_empty_rect(&cropbox))
		fz_intersect_rect(&mediabox, &cropbox);

	page->mediabox.x0 = fz_min(mediabox.x0, mediabox.x1) * userunit;
	page->mediabox.y0 = fz_min(mediabox.y0, mediabox.y1) * userunit;
	page->mediabox.x1 = fz_max(mediabox.x0, mediabox.x1) * userunit;
	page->mediabox.y1 = fz_max(mediabox.y0, mediabox.y1) * userunit;

	if (page->mediabox.x1 - page->mediabox.x0 < 1 || page->mediabox.y1 - page->mediabox.y0 < 1)
	{
		fz_warn(ctx, "invalid page size in page %d", number + 1);
		page->mediabox = fz_unit_rect;
	}

	page->rotate = pdf_to_int(pdf_lookup_inherited_page_item(doc, pageobj, "Rotate"));
	/* Snap page->rotate to 0, 90, 180 or 270 */
	if (page->rotate < 0)
		page->rotate = 360 - ((-page->rotate) % 360);
	if (page->rotate >= 360)
		page->rotate = page->rotate % 360;
	page->rotate = 90*((page->rotate + 45)/90);
	if (page->rotate > 360)
		page->rotate = 0;

	fz_pre_rotate(fz_scale(&page->ctm, 1, -1), -page->rotate);
	realbox = page->mediabox;
	fz_transform_rect(&realbox, &page->ctm);
	fz_pre_scale(fz_translate(&mat, -realbox.x0, -realbox.y0), userunit, userunit);
	fz_concat(&page->ctm, &page->ctm, &mat);

	fz_try(ctx)
	{
		obj = pdf_dict_gets(pageobj, "Annots");
		if (obj)
		{
			page->links = pdf_load_link_annots(doc, obj, &page->ctm);
			pdf_load_annots(doc, page, obj);
		}
	}
	fz_catch(ctx)
	{
		if (fz_caught(ctx) != FZ_ERROR_TRYLATER)
			/* SumatraPDF: ignore annotations in case of unexpected errors */
			fz_warn(ctx, "unexpectedly failed to load page annotations");
		page->incomplete |= PDF_PAGE_INCOMPLETE_ANNOTS;
	}

	page->duration = pdf_to_real(pdf_dict_gets(pageobj, "Dur"));

	obj = pdf_dict_gets(pageobj, "Trans");
	page->transition_present = (obj != NULL);
	if (obj)
	{
		pdf_load_transition(doc, page, obj);
	}

	// TODO: inherit
	page->resources = pdf_lookup_inherited_page_item(doc, pageobj, "Resources");
	if (page->resources)
		pdf_keep_obj(page->resources);

	obj = pdf_dict_gets(pageobj, "Contents");
	fz_try(ctx)
	{
		page->contents = pdf_keep_obj(obj);

		if (pdf_resources_use_blending(doc, page->resources))
			page->transparency = 1;
		/* cf. http://code.google.com/p/sumatrapdf/issues/detail?id=2107 */
		else if (!strcmp(pdf_to_name(pdf_dict_getp(pageobj, "Group/S")), "Transparency"))
			page->transparency = 1;

		for (annot = page->annots; annot && !page->transparency; annot = annot->next)
			if (annot->ap && pdf_resources_use_blending(doc, annot->ap->resources))
				page->transparency = 1;
	}
	fz_catch(ctx)
	{
		if (fz_caught(ctx) != FZ_ERROR_TRYLATER)
		{
			pdf_free_page(doc, page);
			fz_rethrow_message(ctx, "cannot load page %d contents (%d 0 R)", number + 1, pdf_to_num(pageref));
		}
		page->incomplete |= PDF_PAGE_INCOMPLETE_CONTENTS;
	}

	return page;
}
Пример #12
0
void
pdf_load_annots(fz_context *ctx, pdf_page *page, pdf_obj *annots)
{
	pdf_document *doc = page->doc;
	pdf_annot *annot, **itr;
	pdf_obj *obj, *ap, *as, *n;
	int i, len, keep_annot;

	fz_var(annot);
	fz_var(itr);
	fz_var(keep_annot);

	itr = &page->annots;

	len = pdf_array_len(ctx, annots);
	/*
	Create an initial linked list of pdf_annot structures with only the obj field
	filled in. We do this because update_appearance has the potential to change
	the annot array, so we don't want to be iterating through the array while
	that happens.
	*/
	fz_try(ctx)
	{
		for (i = 0; i < len; i++)
		{
			obj = pdf_array_get(ctx, annots, i);

			annot = pdf_new_annot(ctx, page);
			*itr = annot;
			annot->obj = pdf_keep_obj(ctx, obj);
			itr = &annot->next;
		}
	}
	fz_catch(ctx)
	{
		pdf_drop_annots(ctx, page->annots);
		page->annots = NULL;
		fz_rethrow(ctx);
	}

	/*
	Iterate through the newly created annot linked list, using a double pointer to
	facilitate deleting broken annotations.
	*/
	itr = &page->annots;
	while (*itr)
	{
		annot = *itr;

		fz_try(ctx)
		{
			pdf_hotspot *hp = &doc->hotspot;

			n = NULL;

			if (doc->update_appearance)
				doc->update_appearance(ctx, doc, annot);

			obj = annot->obj;
			ap = pdf_dict_get(ctx, obj, PDF_NAME_AP);
			as = pdf_dict_get(ctx, obj, PDF_NAME_AS);

			/* We only collect annotations with an appearance
			 * stream into this list, so remove any that don't
			 * (such as links) and continue. */
			keep_annot = pdf_is_dict(ctx, ap);
			if (!keep_annot)
				break;

			if (hp->num == pdf_to_num(ctx, obj) && (hp->state & HOTSPOT_POINTER_DOWN))
			{
				n = pdf_dict_get(ctx, ap, PDF_NAME_D); /* down state */
			}

			if (n == NULL)
				n = pdf_dict_get(ctx, ap, PDF_NAME_N); /* normal state */

			/* lookup current state in sub-dictionary */
			if (!pdf_is_stream(ctx, n))
				n = pdf_dict_get(ctx, n, as);

			annot->ap = NULL;

			if (pdf_is_stream(ctx, n))
			{
				annot->ap = pdf_load_xobject(ctx, doc, n);
				annot->ap_iteration = annot->ap->iteration;
			}
			else
				fz_warn(ctx, "no appearance stream for annotation %d 0 R", pdf_to_num(ctx, annot->obj));

			if (obj == doc->focus_obj)
				doc->focus = annot;

			/* Move to next item in the linked list */
			itr = &annot->next;
		}
		fz_catch(ctx)
		{
			if (fz_caught(ctx) == FZ_ERROR_TRYLATER)
			{
				pdf_drop_annots(ctx, page->annots);
				page->annots = NULL;
				fz_rethrow(ctx);
			}
			keep_annot = 0;
			fz_warn(ctx, "ignoring broken annotation");
		}
		if (!keep_annot)
		{
			/* Move to next item in the linked list, dropping this one */
			*itr = annot->next;
			annot->next = NULL; /* Required because pdf_drop_annots follows the "next" chain */
			pdf_drop_annots(ctx, annot);
		}
	}

	page->annot_tailp = itr;
}
Пример #13
0
void
fz_run_display_list(fz_display_list *list, fz_device *dev, const fz_matrix *top_ctm, const fz_rect *scissor, fz_cookie *cookie)
{
	fz_display_node *node;
	fz_matrix ctm;
	int clipped = 0;
	int tiled = 0;
	int progress = 0;
	fz_context *ctx = dev->ctx;

	if (!scissor)
		scissor = &fz_infinite_rect;

	if (cookie)
	{
		cookie->progress_max = list->len;
		cookie->progress = 0;
	}

	for (node = list->first; node; node = node->next)
	{
		int empty;

		fz_rect node_rect = node->rect;
		fz_transform_rect(&node_rect, top_ctm);

		/* Check the cookie for aborting */
		if (cookie)
		{
			if (cookie->abort)
				break;
			cookie->progress = progress++;
		}

		/* cull objects to draw using a quick visibility test */

		if (tiled ||
			node->cmd == FZ_CMD_BEGIN_TILE || node->cmd == FZ_CMD_END_TILE ||
			node->cmd == FZ_CMD_BEGIN_PAGE || node->cmd == FZ_CMD_END_PAGE)
		{
			empty = 0;
		}
		else
		{
			fz_rect rect = node_rect;
			fz_intersect_rect(&rect, scissor);
			empty = fz_is_empty_rect(&rect);
		}

		if (clipped || empty)
		{
			switch (node->cmd)
			{
			case FZ_CMD_CLIP_PATH:
			case FZ_CMD_CLIP_STROKE_PATH:
			case FZ_CMD_CLIP_STROKE_TEXT:
			case FZ_CMD_CLIP_IMAGE_MASK:
			case FZ_CMD_BEGIN_MASK:
			case FZ_CMD_BEGIN_GROUP:
				clipped++;
				continue;
			case FZ_CMD_CLIP_TEXT:
				/* Accumulated text has no extra pops */
				if (node->flag != 2)
					clipped++;
				continue;
			case FZ_CMD_POP_CLIP:
			case FZ_CMD_END_GROUP:
				if (!clipped)
					goto visible;
				clipped--;
				continue;
			case FZ_CMD_END_MASK:
				if (!clipped)
					goto visible;
				continue;
			default:
				continue;
			}
		}

visible:
		fz_concat(&ctm, &node->ctm, top_ctm);

		fz_try(ctx)
		{
			switch (node->cmd)
			{
			case FZ_CMD_BEGIN_PAGE:
				fz_begin_page(dev, &node_rect, &ctm);
				break;
			case FZ_CMD_END_PAGE:
				fz_end_page(dev);
				break;
			case FZ_CMD_FILL_PATH:
				fz_fill_path(dev, node->item.path, node->flag, &ctm,
					node->colorspace, node->color, node->alpha);
				break;
			case FZ_CMD_STROKE_PATH:
				fz_stroke_path(dev, node->item.path, node->stroke, &ctm,
					node->colorspace, node->color, node->alpha);
				break;
			case FZ_CMD_CLIP_PATH:
				fz_clip_path(dev, node->item.path, &node_rect, node->flag, &ctm);
				break;
			case FZ_CMD_CLIP_STROKE_PATH:
				fz_clip_stroke_path(dev, node->item.path, &node_rect, node->stroke, &ctm);
				break;
			case FZ_CMD_FILL_TEXT:
				fz_fill_text(dev, node->item.text, &ctm,
					node->colorspace, node->color, node->alpha);
				break;
			case FZ_CMD_STROKE_TEXT:
				fz_stroke_text(dev, node->item.text, node->stroke, &ctm,
					node->colorspace, node->color, node->alpha);
				break;
			case FZ_CMD_CLIP_TEXT:
				fz_clip_text(dev, node->item.text, &ctm, node->flag);
				break;
			case FZ_CMD_CLIP_STROKE_TEXT:
				fz_clip_stroke_text(dev, node->item.text, node->stroke, &ctm);
				break;
			case FZ_CMD_IGNORE_TEXT:
				fz_ignore_text(dev, node->item.text, &ctm);
				break;
			case FZ_CMD_FILL_SHADE:
				if ((dev->hints & FZ_IGNORE_SHADE) == 0)
					fz_fill_shade(dev, node->item.shade, &ctm, node->alpha);
				break;
			case FZ_CMD_FILL_IMAGE:
				if ((dev->hints & FZ_IGNORE_IMAGE) == 0)
					fz_fill_image(dev, node->item.image, &ctm, node->alpha);
				break;
			case FZ_CMD_FILL_IMAGE_MASK:
				if ((dev->hints & FZ_IGNORE_IMAGE) == 0)
					fz_fill_image_mask(dev, node->item.image, &ctm,
						node->colorspace, node->color, node->alpha);
				break;
			case FZ_CMD_CLIP_IMAGE_MASK:
				if ((dev->hints & FZ_IGNORE_IMAGE) == 0)
					fz_clip_image_mask(dev, node->item.image, &node_rect, &ctm);
				break;
			case FZ_CMD_POP_CLIP:
				fz_pop_clip(dev);
				break;
			case FZ_CMD_BEGIN_MASK:
				fz_begin_mask(dev, &node_rect, node->flag, node->colorspace, node->color);
				break;
			case FZ_CMD_END_MASK:
				fz_end_mask(dev);
				break;
			case FZ_CMD_BEGIN_GROUP:
				fz_begin_group(dev, &node_rect,
					(node->flag & ISOLATED) != 0, (node->flag & KNOCKOUT) != 0,
					node->item.blendmode, node->alpha);
				break;
			case FZ_CMD_END_GROUP:
				fz_end_group(dev);
				break;
			case FZ_CMD_BEGIN_TILE:
			{
				int cached;
				fz_rect tile_rect;
				tiled++;
				tile_rect.x0 = node->color[2];
				tile_rect.y0 = node->color[3];
				tile_rect.x1 = node->color[4];
				tile_rect.y1 = node->color[5];
				cached = fz_begin_tile_id(dev, &node->rect, &tile_rect, node->color[0], node->color[1], &ctm, node->flag);
				if (cached)
					node = skip_to_end_tile(node, &progress);
				break;
			}
			case FZ_CMD_END_TILE:
				tiled--;
				fz_end_tile(dev);
				break;
			/* SumatraPDF: support transfer functions */
			case FZ_CMD_APPLY_TRANSFER_FUNCTION:
				fz_apply_transfer_function(dev, node->item.tr, node->flag);
				break;
			}
		}
		fz_catch(ctx)
		{
			/* Swallow the error */
			if (cookie)
				cookie->errors++;
			if (fz_caught(ctx) == FZ_ERROR_ABORT)
				break;
			fz_warn(ctx, "Ignoring error during interpretation");
		}
	}
}