static int is_rgb_color(float threshold, float r, float g, float b) { float rg_diff = fz_abs(r - g); float rb_diff = fz_abs(r - b); float gb_diff = fz_abs(g - b); return rg_diff > threshold || rb_diff > threshold || gb_diff > threshold; }
static void fz_dash_bezier(struct sctx *s, float xa, float ya, float xb, float yb, float xc, float yc, float xd, float yd, int depth, int dash_cap) { float dmax; float xab, yab; float xbc, ybc; float xcd, ycd; float xabc, yabc; float xbcd, ybcd; float xabcd, yabcd; /* termination check */ dmax = fz_abs(xa - xb); dmax = fz_max(dmax, fz_abs(ya - yb)); dmax = fz_max(dmax, fz_abs(xd - xc)); dmax = fz_max(dmax, fz_abs(yd - yc)); if (dmax < s->flatness || depth >= MAX_DEPTH) { fz_point p; p.x = xd; p.y = yd; fz_dash_lineto(s, p, dash_cap, 1); return; } xab = xa + xb; yab = ya + yb; xbc = xb + xc; ybc = yb + yc; xcd = xc + xd; ycd = yc + yd; xabc = xab + xbc; yabc = yab + ybc; xbcd = xbc + xcd; ybcd = ybc + ycd; xabcd = xabc + xbcd; yabcd = yabc + ybcd; xab *= 0.5f; yab *= 0.5f; xbc *= 0.5f; ybc *= 0.5f; xcd *= 0.5f; ycd *= 0.5f; xabc *= 0.25f; yabc *= 0.25f; xbcd *= 0.25f; ybcd *= 0.25f; xabcd *= 0.125f; yabcd *= 0.125f; fz_dash_bezier(s, xa, ya, xab, yab, xabc, yabc, xabcd, yabcd, depth + 1, dash_cap); fz_dash_bezier(s, xabcd, yabcd, xbcd, ybcd, xcd, ycd, xd, yd, depth + 1, dash_cap); }
static void bezier(fz_gel *gel, const fz_matrix *ctm, float flatness, float xa, float ya, float xb, float yb, float xc, float yc, float xd, float yd, int depth) { float dmax; float xab, yab; float xbc, ybc; float xcd, ycd; float xabc, yabc; float xbcd, ybcd; float xabcd, yabcd; /* termination check */ dmax = fz_abs(xa - xb); dmax = fz_max(dmax, fz_abs(ya - yb)); dmax = fz_max(dmax, fz_abs(xd - xc)); dmax = fz_max(dmax, fz_abs(yd - yc)); if (dmax < flatness || depth >= MAX_DEPTH) { line(gel, ctm, xa, ya, xd, yd); return; } xab = xa + xb; yab = ya + yb; xbc = xb + xc; ybc = yb + yc; xcd = xc + xd; ycd = yc + yd; xabc = xab + xbc; yabc = yab + ybc; xbcd = xbc + xcd; ybcd = ybc + ycd; xabcd = xabc + xbcd; yabcd = yabc + ybcd; xab *= 0.5f; yab *= 0.5f; xbc *= 0.5f; ybc *= 0.5f; xcd *= 0.5f; ycd *= 0.5f; xabc *= 0.25f; yabc *= 0.25f; xbcd *= 0.25f; ybcd *= 0.25f; xabcd *= 0.125f; yabcd *= 0.125f; bezier(gel, ctm, flatness, xa, ya, xab, yab, xabc, yabc, xabcd, yabcd, depth + 1); bezier(gel, ctm, flatness, xabcd, yabcd, xbcd, ybcd, xcd, ycd, xd, yd, depth + 1); }
int fz_highlight_selection(fz_context *ctx, fz_stext_page *page, fz_rect rect, fz_rect *hit_bbox, int hit_max) { fz_rect linebox, charbox; fz_stext_block *block; fz_stext_line *line; fz_stext_span *span; int i, block_num, hit_count; float x0 = rect.x0; float x1 = rect.x1; float y0 = rect.y0; float y1 = rect.y1; hit_count = 0; for (block_num = 0; block_num < page->len; block_num++) { if (page->blocks[block_num].type != FZ_PAGE_BLOCK_TEXT) continue; block = page->blocks[block_num].u.text; for (line = block->lines; line < block->lines + block->len; line++) { linebox = fz_empty_rect; for (span = line->first_span; span; span = span->next) { for (i = 0; i < span->len; i++) { fz_stext_char_bbox(ctx, &charbox, span, i); if (charbox.x1 >= x0 && charbox.x0 <= x1 && charbox.y1 >= y0 && charbox.y0 <= y1) { if (charbox.y0 != linebox.y0 || fz_abs(charbox.x0 - linebox.x1) > 5) { if (!fz_is_empty_rect(&linebox) && hit_count < hit_max) hit_bbox[hit_count++] = linebox; linebox = charbox; } else { fz_union_rect(&linebox, &charbox); } } } } if (!fz_is_empty_rect(&linebox) && hit_count < hit_max) hit_bbox[hit_count++] = linebox; } } return hit_count; }
int fz_highlight_selection(fz_context *ctx, fz_text_page *page, fz_rect rect, fz_rect *hit_bbox, int hit_max) { fz_rect linebox, charbox; fz_text_block *block; fz_text_line *line; int i, hit_count; float x0 = rect.x0; float x1 = rect.x1; float y0 = rect.y0; float y1 = rect.y1; hit_count = 0; for (block = page->blocks; block < page->blocks + page->len; block++) { for (line = block->lines; line < block->lines + block->len; line++) { int span_num; linebox = fz_empty_rect; for (span_num = 0; span_num < line->len; span_num++) { fz_text_span *span = line->spans[span_num]; for (i = 0; i < span->len; i++) { fz_text_char_bbox(&charbox, span, i); if (charbox.x1 >= x0 && charbox.x0 <= x1 && charbox.y1 >= y0 && charbox.y0 <= y1) { if (charbox.y0 != linebox.y0 || fz_abs(charbox.x0 - linebox.x1) > 5) { if (!fz_is_empty_rect(&linebox) && hit_count < hit_max) hit_bbox[hit_count++] = linebox; linebox = charbox; } else { fz_union_rect(&linebox, &charbox); } } } } if (!fz_is_empty_rect(&linebox) && hit_count < hit_max) hit_bbox[hit_count++] = linebox; } } return hit_count; }
int fz_highlight_selection(fz_context *ctx, fz_stext_page *page, fz_rect rect, fz_rect *hit_bbox, int hit_max) { fz_rect linebox, charbox; fz_stext_block *block; fz_stext_line *line; fz_stext_char *ch; int hit_count; float x0 = rect.x0; float x1 = rect.x1; float y0 = rect.y0; float y1 = rect.y1; hit_count = 0; for (block = page->first_block; block; block = block->next) { if (block->type != FZ_STEXT_BLOCK_TEXT) continue; for (line = block->u.t.first_line; line; line = line->next) { linebox = fz_empty_rect; for (ch = line->first_char; ch; ch = ch->next) { fz_stext_char_bbox(ctx, &charbox, line, ch); if (charbox.x1 >= x0 && charbox.x0 <= x1 && charbox.y1 >= y0 && charbox.y0 <= y1) { if (charbox.y0 != linebox.y0 || fz_abs(charbox.x0 - linebox.x1) > 5) { if (!fz_is_empty_rect(&linebox) && hit_count < hit_max) hit_bbox[hit_count++] = linebox; linebox = charbox; } else { fz_union_rect(&linebox, &charbox); } } } if (!fz_is_empty_rect(&linebox) && hit_count < hit_max) hit_bbox[hit_count++] = linebox; } } return hit_count; }
int fz_search_stext_page(fz_context *ctx, fz_stext_page *text, const char *needle, fz_rect *hit_bbox, int hit_max) { int pos, len, i, n, hit_count; if (strlen(needle) == 0) return 0; hit_count = 0; len = textlen_stext(ctx, text); pos = 0; while (pos < len) { n = match_stext(ctx, text, needle, pos); if (n) { fz_rect linebox = fz_empty_rect; for (i = 0; i < n; i++) { fz_rect charbox; bboxat(ctx, text, pos + i, &charbox); if (!fz_is_empty_rect(&charbox)) { if (charbox.y0 != linebox.y0 || fz_abs(charbox.x0 - linebox.x1) > 5) { if (!fz_is_empty_rect(&linebox) && hit_count < hit_max) hit_bbox[hit_count++] = linebox; linebox = charbox; } else { fz_union_rect(&linebox, &charbox); } } } if (!fz_is_empty_rect(&linebox) && hit_count < hit_max) hit_bbox[hit_count++] = linebox; pos += n; } else { pos += 1; } } return hit_count; }
static fz_text_block * lookup_block_for_line(fz_context *ctx, fz_text_page *page, fz_text_line *line) { float size = line->len > 0 && line->spans[0].len > 0 ? line->spans[0].style->size : 1; int i; /* SumatraPDF: TODO: tweak heuristic below */ if (page->len > 0) return page->blocks; for (i = 0; i < page->len; i++) { fz_text_block *block = page->blocks + i; float w = block->bbox.x1 - block->bbox.x0; float dx = line->bbox.x0 - block->bbox.x0; float dy = line->bbox.y0 - block->bbox.y1; if (dy > -size * 1.5f && dy < size * PARAGRAPH_DIST) if (line->bbox.x0 <= block->bbox.x1 && line->bbox.x1 >= block->bbox.x0) if (fz_abs(dx) < w / 2) return block; } if (page->len == page->cap) { int new_cap = fz_maxi(16, page->cap * 2); page->blocks = fz_resize_array(ctx, page->blocks, new_cap, sizeof(*page->blocks)); page->cap = new_cap; } page->blocks[page->len].bbox = fz_empty_rect; page->blocks[page->len].len = 0; page->blocks[page->len].cap = 0; page->blocks[page->len].lines = NULL; return &page->blocks[page->len++]; }
static void xps_draw_radial_gradient(fz_context *ctx, xps_document *doc, const fz_matrix *ctm, const fz_rect *area, struct stop *stops, int count, fz_xml *root, int spread) { float x0, y0, r0; float x1, y1, r1; float xrad = 1; float yrad = 1; float invscale; int i, ma = 1; fz_matrix local_ctm = *ctm; fz_matrix inv; fz_rect local_area = *area; char *center_att = fz_xml_att(root, "Center"); char *origin_att = fz_xml_att(root, "GradientOrigin"); char *radius_x_att = fz_xml_att(root, "RadiusX"); char *radius_y_att = fz_xml_att(root, "RadiusY"); x0 = y0 = 0.0; x1 = y1 = 1.0; xrad = 1.0; yrad = 1.0; if (origin_att) xps_parse_point(ctx, doc, origin_att, &x0, &y0); if (center_att) xps_parse_point(ctx, doc, center_att, &x1, &y1); if (radius_x_att) xrad = fz_atof(radius_x_att); if (radius_y_att) yrad = fz_atof(radius_y_att); xrad = fz_max(0.01f, xrad); yrad = fz_max(0.01f, yrad); /* scale the ctm to make ellipses */ if (fz_abs(xrad) > FLT_EPSILON) { fz_pre_scale(&local_ctm, 1, yrad/xrad); } if (yrad != 0.0) { invscale = xrad / yrad; y0 = y0 * invscale; y1 = y1 * invscale; } r0 = 0; r1 = xrad; fz_transform_rect(&local_area, fz_invert_matrix(&inv, &local_ctm)); ma = fz_maxi(ma, ceilf(hypotf(local_area.x0 - x0, local_area.y0 - y0) / xrad)); ma = fz_maxi(ma, ceilf(hypotf(local_area.x1 - x0, local_area.y0 - y0) / xrad)); ma = fz_maxi(ma, ceilf(hypotf(local_area.x0 - x0, local_area.y1 - y0) / xrad)); ma = fz_maxi(ma, ceilf(hypotf(local_area.x1 - x0, local_area.y1 - y0) / xrad)); if (spread == SPREAD_REPEAT) { for (i = ma - 1; i >= 0; i--) xps_draw_one_radial_gradient(ctx, doc, &local_ctm, stops, count, 0, x0, y0, r0 + i * xrad, x1, y1, r1 + i * xrad); } else if (spread == SPREAD_REFLECT) { if ((ma % 2) != 0) ma++; for (i = ma - 2; i >= 0; i -= 2) { xps_draw_one_radial_gradient(ctx, doc, &local_ctm, stops, count, 0, x0, y0, r0 + i * xrad, x1, y1, r1 + i * xrad); xps_draw_one_radial_gradient(ctx, doc, &local_ctm, stops, count, 0, x0, y0, r0 + (i + 2) * xrad, x1, y1, r1 + i * xrad); } } else { xps_draw_one_radial_gradient(ctx, doc, &local_ctm, stops, count, 1, x0, y0, r0, x1, y1, r1); } }
static float vdist(fz_point *dir, fz_point *a, fz_point *b) { float dx = b->x - a->x; float dy = b->y - a->y; return fz_abs(dx * dir->y + dy * dir->x); }
void fz_flatten_dash_path(fz_gel *gel, fz_path *path, fz_stroke_state *stroke, fz_matrix ctm, float flatness, float linewidth) { struct sctx s; fz_point p0, p1, p2, p3, beg; float phase_len, max_expand; int i; s.gel = gel; s.ctm = &ctm; s.flatness = flatness; s.linejoin = stroke->linejoin; s.linewidth = linewidth * 0.5f; s.miterlimit = stroke->miterlimit; s.sn = 0; s.bn = 0; s.dot = 0; s.dash_list = stroke->dash_list; s.dash_phase = stroke->dash_phase; s.dash_len = stroke->dash_len; s.toggle = 0; s.offset = 0; s.phase = 0; s.cap = stroke->start_cap; if (path->len > 0 && path->items[0].k != FZ_MOVETO) return; phase_len = 0; for (i = 0; i < stroke->dash_len; i++) phase_len += stroke->dash_list[i]; max_expand = fz_max(fz_max(fz_abs(ctm.a),fz_abs(ctm.b)),fz_max(fz_abs(ctm.c),fz_abs(ctm.d))); if (phase_len < 0.01f || phase_len * max_expand < 0.5f) { fz_flatten_stroke_path(gel, path, stroke, ctm, flatness, linewidth); return; } p0.x = p0.y = 0; i = 0; while (i < path->len) { switch (path->items[i++].k) { case FZ_MOVETO: p1.x = path->items[i++].v; p1.y = path->items[i++].v; fz_dash_moveto(&s, p1, stroke->start_cap, stroke->end_cap); beg = p0 = p1; break; case FZ_LINETO: p1.x = path->items[i++].v; p1.y = path->items[i++].v; fz_dash_lineto(&s, p1, stroke->dash_cap, 0); p0 = p1; break; case FZ_CURVETO: p1.x = path->items[i++].v; p1.y = path->items[i++].v; p2.x = path->items[i++].v; p2.y = path->items[i++].v; p3.x = path->items[i++].v; p3.y = path->items[i++].v; fz_dash_bezier(&s, p0.x, p0.y, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, 0, stroke->dash_cap); p0 = p3; break; case FZ_CLOSE_PATH: fz_dash_lineto(&s, beg, stroke->dash_cap, 0); p0 = p1 = beg; break; } } fz_stroke_flush(&s, s.cap, stroke->end_cap); }