summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Vrhel <michael.vrhel@artifex.com>2017-06-23 12:23:36 -0700
committerRobin Watts <robin.watts@artifex.com>2017-07-17 19:32:06 +0100
commit63713f22ae830142dfe0d3896948ec53c4705ace (patch)
treefe8334e262f4507dc2cd2a3ee6d6239bb2c44b40
parent28bfd69eb4101a2197920da6cbc21f491d8cb288 (diff)
downloadmupdf-63713f22ae830142dfe0d3896948ec53c4705ace.tar.xz
Add colorspace handling to transparency groups
Also force softmasks to be isolated groups.
-rw-r--r--include/mupdf/fitz/device.h4
-rw-r--r--include/mupdf/pdf/page.h1
-rw-r--r--platform/java/mupdf_native.c2
-rw-r--r--source/fitz/bbox-device.c2
-rw-r--r--source/fitz/colorspace.c2
-rw-r--r--source/fitz/device.c4
-rw-r--r--source/fitz/draw-device.c12
-rw-r--r--source/fitz/list-device.c46
-rw-r--r--source/fitz/svg-device.c2
-rw-r--r--source/fitz/test-device.c4
-rw-r--r--source/fitz/trace-device.c2
-rw-r--r--source/pdf/pdf-device.c4
-rw-r--r--source/pdf/pdf-op-run.c19
-rw-r--r--source/pdf/pdf-page.c6
-rw-r--r--source/pdf/pdf-run.c22
-rw-r--r--source/tools/murun.c4
16 files changed, 94 insertions, 42 deletions
diff --git a/include/mupdf/fitz/device.h b/include/mupdf/fitz/device.h
index 6d2c24c2..afbd8563 100644
--- a/include/mupdf/fitz/device.h
+++ b/include/mupdf/fitz/device.h
@@ -106,7 +106,7 @@ struct fz_device_s
void (*begin_mask)(fz_context *, fz_device *, const fz_rect *, int luminosity, fz_colorspace *, const float *bc, const fz_color_params *);
void (*end_mask)(fz_context *, fz_device *);
- void (*begin_group)(fz_context *, fz_device *, const fz_rect *, int isolated, int knockout, int blendmode, float alpha);
+ void (*begin_group)(fz_context *, fz_device *, const fz_rect *, fz_colorspace *cs, int isolated, int knockout, int blendmode, float alpha);
void (*end_group)(fz_context *, fz_device *);
int (*begin_tile)(fz_context *, fz_device *, const fz_rect *area, const fz_rect *view, float xstep, float ystep, const fz_matrix *ctm, int id);
@@ -141,7 +141,7 @@ void fz_fill_image_mask(fz_context *ctx, fz_device *dev, fz_image *image, const
void fz_clip_image_mask(fz_context *ctx, fz_device *dev, fz_image *image, const fz_matrix *ctm, const fz_rect *scissor);
void fz_begin_mask(fz_context *ctx, fz_device *dev, const fz_rect *area, int luminosity, fz_colorspace *colorspace, const float *bc, const fz_color_params *color_params);
void fz_end_mask(fz_context *ctx, fz_device *dev);
-void fz_begin_group(fz_context *ctx, fz_device *dev, const fz_rect *area, int isolated, int knockout, int blendmode, float alpha);
+void fz_begin_group(fz_context *ctx, fz_device *dev, const fz_rect *area, fz_colorspace *cs, int isolated, int knockout, int blendmode, float alpha);
void fz_end_group(fz_context *ctx, fz_device *dev);
void fz_begin_tile(fz_context *ctx, fz_device *dev, const fz_rect *area, const fz_rect *view, float xstep, float ystep, const fz_matrix *ctm);
int fz_begin_tile_id(fz_context *ctx, fz_device *dev, const fz_rect *area, const fz_rect *view, float xstep, float ystep, const fz_matrix *ctm, int id);
diff --git a/include/mupdf/pdf/page.h b/include/mupdf/pdf/page.h
index 3a077e37..4aae3481 100644
--- a/include/mupdf/pdf/page.h
+++ b/include/mupdf/pdf/page.h
@@ -39,6 +39,7 @@ void pdf_page_obj_transform(fz_context *ctx, pdf_obj *pageobj, fz_rect *page_med
void pdf_page_transform(fz_context *ctx, pdf_page *page, fz_rect *mediabox, fz_matrix *ctm);
pdf_obj *pdf_page_resources(fz_context *ctx, pdf_page *page);
pdf_obj *pdf_page_contents(fz_context *ctx, pdf_page *page);
+pdf_obj *pdf_page_group(fz_context *ctx, pdf_page *page);
fz_link *pdf_load_links(fz_context *ctx, pdf_page *page);
diff --git a/platform/java/mupdf_native.c b/platform/java/mupdf_native.c
index 2b198a77..69208f56 100644
--- a/platform/java/mupdf_native.c
+++ b/platform/java/mupdf_native.c
@@ -2689,7 +2689,7 @@ FUN(NativeDevice_beginGroup)(JNIEnv *env, jobject self, jobject jrect, jboolean
info = lockNativeDevice(env, self);
fz_try(ctx)
- fz_begin_group(ctx, dev, &rect, isolated, knockout, blendmode, alpha);
+ fz_begin_group(ctx, dev, &rect, NULL, isolated, knockout, blendmode, alpha);
fz_always(ctx)
unlockNativeDevice(env, info);
fz_catch(ctx)
diff --git a/source/fitz/bbox-device.c b/source/fitz/bbox-device.c
index a288ec45..37778741 100644
--- a/source/fitz/bbox-device.c
+++ b/source/fitz/bbox-device.c
@@ -151,7 +151,7 @@ fz_bbox_end_mask(fz_context *ctx, fz_device *dev)
}
static void
-fz_bbox_begin_group(fz_context *ctx, fz_device *dev, const fz_rect *rect, int isolated, int knockout, int blendmode, float alpha)
+fz_bbox_begin_group(fz_context *ctx, fz_device *dev, const fz_rect *rect, fz_colorspace *cs, int isolated, int knockout, int blendmode, float alpha)
{
fz_bbox_add_rect(ctx, dev, rect, 1);
}
diff --git a/source/fitz/colorspace.c b/source/fitz/colorspace.c
index 229cd4ca..0a6d2b91 100644
--- a/source/fitz/colorspace.c
+++ b/source/fitz/colorspace.c
@@ -324,7 +324,7 @@ fz_new_icc_link(fz_context *ctx, fz_iccprofile *src, fz_iccprofile *prf, fz_iccp
link->num_in = src->num_devcomp;
link->num_out = dst->num_devcomp;
- if (memcmp(src->md5, dst->md5, 16) == 0 && rend->ri == FZ_RI_RELATIVE_COLORIMETRIC && prf == NULL)
+ if (memcmp(src->md5, dst->md5, 16) == 0 && prf == NULL)
{
link->is_identity = 1;
return link;
diff --git a/source/fitz/device.c b/source/fitz/device.c
index fcf135d0..0f658d31 100644
--- a/source/fitz/device.c
+++ b/source/fitz/device.c
@@ -416,7 +416,7 @@ fz_end_mask(fz_context *ctx, fz_device *dev)
}
void
-fz_begin_group(fz_context *ctx, fz_device *dev, const fz_rect *area, int isolated, int knockout, int blendmode, float alpha)
+fz_begin_group(fz_context *ctx, fz_device *dev, const fz_rect *area, fz_colorspace *cs, int isolated, int knockout, int blendmode, float alpha)
{
if (dev->error_depth)
{
@@ -429,7 +429,7 @@ fz_begin_group(fz_context *ctx, fz_device *dev, const fz_rect *area, int isolate
if (dev->hints & FZ_MAINTAIN_CONTAINER_STACK)
push_clip_stack(ctx, dev, area, fz_device_container_stack_is_group);
if (dev->begin_group)
- dev->begin_group(ctx, dev, area, isolated, knockout, blendmode, alpha);
+ dev->begin_group(ctx, dev, area, cs, isolated, knockout, blendmode, alpha);
}
fz_catch(ctx)
{
diff --git a/source/fitz/draw-device.c b/source/fitz/draw-device.c
index 54ed3f05..66b198fc 100644
--- a/source/fitz/draw-device.c
+++ b/source/fitz/draw-device.c
@@ -1854,7 +1854,7 @@ fz_draw_end_mask(fz_context *ctx, fz_device *devp)
}
static void
-fz_draw_begin_group(fz_context *ctx, fz_device *devp, const fz_rect *rect, int isolated, int knockout, int blendmode, float alpha)
+fz_draw_begin_group(fz_context *ctx, fz_device *devp, const fz_rect *rect, fz_colorspace *cs, int isolated, int knockout, int blendmode, float alpha)
{
fz_draw_device *dev = (fz_draw_device*)devp;
fz_irect bbox;
@@ -1863,6 +1863,9 @@ fz_draw_begin_group(fz_context *ctx, fz_device *devp, const fz_rect *rect, int i
fz_colorspace *model = state->dest->colorspace;
fz_rect trect = *rect;
+ if (cs != NULL)
+ model = fz_default_colorspace(ctx, dev->default_cs, cs);
+
if (state->blendmode & FZ_BLEND_KNOCKOUT)
fz_knockout_begin(ctx, dev);
@@ -1952,6 +1955,13 @@ fz_draw_end_group(fz_context *ctx, fz_device *devp)
if (state[1].blendmode & FZ_BLEND_KNOCKOUT)
printf(" (knockout)");
#endif
+ if (state[0].dest->colorspace != state[1].dest->colorspace)
+ {
+ fz_pixmap *converted = fz_convert_pixmap(ctx, state[1].dest, state[0].dest->colorspace, NULL, dev->default_cs, fz_default_color_params(ctx), 1);
+ fz_drop_pixmap(ctx, state[1].dest);
+ state[1].dest = converted;
+ }
+
if ((blendmode == 0) && (state[0].shape == state[1].shape))
fz_paint_pixmap(state[0].dest, state[1].dest, alpha * 255);
else
diff --git a/source/fitz/list-device.c b/source/fitz/list-device.c
index 4d2f0c00..03f163a5 100644
--- a/source/fitz/list-device.c
+++ b/source/fitz/list-device.c
@@ -1098,29 +1098,40 @@ fz_list_end_mask(fz_context *ctx, fz_device *dev)
}
static void
-fz_list_begin_group(fz_context *ctx, fz_device *dev, const fz_rect *rect, int isolated, int knockout, int blendmode, float alpha)
+fz_list_begin_group(fz_context *ctx, fz_device *dev, const fz_rect *rect, fz_colorspace *colorspace, int isolated, int knockout, int blendmode, float alpha)
{
int flags;
+ colorspace = fz_keep_colorspace(ctx, colorspace);
+
flags = (blendmode<<2);
if (isolated)
flags |= ISOLATED;
if (knockout)
flags |= KNOCKOUT;
- fz_append_display_node(
- ctx,
- dev,
- FZ_CMD_BEGIN_GROUP,
- flags,
- rect,
- NULL, /* path */
- NULL, /* color */
- NULL, /* colorspace */
- &alpha, /* alpha */
- NULL, /* ctm */
- NULL, /* stroke */
- NULL, /* private_data */
- 0); /* private_data_len */
+
+ fz_try(ctx)
+ {
+ fz_append_display_node(
+ ctx,
+ dev,
+ FZ_CMD_BEGIN_GROUP,
+ flags,
+ rect,
+ NULL, /* path */
+ NULL, /* color */
+ NULL, /* colorspace */
+ &alpha, /* alpha */
+ NULL, /* ctm */
+ NULL, /* stroke */
+ &colorspace, /* private_data */
+ sizeof(colorspace)); /* private_data_len */
+ }
+ fz_catch(ctx)
+ {
+ fz_drop_colorspace(ctx, colorspace);
+ fz_rethrow(ctx);
+ }
}
static void
@@ -1394,6 +1405,9 @@ fz_drop_display_list_imp(fz_context *ctx, fz_storable *list_)
case FZ_CMD_CLIP_IMAGE_MASK:
fz_drop_image(ctx, *(fz_image **)node);
break;
+ case FZ_CMD_BEGIN_GROUP:
+ fz_drop_colorspace(ctx, *(fz_colorspace **)node);
+ break;
case FZ_CMD_DEFAULT_COLORSPACES:
fz_drop_default_colorspaces(ctx, *(fz_default_colorspaces **)node);
break;
@@ -1732,7 +1746,7 @@ visible:
fz_end_mask(ctx, dev);
break;
case FZ_CMD_BEGIN_GROUP:
- fz_begin_group(ctx, dev, &trans_rect, (n.flags & ISOLATED) != 0, (n.flags & KNOCKOUT) != 0, (n.flags>>2), alpha);
+ fz_begin_group(ctx, dev, &trans_rect, *(fz_colorspace **)node, (n.flags & ISOLATED) != 0, (n.flags & KNOCKOUT) != 0, (n.flags>>2), alpha);
break;
case FZ_CMD_END_GROUP:
fz_end_group(ctx, dev);
diff --git a/source/fitz/svg-device.c b/source/fitz/svg-device.c
index 1bd6987f..b327824f 100644
--- a/source/fitz/svg-device.c
+++ b/source/fitz/svg-device.c
@@ -1094,7 +1094,7 @@ svg_dev_end_mask(fz_context *ctx, fz_device *dev)
}
static void
-svg_dev_begin_group(fz_context *ctx, fz_device *dev, const fz_rect *bbox, int isolated, int knockout, int blendmode, float alpha)
+svg_dev_begin_group(fz_context *ctx, fz_device *dev, const fz_rect *bbox, fz_colorspace *cs, int isolated, int knockout, int blendmode, float alpha)
{
svg_device *sdev = (svg_device*)dev;
fz_output *out = sdev->out;
diff --git a/source/fitz/test-device.c b/source/fitz/test-device.c
index aa6631a8..94572a55 100644
--- a/source/fitz/test-device.c
+++ b/source/fitz/test-device.c
@@ -439,11 +439,11 @@ fz_test_end_mask(fz_context *ctx, fz_device *dev_)
}
static void
-fz_test_begin_group(fz_context *ctx, fz_device *dev_, const fz_rect *rect, int isolated, int knockout, int blendmode, float alpha)
+fz_test_begin_group(fz_context *ctx, fz_device *dev_, const fz_rect *rect, fz_colorspace *cs, int isolated, int knockout, int blendmode, float alpha)
{
fz_test_device *dev = (fz_test_device*)dev_;
- fz_begin_group(ctx, dev->passthrough, rect, isolated, knockout, blendmode, alpha);
+ fz_begin_group(ctx, dev->passthrough, rect, cs, isolated, knockout, blendmode, alpha);
}
static void
diff --git a/source/fitz/trace-device.c b/source/fitz/trace-device.c
index db08aa52..13ce7256 100644
--- a/source/fitz/trace-device.c
+++ b/source/fitz/trace-device.c
@@ -313,7 +313,7 @@ fz_trace_end_mask(fz_context *ctx, fz_device *dev)
}
static void
-fz_trace_begin_group(fz_context *ctx, fz_device *dev, const fz_rect *bbox, int isolated, int knockout, int blendmode, float alpha)
+fz_trace_begin_group(fz_context *ctx, fz_device *dev, const fz_rect *bbox, fz_colorspace *cs, int isolated, int knockout, int blendmode, float alpha)
{
fz_output *out = ((fz_trace_device*)dev)->out;
fz_write_printf(ctx, out, "<group bbox=\"%g %g %g %g\" isolated=\"%d\" knockout=\"%d\" blendmode=\"%s\" alpha=\"%g\">\n",
diff --git a/source/pdf/pdf-device.c b/source/pdf/pdf-device.c
index ba51265a..34aab893 100644
--- a/source/pdf/pdf-device.c
+++ b/source/pdf/pdf-device.c
@@ -977,7 +977,7 @@ pdf_dev_end_mask(fz_context *ctx, fz_device *dev)
}
static void
-pdf_dev_begin_group(fz_context *ctx, fz_device *dev, const fz_rect *bbox, int isolated, int knockout, int blendmode, float alpha)
+pdf_dev_begin_group(fz_context *ctx, fz_device *dev, const fz_rect *bbox, fz_colorspace *cs, int isolated, int knockout, int blendmode, float alpha)
{
pdf_device *pdev = (pdf_device*)dev;
pdf_document *doc = pdev->doc;
@@ -987,7 +987,7 @@ pdf_dev_begin_group(fz_context *ctx, fz_device *dev, const fz_rect *bbox, int is
pdf_dev_end_text(ctx, pdev);
- num = pdf_dev_new_form(ctx, &form_ref, pdev, bbox, isolated, knockout, alpha, NULL);
+ num = pdf_dev_new_form(ctx, &form_ref, pdev, bbox, isolated, knockout, alpha, cs);
/* Do we have an appropriate blending extgstate already? */
{
diff --git a/source/pdf/pdf-op-run.c b/source/pdf/pdf-op-run.c
index 2e6d9cac..56c84cd9 100644
--- a/source/pdf/pdf-op-run.c
+++ b/source/pdf/pdf-op-run.c
@@ -13,7 +13,7 @@
typedef struct pdf_material_s pdf_material;
typedef struct pdf_run_processor_s pdf_run_processor;
-static void pdf_run_xobject(fz_context *ctx, pdf_run_processor *proc, pdf_xobject *xobj, pdf_obj *page_resources, const fz_matrix *transform);
+static void pdf_run_xobject(fz_context *ctx, pdf_run_processor *proc, pdf_xobject *xobj, pdf_obj *page_resources, const fz_matrix *transform, int is_smask);
enum
{
@@ -150,7 +150,7 @@ begin_softmask(fz_context *ctx, pdf_run_processor *pr, softmask_save *save)
fz_try(ctx)
{
fz_begin_mask(ctx, pr->dev, &mask_bbox, gstate->luminosity, mask_colorspace, gstate->softmask_bc, &gstate->fill.color_params);
- pdf_run_xobject(ctx, pr, softmask, save->page_resources, &fz_identity);
+ pdf_run_xobject(ctx, pr, softmask, save->page_resources, &fz_identity, 1);
}
fz_always(ctx)
fz_drop_colorspace(ctx, mask_colorspace);
@@ -193,7 +193,7 @@ pdf_begin_group(fz_context *ctx, pdf_run_processor *pr, const fz_rect *bbox, sof
pdf_gstate *gstate = begin_softmask(ctx, pr, softmask);
if (gstate->blendmode)
- fz_begin_group(ctx, pr->dev, bbox, 1, 0, gstate->blendmode, 1);
+ fz_begin_group(ctx, pr->dev, bbox, NULL, 1, 0, gstate->blendmode, 1);
return pr->gstate + pr->gtop;
}
@@ -527,7 +527,7 @@ pdf_show_image(fz_context *ctx, pdf_run_processor *pr, fz_image *image)
{
/* apply blend group even though we skip the soft mask */
if (gstate->blendmode)
- fz_begin_group(ctx, pr->dev, &bbox, 0, 0, gstate->blendmode, 1);
+ fz_begin_group(ctx, pr->dev, &bbox, NULL, 0, 0, gstate->blendmode, 1);
fz_clip_image_mask(ctx, pr->dev, image->mask, &image_ctm, &bbox);
}
else
@@ -635,7 +635,7 @@ pdf_show_path(fz_context *ctx, pdf_run_processor *pr, int doclose, int dofill, i
else
{
knockout_group = 1;
- fz_begin_group(ctx, pr->dev, &bbox, 0, 1, FZ_BLEND_NORMAL, 1);
+ fz_begin_group(ctx, pr->dev, &bbox, NULL, 0, 1, FZ_BLEND_NORMAL, 1);
}
}
@@ -780,7 +780,7 @@ pdf_flush_text(fz_context *ctx, pdf_run_processor *pr)
else
{
knockout_group = 1;
- fz_begin_group(ctx, pr->dev, &tb, 0, 1, FZ_BLEND_NORMAL, 1);
+ fz_begin_group(ctx, pr->dev, &tb, NULL, 0, 1, FZ_BLEND_NORMAL, 1);
}
}
@@ -1197,7 +1197,7 @@ pdf_set_pattern(fz_context *ctx, pdf_run_processor *pr, int what, pdf_pattern *p
}
static void
-pdf_run_xobject(fz_context *ctx, pdf_run_processor *proc, pdf_xobject *xobj, pdf_obj *page_resources, const fz_matrix *transform)
+pdf_run_xobject(fz_context *ctx, pdf_run_processor *proc, pdf_xobject *xobj, pdf_obj *page_resources, const fz_matrix *transform, int is_smask)
{
pdf_run_processor *pr = (pdf_run_processor *)proc;
pdf_gstate *gstate = NULL;
@@ -1262,7 +1262,8 @@ pdf_run_xobject(fz_context *ctx, pdf_run_processor *proc, pdf_xobject *xobj, pdf
* if it throws an error, we must call fz_end_group. */
cleanup_state = 2;
fz_begin_group(ctx, pr->dev, &bbox,
- pdf_xobject_isolated(ctx, xobj),
+ pdf_xobject_colorspace(ctx, xobj),
+ (is_smask ? 1 : pdf_xobject_isolated(ctx, xobj)),
pdf_xobject_knockout(ctx, xobj),
gstate->blendmode, gstate->fill.alpha);
@@ -1983,7 +1984,7 @@ static void pdf_run_Do_image(fz_context *ctx, pdf_processor *proc, const char *n
static void pdf_run_Do_form(fz_context *ctx, pdf_processor *proc, const char *name, pdf_xobject *xobj, pdf_obj *page_resources)
{
- pdf_run_xobject(ctx, (pdf_run_processor*)proc, xobj, page_resources, &fz_identity);
+ pdf_run_xobject(ctx, (pdf_run_processor*)proc, xobj, page_resources, &fz_identity, 0);
}
/* marked content */
diff --git a/source/pdf/pdf-page.c b/source/pdf/pdf-page.c
index 0a7f968e..1830409a 100644
--- a/source/pdf/pdf-page.c
+++ b/source/pdf/pdf-page.c
@@ -562,6 +562,12 @@ pdf_page_contents(fz_context *ctx, pdf_page *page)
return pdf_dict_get(ctx, page->obj, PDF_NAME_Contents);
}
+pdf_obj *
+pdf_page_group(fz_context *ctx, pdf_page *page)
+{
+ return pdf_dict_get(ctx, page->obj, PDF_NAME_Group);
+}
+
void
pdf_page_obj_transform(fz_context *ctx, pdf_obj *pageobj, fz_rect *page_mediabox, fz_matrix *page_ctm)
{
diff --git a/source/pdf/pdf-run.c b/source/pdf/pdf-run.c
index 14dc4ed0..1d823277 100644
--- a/source/pdf/pdf-run.c
+++ b/source/pdf/pdf-run.c
@@ -51,7 +51,27 @@ pdf_run_page_contents_with_usage(fz_context *ctx, pdf_document *doc, pdf_page *p
contents = pdf_page_contents(ctx, page);
if (page->transparency)
- fz_begin_group(ctx, dev, fz_transform_rect(&mediabox, &local_ctm), 1, 0, 0, 1);
+ {
+ fz_colorspace *colorspace = NULL;
+ pdf_obj *group = pdf_page_group(ctx, page);
+
+ if (group)
+ {
+ pdf_obj *cs = pdf_dict_get(ctx, group, PDF_NAME_CS);
+ if (cs)
+ {
+ fz_try(ctx)
+ {
+ colorspace = pdf_load_colorspace(ctx, cs);
+ }
+ fz_catch(ctx)
+ {
+ colorspace = NULL;
+ }
+ }
+ }
+ fz_begin_group(ctx, dev, fz_transform_rect(&mediabox, &local_ctm), colorspace, 1, 0, 0, 1);
+ }
proc = pdf_new_run_processor(ctx, dev, &local_ctm, usage, NULL, 0);
fz_try(ctx)
diff --git a/source/tools/murun.c b/source/tools/murun.c
index 5e627295..ec9a93e3 100644
--- a/source/tools/murun.c
+++ b/source/tools/murun.c
@@ -1067,7 +1067,7 @@ js_dev_end_mask(fz_context *ctx, fz_device *dev)
static void
js_dev_begin_group(fz_context *ctx, fz_device *dev, const fz_rect *bbox,
- int isolated, int knockout, int blendmode, float alpha)
+ fz_colorspace *cs, int isolated, int knockout, int blendmode, float alpha)
{
js_State *J = ((js_device*)dev)->J;
if (js_try(J))
@@ -1404,7 +1404,7 @@ static void ffi_Device_beginGroup(js_State *J)
int blendmode = fz_lookup_blendmode(js_tostring(J, 4));
float alpha = js_tonumber(J, 5);
fz_try(ctx)
- fz_begin_group(ctx, dev, &area, isolated, knockout, blendmode, alpha);
+ fz_begin_group(ctx, dev, &area, NULL, isolated, knockout, blendmode, alpha);
fz_catch(ctx)
rethrow(J);
}