summaryrefslogtreecommitdiff
path: root/fitz
diff options
context:
space:
mode:
authorRobin Watts <Robin.Watts@artifex.com>2011-07-06 16:32:33 +0100
committerRobin Watts <Robin.Watts@artifex.com>2011-07-08 19:26:34 +0100
commit2c4bbbfdc7413a68cad395c3c61ff8e62dceb18b (patch)
treec2299029fa26028103e533c2dce15aa18d9a8d76 /fitz
parent2f8acb0010c469c46682a298d66b108cc4c6cdd0 (diff)
downloadmupdf-2c4bbbfdc7413a68cad395c3c61ff8e62dceb18b.tar.xz
Clip area optimisations for displaylist case:
First, we add clipping rects to clipping functions. Various functions (the ones that handle clipping) are now additionally passed a rectangle that represents an additional bound for this clip in device space (i.e. it has already been mapped through the current ctm). Next, when constructing the displaylist, keep track of the bounding box for the contents of each clip. While writing the list, on every node we add, we add the bbox for that node to the enclosing clips content bbox (if there is an enclosing clip). When we pop a clip, write back to the corresponding push to update the bbox. This means if we get large clip regions, with only small areas used within them, we will only do the slow blending for those small areas. Finally, we fix a calculation in fz_bound_path which was incorrectly accounting for mitrelimits. This was showing up in testing on page 630 of the PDF reference v1.7.
Diffstat (limited to 'fitz')
-rw-r--r--fitz/base_geometry.c30
-rw-r--r--fitz/dev_list.c87
-rw-r--r--fitz/dev_null.c12
-rw-r--r--fitz/dev_trace.c6
-rw-r--r--fitz/fitz.h14
-rw-r--r--fitz/res_path.c2
6 files changed, 128 insertions, 23 deletions
diff --git a/fitz/base_geometry.c b/fitz/base_geometry.c
index 302ef966..00a85c9b 100644
--- a/fitz/base_geometry.c
+++ b/fitz/base_geometry.c
@@ -160,6 +160,36 @@ fz_round_rect(fz_rect f)
return i;
}
+fz_rect
+fz_intersect_rect(fz_rect a, fz_rect b)
+{
+ fz_rect r;
+ if (fz_is_infinite_rect(a)) return b;
+ if (fz_is_infinite_rect(b)) return a;
+ if (fz_is_empty_rect(a)) return fz_empty_rect;
+ if (fz_is_empty_rect(b)) return fz_empty_rect;
+ r.x0 = MAX(a.x0, b.x0);
+ r.y0 = MAX(a.y0, b.y0);
+ r.x1 = MIN(a.x1, b.x1);
+ r.y1 = MIN(a.y1, b.y1);
+ return (r.x1 < r.x0 || r.y1 < r.y0) ? fz_empty_rect : r;
+}
+
+fz_rect
+fz_union_rect(fz_rect a, fz_rect b)
+{
+ fz_rect r;
+ if (fz_is_infinite_rect(a)) return a;
+ if (fz_is_infinite_rect(b)) return b;
+ if (fz_is_empty_rect(a)) return b;
+ if (fz_is_empty_rect(b)) return a;
+ r.x0 = MIN(a.x0, b.x0);
+ r.y0 = MIN(a.y0, b.y0);
+ r.x1 = MAX(a.x1, b.x1);
+ r.y1 = MAX(a.y1, b.y1);
+ return r;
+}
+
fz_bbox
fz_intersect_bbox(fz_bbox a, fz_bbox b)
{
diff --git a/fitz/dev_list.c b/fitz/dev_list.c
index eeb4e485..44528d8b 100644
--- a/fitz/dev_list.c
+++ b/fitz/dev_list.c
@@ -2,6 +2,8 @@
typedef struct fz_display_node_s fz_display_node;
+#define STACK_SIZE 96
+
typedef enum fz_display_command_e
{
FZ_CMD_FILL_PATH,
@@ -50,6 +52,13 @@ struct fz_display_list_s
{
fz_display_node *first;
fz_display_node *last;
+
+ int top;
+ struct {
+ fz_rect *update;
+ fz_rect rect;
+ } stack[STACK_SIZE];
+ int tiled;
};
enum { ISOLATED = 1, KNOCKOUT = 2 };
@@ -98,6 +107,54 @@ fz_clone_stroke_state(fz_stroke_state *stroke)
static void
fz_append_display_node(fz_display_list *list, fz_display_node *node)
{
+ switch (node->cmd) {
+ case FZ_CMD_CLIP_PATH:
+ case FZ_CMD_CLIP_STROKE_PATH:
+ case FZ_CMD_CLIP_IMAGE_MASK:
+ list->stack[list->top].update = &node->rect;
+ list->stack[list->top].rect = fz_empty_rect;
+ list->top++;
+ break;
+ case FZ_CMD_CLIP_TEXT:
+ case FZ_CMD_CLIP_STROKE_TEXT:
+ list->stack[list->top].update = NULL;
+ list->stack[list->top].rect = fz_empty_rect;
+ list->top++;
+ break;
+ case FZ_CMD_BEGIN_TILE:
+ list->tiled++;
+ if (list->top > 0) {
+ list->stack[list->top-1].rect = fz_infinite_rect;
+ }
+ break;
+ case FZ_CMD_END_TILE:
+ list->tiled--;
+ break;
+ case FZ_CMD_END_GROUP:
+ break;
+ case FZ_CMD_POP_CLIP:
+ if (list->top > 0) {
+ fz_rect *update;
+ list->top--;
+ update = list->stack[list->top].update;
+ if (list->tiled == 0) {
+ if (update != NULL) {
+ *update = fz_intersect_rect(*update, list->stack[list->top].rect);
+ node->rect = *update;
+ } else {
+ node->rect = list->stack[list->top].rect;
+ }
+ } else {
+ node->rect = fz_infinite_rect;
+ }
+ }
+ /*@fallthrough@*/
+ default:
+ if ((list->top > 0) && (list->tiled == 0)) {
+ list->stack[list->top-1].rect = fz_union_rect(list->stack[list->top-1].rect, node->rect);
+ }
+ break;
+ }
if (!list->first)
{
list->first = node;
@@ -177,22 +234,26 @@ fz_list_stroke_path(void *user, fz_path *path, fz_stroke_state *stroke, fz_matri
}
static void
-fz_list_clip_path(void *user, fz_path *path, int even_odd, fz_matrix ctm)
+fz_list_clip_path(void *user, fz_path *path, fz_rect *rect, int even_odd, fz_matrix ctm)
{
fz_display_node *node;
node = fz_new_display_node(FZ_CMD_CLIP_PATH, ctm, NULL, NULL, 0);
node->rect = fz_bound_path(path, NULL, ctm);
+ if (rect != NULL)
+ node->rect = fz_intersect_rect(node->rect, *rect);
node->item.path = fz_clone_path(path);
node->flag = even_odd;
fz_append_display_node(user, node);
}
static void
-fz_list_clip_stroke_path(void *user, fz_path *path, fz_stroke_state *stroke, fz_matrix ctm)
+fz_list_clip_stroke_path(void *user, fz_path *path, fz_rect *rect, fz_stroke_state *stroke, fz_matrix ctm)
{
fz_display_node *node;
node = fz_new_display_node(FZ_CMD_CLIP_STROKE_PATH, ctm, NULL, NULL, 0);
node->rect = fz_bound_path(path, stroke, ctm);
+ if (rect != NULL)
+ node->rect = fz_intersect_rect(node->rect, *rect);
node->item.path = fz_clone_path(path);
node->stroke = fz_clone_stroke_state(stroke);
fz_append_display_node(user, node);
@@ -261,7 +322,6 @@ fz_list_pop_clip(void *user)
{
fz_display_node *node;
node = fz_new_display_node(FZ_CMD_POP_CLIP, fz_identity, NULL, NULL, 0);
- /* TODO: scan back for matching pushclip and calculate bbox of contents */
fz_append_display_node(user, node);
}
@@ -297,11 +357,13 @@ fz_list_fill_image_mask(void *user, fz_pixmap *image, fz_matrix ctm,
}
static void
-fz_list_clip_image_mask(void *user, fz_pixmap *image, fz_matrix ctm)
+fz_list_clip_image_mask(void *user, fz_pixmap *image, fz_rect *rect, fz_matrix ctm)
{
fz_display_node *node;
node = fz_new_display_node(FZ_CMD_CLIP_IMAGE_MASK, ctm, NULL, NULL, 0);
node->rect = fz_transform_rect(ctm, fz_unit_rect);
+ if (rect != NULL)
+ node->rect = fz_intersect_rect(node->rect, *rect);
node->item.image = fz_keep_pixmap(image);
fz_append_display_node(user, node);
}
@@ -407,6 +469,8 @@ fz_new_display_list(void)
fz_display_list *list = fz_malloc(sizeof(fz_display_list));
list->first = NULL;
list->last = NULL;
+ list->top = 0;
+ list->tiled = 0;
return list;
}
@@ -499,11 +563,17 @@ visible:
node->colorspace, node->color, node->alpha);
break;
case FZ_CMD_CLIP_PATH:
- fz_clip_path(dev, node->item.path, node->flag, ctm);
+ {
+ fz_rect trect = fz_transform_rect(top_ctm, node->rect);
+ fz_clip_path(dev, node->item.path, &trect, node->flag, ctm);
break;
+ }
case FZ_CMD_CLIP_STROKE_PATH:
- fz_clip_stroke_path(dev, node->item.path, node->stroke, ctm);
+ {
+ fz_rect trect = fz_transform_rect(top_ctm, node->rect);
+ fz_clip_stroke_path(dev, node->item.path, &trect, node->stroke, ctm);
break;
+ }
case FZ_CMD_FILL_TEXT:
fz_fill_text(dev, node->item.text, ctm,
node->colorspace, node->color, node->alpha);
@@ -532,8 +602,11 @@ visible:
node->colorspace, node->color, node->alpha);
break;
case FZ_CMD_CLIP_IMAGE_MASK:
- fz_clip_image_mask(dev, node->item.image, ctm);
+ {
+ fz_rect trect = fz_transform_rect(top_ctm, node->rect);
+ fz_clip_image_mask(dev, node->item.image, &trect, ctm);
break;
+ }
case FZ_CMD_POP_CLIP:
fz_pop_clip(dev);
break;
diff --git a/fitz/dev_null.c b/fitz/dev_null.c
index f81b330c..4d40ef73 100644
--- a/fitz/dev_null.c
+++ b/fitz/dev_null.c
@@ -35,17 +35,17 @@ fz_stroke_path(fz_device *dev, fz_path *path, fz_stroke_state *stroke, fz_matrix
}
void
-fz_clip_path(fz_device *dev, fz_path *path, int even_odd, fz_matrix ctm)
+fz_clip_path(fz_device *dev, fz_path *path, fz_rect *rect, int even_odd, fz_matrix ctm)
{
if (dev->clip_path)
- dev->clip_path(dev->user, path, even_odd, ctm);
+ dev->clip_path(dev->user, path, rect, even_odd, ctm);
}
void
-fz_clip_stroke_path(fz_device *dev, fz_path *path, fz_stroke_state *stroke, fz_matrix ctm)
+fz_clip_stroke_path(fz_device *dev, fz_path *path, fz_rect *rect, fz_stroke_state *stroke, fz_matrix ctm)
{
if (dev->clip_stroke_path)
- dev->clip_stroke_path(dev->user, path, stroke, ctm);
+ dev->clip_stroke_path(dev->user, path, rect, stroke, ctm);
}
void
@@ -115,10 +115,10 @@ fz_fill_image_mask(fz_device *dev, fz_pixmap *image, fz_matrix ctm,
}
void
-fz_clip_image_mask(fz_device *dev, fz_pixmap *image, fz_matrix ctm)
+fz_clip_image_mask(fz_device *dev, fz_pixmap *image, fz_rect *rect, fz_matrix ctm)
{
if (dev->clip_image_mask)
- dev->clip_image_mask(dev->user, image, ctm);
+ dev->clip_image_mask(dev->user, image, rect, ctm);
}
void
diff --git a/fitz/dev_trace.c b/fitz/dev_trace.c
index 9e6853b8..06f749f9 100644
--- a/fitz/dev_trace.c
+++ b/fitz/dev_trace.c
@@ -105,7 +105,7 @@ fz_trace_stroke_path(void *user, fz_path *path, fz_stroke_state *stroke, fz_matr
}
static void
-fz_trace_clip_path(void *user, fz_path *path, int even_odd, fz_matrix ctm)
+fz_trace_clip_path(void *user, fz_path *path, fz_rect *rect, int even_odd, fz_matrix ctm)
{
printf("<clip_path ");
if (even_odd)
@@ -119,7 +119,7 @@ fz_trace_clip_path(void *user, fz_path *path, int even_odd, fz_matrix ctm)
}
static void
-fz_trace_clip_stroke_path(void *user, fz_path *path, fz_stroke_state *stroke, fz_matrix ctm)
+fz_trace_clip_stroke_path(void *user, fz_path *path, fz_rect *rect, fz_stroke_state *stroke, fz_matrix ctm)
{
printf("<clip_stroke_path ");
fz_trace_matrix(ctm);
@@ -210,7 +210,7 @@ fz_colorspace *colorspace, float *color, float alpha)
}
static void
-fz_trace_clip_image_mask(void *user, fz_pixmap *image, fz_matrix ctm)
+fz_trace_clip_image_mask(void *user, fz_pixmap *image, fz_rect *rect, fz_matrix ctm)
{
printf("<clip_image_mask ");
fz_trace_matrix(ctm);
diff --git a/fitz/fitz.h b/fitz/fitz.h
index 381ae919..5bc22f4e 100644
--- a/fitz/fitz.h
+++ b/fitz/fitz.h
@@ -264,7 +264,9 @@ float fz_matrix_expansion(fz_matrix m);
fz_bbox fz_round_rect(fz_rect r);
fz_bbox fz_intersect_bbox(fz_bbox a, fz_bbox b);
+fz_rect fz_intersect_rect(fz_rect a, fz_rect b);
fz_bbox fz_union_bbox(fz_bbox a, fz_bbox b);
+fz_rect fz_union_rect(fz_rect a, fz_rect b);
fz_point fz_transform_point(fz_matrix m, fz_point p);
fz_point fz_transform_vector(fz_matrix m, fz_point p);
@@ -954,8 +956,8 @@ struct fz_device_s
void (*fill_path)(void *, fz_path *, int even_odd, fz_matrix, fz_colorspace *, float *color, float alpha);
void (*stroke_path)(void *, fz_path *, fz_stroke_state *, fz_matrix, fz_colorspace *, float *color, float alpha);
- void (*clip_path)(void *, fz_path *, int even_odd, fz_matrix);
- void (*clip_stroke_path)(void *, fz_path *, fz_stroke_state *, fz_matrix);
+ void (*clip_path)(void *, fz_path *, fz_rect *rect, int even_odd, fz_matrix);
+ void (*clip_stroke_path)(void *, fz_path *, fz_rect *rect, fz_stroke_state *, fz_matrix);
void (*fill_text)(void *, fz_text *, fz_matrix, fz_colorspace *, float *color, float alpha);
void (*stroke_text)(void *, fz_text *, fz_stroke_state *, fz_matrix, fz_colorspace *, float *color, float alpha);
@@ -966,7 +968,7 @@ struct fz_device_s
void (*fill_shade)(void *, fz_shade *shd, fz_matrix ctm, float alpha);
void (*fill_image)(void *, fz_pixmap *img, fz_matrix ctm, float alpha);
void (*fill_image_mask)(void *, fz_pixmap *img, fz_matrix ctm, fz_colorspace *, float *color, float alpha);
- void (*clip_image_mask)(void *, fz_pixmap *img, fz_matrix ctm);
+ void (*clip_image_mask)(void *, fz_pixmap *img, fz_rect *rect, fz_matrix ctm);
void (*pop_clip)(void *);
@@ -981,8 +983,8 @@ struct fz_device_s
void fz_fill_path(fz_device *dev, fz_path *path, int even_odd, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha);
void fz_stroke_path(fz_device *dev, fz_path *path, fz_stroke_state *stroke, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha);
-void fz_clip_path(fz_device *dev, fz_path *path, int even_odd, fz_matrix ctm);
-void fz_clip_stroke_path(fz_device *dev, fz_path *path, fz_stroke_state *stroke, fz_matrix ctm);
+void fz_clip_path(fz_device *dev, fz_path *path, fz_rect *rect, int even_odd, fz_matrix ctm);
+void fz_clip_stroke_path(fz_device *dev, fz_path *path, fz_rect *rect, fz_stroke_state *stroke, fz_matrix ctm);
void fz_fill_text(fz_device *dev, fz_text *text, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha);
void fz_stroke_text(fz_device *dev, fz_text *text, fz_stroke_state *stroke, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha);
void fz_clip_text(fz_device *dev, fz_text *text, fz_matrix ctm, int accumulate);
@@ -992,7 +994,7 @@ void fz_pop_clip(fz_device *dev);
void fz_fill_shade(fz_device *dev, fz_shade *shade, fz_matrix ctm, float alpha);
void fz_fill_image(fz_device *dev, fz_pixmap *image, fz_matrix ctm, float alpha);
void fz_fill_image_mask(fz_device *dev, fz_pixmap *image, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha);
-void fz_clip_image_mask(fz_device *dev, fz_pixmap *image, fz_matrix ctm);
+void fz_clip_image_mask(fz_device *dev, fz_pixmap *image, fz_rect *rect, fz_matrix ctm);
void fz_begin_mask(fz_device *dev, fz_rect area, int luminosity, fz_colorspace *colorspace, float *bc);
void fz_end_mask(fz_device *dev);
void fz_begin_group(fz_device *dev, fz_rect area, int isolated, int knockout, int blendmode, float alpha);
diff --git a/fitz/res_path.c b/fitz/res_path.c
index 4959754b..b9eb1ee3 100644
--- a/fitz/res_path.c
+++ b/fitz/res_path.c
@@ -158,7 +158,7 @@ fz_bound_path(fz_path *path, fz_stroke_state *stroke, fz_matrix ctm)
if (stroke)
{
- float miterlength = sinf(stroke->miterlimit * 0.5f);
+ float miterlength = stroke->miterlimit;
float linewidth = stroke->linewidth;
float expand = MAX(miterlength, linewidth) * 0.5f;
r.x0 -= expand;