void xps_parse_tiling_brush(xps_document *doc, const fz_matrix *ctm, const fz_rect *area, char *base_uri, xps_resource *dict, fz_xml *root, void (*func)(xps_document*, const fz_matrix*, const fz_rect*, char*, xps_resource*, fz_xml*, void*), void *user) { fz_xml *node; struct closure c; char *opacity_att; char *transform_att; char *viewbox_att; char *viewport_att; char *tile_mode_att; fz_xml *transform_tag = NULL; fz_matrix transform; fz_rect viewbox; fz_rect viewport; float xstep, ystep; float xscale, yscale; int tile_mode; opacity_att = fz_xml_att(root, "Opacity"); transform_att = fz_xml_att(root, "Transform"); viewbox_att = fz_xml_att(root, "Viewbox"); viewport_att = fz_xml_att(root, "Viewport"); tile_mode_att = fz_xml_att(root, "TileMode"); c.base_uri = base_uri; c.dict = dict; c.root = root; c.user = user; c.func = func; for (node = fz_xml_down(root); node; node = fz_xml_next(node)) { if (!strcmp(fz_xml_tag(node), "ImageBrush.Transform")) transform_tag = fz_xml_down(node); if (!strcmp(fz_xml_tag(node), "VisualBrush.Transform")) transform_tag = fz_xml_down(node); } xps_resolve_resource_reference(doc, dict, &transform_att, &transform_tag, NULL); transform = fz_identity; if (transform_att) xps_parse_render_transform(doc, transform_att, &transform); if (transform_tag) xps_parse_matrix_transform(doc, transform_tag, &transform); fz_concat(&transform, &transform, ctm); viewbox = fz_unit_rect; if (viewbox_att) xps_parse_rectangle(doc, viewbox_att, &viewbox); viewport = fz_unit_rect; if (viewport_att) xps_parse_rectangle(doc, viewport_att, &viewport); if (fabsf(viewport.x1 - viewport.x0) < 0.01f || fabsf(viewport.y1 - viewport.y0) < 0.01f) fz_warn(doc->ctx, "not drawing tile for viewport size %.4f x %.4f", viewport.x1 - viewport.x0, viewport.y1 - viewport.y0); else if (fabsf(viewbox.x1 - viewbox.x0) < 0.01f || fabsf(viewbox.y1 - viewbox.y0) < 0.01f) fz_warn(doc->ctx, "not drawing tile for viewbox size %.4f x %.4f", viewbox.x1 - viewbox.x0, viewbox.y1 - viewbox.y0); /* some sanity checks on the viewport/viewbox size */ if (fabsf(viewport.x1 - viewport.x0) < 0.01f) return; if (fabsf(viewport.y1 - viewport.y0) < 0.01f) return; if (fabsf(viewbox.x1 - viewbox.x0) < 0.01f) return; if (fabsf(viewbox.y1 - viewbox.y0) < 0.01f) return; xstep = viewbox.x1 - viewbox.x0; ystep = viewbox.y1 - viewbox.y0; xscale = (viewport.x1 - viewport.x0) / xstep; yscale = (viewport.y1 - viewport.y0) / ystep; tile_mode = TILE_NONE; if (tile_mode_att) { if (!strcmp(tile_mode_att, "None")) tile_mode = TILE_NONE; if (!strcmp(tile_mode_att, "Tile")) tile_mode = TILE_TILE; if (!strcmp(tile_mode_att, "FlipX")) tile_mode = TILE_FLIP_X; if (!strcmp(tile_mode_att, "FlipY")) tile_mode = TILE_FLIP_Y; if (!strcmp(tile_mode_att, "FlipXY")) tile_mode = TILE_FLIP_X_Y; } if (tile_mode == TILE_FLIP_X || tile_mode == TILE_FLIP_X_Y) xstep *= 2; if (tile_mode == TILE_FLIP_Y || tile_mode == TILE_FLIP_X_Y) ystep *= 2; xps_begin_opacity(doc, &transform, area, base_uri, dict, opacity_att, NULL); fz_pre_translate(&transform, viewport.x0, viewport.y0); fz_pre_scale(&transform, xscale, yscale); fz_pre_translate(&transform, -viewbox.x0, -viewbox.y0); if (tile_mode != TILE_NONE) { int x0, y0, x1, y1; fz_matrix invctm; fz_rect local_area = *area; fz_transform_rect(&local_area, fz_invert_matrix(&invctm, &transform)); /* SumatraPDF: make sure that the intended area is covered */ { fz_point tl; fz_irect bbox; fz_rect bigview = viewbox; bigview.x1 = bigview.x0 + xstep; bigview.y1 = bigview.y0 + ystep; fz_irect_from_rect(&bbox, fz_transform_rect(&bigview, &transform)); tl.x = bbox.x0; tl.y = bbox.y0; fz_transform_point(&tl, &invctm); local_area.x0 -= fz_max(tl.x, 0) - 0.001f; local_area.y0 -= fz_max(tl.y, 0) - 0.001f; local_area.x1 += xstep - fz_max(tl.x, 0) - 0.001f; local_area.y1 += ystep - fz_max(tl.y, 0) - 0.001f; } x0 = floorf(local_area.x0 / xstep); y0 = floorf(local_area.y0 / ystep); x1 = ceilf(local_area.x1 / xstep); y1 = ceilf(local_area.y1 / ystep); #ifdef TILE /* cf. http://code.google.com/p/sumatrapdf/issues/detail?id=2248 */ if ((local_area.x1 - local_area.x0) / xstep > 1 || (local_area.y1 - local_area.y0) / ystep > 1) #else if (0) #endif { fz_rect bigview = viewbox; bigview.x1 = bigview.x0 + xstep; bigview.y1 = bigview.y0 + ystep; fz_begin_tile(doc->dev, &local_area, &bigview, xstep, ystep, &transform); xps_paint_tiling_brush(doc, &transform, &viewbox, tile_mode, &c); fz_end_tile(doc->dev); } else { int x, y; for (y = y0; y < y1; y++) { for (x = x0; x < x1; x++) { fz_matrix ttm = transform; fz_pre_translate(&ttm, xstep * x, ystep * y); xps_paint_tiling_brush(doc, &ttm, &viewbox, tile_mode, &c); } } } } else { xps_paint_tiling_brush(doc, &transform, &viewbox, tile_mode, &c); } xps_end_opacity(doc, base_uri, dict, opacity_att, NULL); }
void do_widget_canvas(fz_irect canvas_area) { pdf_widget *widget; fz_rect bounds; fz_irect area; if (!pdf) return; for (widget = pdf_first_widget(ctx, page); widget; widget = pdf_next_widget(ctx, widget)) { bounds = pdf_bound_widget(ctx, widget); bounds = fz_transform_rect(bounds, view_page_ctm); area = fz_irect_from_rect(bounds); if (ui_mouse_inside(&canvas_area) && ui_mouse_inside(&area)) { if (!widget->is_hot) pdf_annot_event_enter(ctx, widget); widget->is_hot = 1; ui.hot = widget; if (!ui.active && ui.down) { ui.active = widget; pdf_annot_event_down(ctx, widget); if (selected_annot != widget) { if (selected_annot && pdf_annot_type(ctx, selected_annot) == PDF_ANNOT_WIDGET) pdf_annot_event_blur(ctx, selected_annot); selected_annot = widget; pdf_annot_event_focus(ctx, widget); } } } else { if (widget->is_hot) pdf_annot_event_exit(ctx, widget); widget->is_hot = 0; } /* Set is_hot and is_active to select current appearance */ widget->is_active = (ui.active == widget && ui.down); if (showform) { glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); glColor4f(0, 0, 1, 0.1f); glRectf(area.x0, area.y0, area.x1, area.y1); glDisable(GL_BLEND); } if (ui.active == widget || (!ui.active && ui.hot == widget)) { glLineStipple(1, 0xAAAA); glEnable(GL_LINE_STIPPLE); glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO); glEnable(GL_BLEND); glColor4f(1, 1, 1, 1); glBegin(GL_LINE_LOOP); glVertex2f(area.x0-0.5f, area.y0-0.5f); glVertex2f(area.x1+0.5f, area.y0-0.5f); glVertex2f(area.x1+0.5f, area.y1+0.5f); glVertex2f(area.x0-0.5f, area.y1+0.5f); glEnd(); glDisable(GL_BLEND); glDisable(GL_LINE_STIPPLE); } if (ui.hot == widget && ui.active == widget && !ui.down) { pdf_annot_event_up(ctx, widget); if (pdf_field_flags(ctx, widget->obj) & PDF_FIELD_IS_READ_ONLY) continue; switch (pdf_widget_type(ctx, widget)) { default: break; case PDF_WIDGET_TYPE_CHECKBOX: case PDF_WIDGET_TYPE_RADIOBUTTON: pdf_toggle_widget(ctx, widget); break; case PDF_WIDGET_TYPE_TEXT: show_tx_dialog(widget); break; case PDF_WIDGET_TYPE_COMBOBOX: case PDF_WIDGET_TYPE_LISTBOX: ui.dialog = ch_dialog; ch_widget = widget; break; case PDF_WIDGET_TYPE_SIGNATURE: show_sig_dialog(widget); break; } } } if (pdf_update_page(ctx, page)) render_page(); }
static void fz_paint_image_imp(fz_pixmap *dst, const fz_irect *scissor, fz_pixmap *shape, fz_pixmap *img, const fz_matrix *ctm, byte *color, int alpha) { byte *dp, *sp, *hp; int u, v, fa, fb, fc, fd; int x, y, w, h; int sw, sh, n, hw; fz_irect bbox; int dolerp; void (*paintfn)(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, int alpha, byte *color, byte *hp); fz_matrix local_ctm = *ctm; fz_rect rect; /* grid fit the image */ fz_gridfit_matrix(&local_ctm); /* turn on interpolation for upscaled and non-rectilinear transforms */ dolerp = 0; if (!fz_is_rectilinear(&local_ctm)) dolerp = 1; if (sqrtf(local_ctm.a * local_ctm.a + local_ctm.b * local_ctm.b) > img->w) dolerp = 1; if (sqrtf(local_ctm.c * local_ctm.c + local_ctm.d * local_ctm.d) > img->h) dolerp = 1; /* except when we shouldn't, at large magnifications */ if (!img->interpolate) { if (sqrtf(local_ctm.a * local_ctm.a + local_ctm.b * local_ctm.b) > img->w * 2) dolerp = 0; if (sqrtf(local_ctm.c * local_ctm.c + local_ctm.d * local_ctm.d) > img->h * 2) dolerp = 0; } rect = fz_unit_rect; fz_irect_from_rect(&bbox, fz_transform_rect(&rect, &local_ctm)); fz_intersect_irect(&bbox, scissor); x = bbox.x0; if (shape && shape->x > x) x = shape->x; y = bbox.y0; if (shape && shape->y > y) y = shape->y; w = bbox.x1; if (shape && shape->x + shape->w < w) w = shape->x + shape->w; w -= x; h = bbox.y1; if (shape && shape->y + shape->h < h) h = shape->y + shape->h; h -= y; if (w < 0 || h < 0) return; /* map from screen space (x,y) to image space (u,v) */ fz_pre_scale(&local_ctm, 1.0f / img->w, 1.0f / img->h); fz_invert_matrix(&local_ctm, &local_ctm); fa = (int)(local_ctm.a *= 65536.0f); fb = (int)(local_ctm.b *= 65536.0f); fc = (int)(local_ctm.c *= 65536.0f); fd = (int)(local_ctm.d *= 65536.0f); local_ctm.e *= 65536.0f; local_ctm.f *= 65536.0f; /* Calculate initial texture positions. Do a half step to start. */ /* Bug 693021: Keep calculation in float for as long as possible to * avoid overflow. */ u = (int)((local_ctm.a * x) + (local_ctm.c * y) + local_ctm.e + ((local_ctm.a + local_ctm.c) * .5f)); v = (int)((local_ctm.b * x) + (local_ctm.d * y) + local_ctm.f + ((local_ctm.b + local_ctm.d) * .5f)); /* RJW: The following is voodoo. No idea why it works, but it gives * the best match between scaled/unscaled/interpolated/non-interpolated * that we have found. */ if (dolerp) { u -= 32768; v -= 32768; } dp = dst->samples + (unsigned int)(((y - dst->y) * dst->w + (x - dst->x)) * dst->n); n = dst->n; sp = img->samples; sw = img->w; sh = img->h; if (shape) { hw = shape->w; hp = shape->samples + (unsigned int)(((y - shape->y) * hw) + x - shape->x); } else { hw = 0; hp = NULL; } /* TODO: if (fb == 0 && fa == 1) call fz_paint_span */ if (dst->n == 4 && img->n == 2) { assert(!color); if (dolerp) paintfn = fz_paint_affine_g2rgb_lerp; else paintfn = fz_paint_affine_g2rgb_near; } else { if (dolerp) { if (color) paintfn = fz_paint_affine_color_lerp; else paintfn = fz_paint_affine_lerp; } else { if (color) paintfn = fz_paint_affine_color_near; else paintfn = fz_paint_affine_near; } } while (h--) { paintfn(dp, sp, sw, sh, u, v, fa, fb, w, n, alpha, color, hp); dp += dst->w * n; hp += hw; u += fc; v += fd; } }