fz_rect fz_intersect_rect(fz_rect a, fz_rect b) { fz_rect r; /* Check for empty box before infinite box */ if (fz_is_empty_rect(a)) return fz_empty_rect; if (fz_is_empty_rect(b)) return fz_empty_rect; if (fz_is_infinite_rect(a)) return b; if (fz_is_infinite_rect(b)) return a; r.x0 = fz_max(a.x0, b.x0); r.y0 = fz_max(a.y0, b.y0); r.x1 = fz_min(a.x1, b.x1); r.y1 = fz_min(a.y1, b.y1); return (r.x1 < r.x0 || r.y1 < r.y0) ? fz_empty_rect : r; }
static void region_mask_merge(region_mask *rm1, const region_mask *rm2, int newlen) { int o, i1, i2; /* First, ensure that rm1 is long enough */ if (rm1->cap < newlen) { int newcap = rm1->cap ? rm1->cap : 2; do { newcap *= 2; } while (newcap < newlen); rm1->mask = fz_resize_array(rm1->ctx, rm1->mask, newcap, sizeof(*rm1->mask)); rm1->cap = newcap; } /* Now run backwards along rm1, filling it out with the merged regions */ for (o = newlen-1, i1 = rm1->len-1, i2 = rm2->len-1; o >= 0; o--) { /* So we read from i1 and i2 and store in o */ if (i1 < 0) { /* Just copy i2 */ rm1->mask[o] = rm2->mask[i2]; i2--; } else if (i2 < 0) { /* Just copy i1 */ rm1->mask[o] = rm1->mask[i1]; i1--; } else if (rm1->mask[i1].stop < rm2->mask[i2].start) { /* rm1's region is entirely before rm2's - copy rm2's */ rm1->mask[o] = rm2->mask[i2]; i2--; } else if (rm2->mask[i2].stop < rm1->mask[i1].start) { /* rm2's region is entirely before rm1's - copy rm1's */ rm1->mask[o] = rm1->mask[i1]; i1--; } else { /* We must be merging */ rm1->mask[o].ave_start = (rm1->mask[i1].start * rm1->freq + rm2->mask[i2].start * rm2->freq)/(rm1->freq + rm2->freq); rm1->mask[o].ave_stop = (rm1->mask[i1].stop * rm1->freq + rm2->mask[i2].stop * rm2->freq)/(rm1->freq + rm2->freq); rm1->mask[o].start = fz_min(rm1->mask[i1].start, rm2->mask[i2].start); rm1->mask[o].stop = fz_max(rm1->mask[i1].stop, rm2->mask[i2].stop); i1--; i2--; } } rm1->freq += rm2->freq; rm1->len = newlen; }
fz_rect fz_bound_text(fz_context *ctx, fz_text *text, fz_matrix ctm) { fz_matrix tm, trm; fz_rect bbox; fz_rect gbox; int i; if (text->len == 0) return fz_empty_rect; // TODO: stroke state tm = text->trm; tm.e = text->items[0].x; tm.f = text->items[0].y; trm = fz_concat(tm, ctm); bbox = fz_bound_glyph(ctx, text->font, text->items[0].gid, trm); for (i = 1; i < text->len; i++) { if (text->items[i].gid >= 0) { tm.e = text->items[i].x; tm.f = text->items[i].y; trm = fz_concat(tm, ctm); gbox = fz_bound_glyph(ctx, text->font, text->items[i].gid, trm); bbox.x0 = fz_min(bbox.x0, gbox.x0); bbox.y0 = fz_min(bbox.y0, gbox.y0); bbox.x1 = fz_max(bbox.x1, gbox.x1); bbox.y1 = fz_max(bbox.y1, gbox.y1); } } /* Compensate for the glyph cache limited positioning precision */ bbox.x0 -= 1; bbox.y0 -= 1; bbox.x1 += 1; bbox.y1 += 1; return bbox; }
static void measure_image(fz_context *ctx, fz_html_flow *node, float max_w, float max_h) { float xs = 1, ys = 1, s = 1; node->x = 0; node->y = 0; if (node->content.image->w > max_w) xs = max_w / node->content.image->w; if (node->content.image->h > max_h) ys = max_h / node->content.image->h; s = fz_min(xs, ys); node->w = node->content.image->w * s; node->h = node->content.image->h * s; }
static void measure_image(fz_context *ctx, fz_html_flow *node, float w, float h) { float xs = 1, ys = 1, s = 1; node->x = 0; node->y = 0; if (node->image->w > w) xs = w / node->image->w; if (node->image->h > h) ys = h / node->image->h; s = fz_min(xs, ys); node->w = node->image->w * s; node->h = node->image->h * s; }
static void pdf_write_line_appearance(fz_context *ctx, pdf_annot *annot, fz_buffer *buf, fz_rect *rect) { pdf_obj *line, *le; fz_point a, b; float w; int ic; w = pdf_write_border_appearance(ctx, annot, buf); pdf_write_stroke_color_appearance(ctx, annot, buf); ic = pdf_write_interior_fill_color_appearance(ctx, annot, buf); line = pdf_dict_get(ctx, annot->obj, PDF_NAME(L)); a.x = pdf_array_get_real(ctx, line, 0); a.y = pdf_array_get_real(ctx, line, 1); b.x = pdf_array_get_real(ctx, line, 2); b.y = pdf_array_get_real(ctx, line, 3); fz_append_printf(ctx, buf, "%g %g m\n%g %g l\nS\n", a.x, a.y, b.x, b.y); rect->x0 = fz_min(a.x, b.x); rect->y0 = fz_min(a.y, b.y); rect->x1 = fz_max(a.x, b.x); rect->y1 = fz_max(a.y, b.y); le = pdf_dict_get(ctx, annot->obj, PDF_NAME(LE)); if (pdf_array_len(ctx, le) == 2) { float dx = b.x - a.x; float dy = b.y - a.y; float l = sqrtf(dx*dx + dy*dy); pdf_write_line_cap_appearance(ctx, buf, rect, a.x, a.y, dx/l, dy/l, w, ic, pdf_array_get(ctx, le, 0)); pdf_write_line_cap_appearance(ctx, buf, rect, b.x, b.y, -dx/l, -dy/l, w, ic, pdf_array_get(ctx, le, 1)); } *rect = fz_expand_rect(*rect, fz_max(1, w)); }
static void union_quad(fz_rect *rect, const fz_point quad[4], float lw) { fz_rect qbox; qbox.x0 = fz_min(fz_min(quad[0].x, quad[1].x), fz_min(quad[2].x, quad[3].x)); qbox.y0 = fz_min(fz_min(quad[0].y, quad[1].y), fz_min(quad[2].y, quad[3].y)); qbox.x1 = fz_max(fz_max(quad[0].x, quad[1].x), fz_max(quad[2].x, quad[3].x)); qbox.y1 = fz_max(fz_max(quad[0].y, quad[1].y), fz_max(quad[2].y, quad[3].y)); *rect = fz_union_rect(*rect, fz_expand_rect(qbox, lw)); }
static int make_fake_doc(pdfapp_t *app) { fz_context *ctx = app->ctx; pdf_document *pdf = NULL; fz_buffer *contents = NULL; pdf_obj *page_obj = NULL; fz_var(contents); fz_var(page_obj); fz_try(ctx) { fz_rect mediabox = { 0, 0, app->winw, app->winh }; int i; pdf = pdf_create_document(ctx); contents = fz_new_buffer(ctx, 100); fz_append_printf(ctx, contents, "1 0 0 RG %g w 0 0 m %g %g l 0 %g m %g 0 l s\n", fz_min(mediabox.x1, mediabox.y1) / 20, mediabox.x1, mediabox.y1, mediabox.y1, mediabox.x1); /* Create enough copies of our blank(ish) page so that the * page number is preserved if and when a subsequent load * works. */ page_obj = pdf_add_page(ctx, pdf, &mediabox, 0, NULL, contents); for (i = 0; i < app->pagecount; i++) pdf_insert_page(ctx, pdf, -1, page_obj); } fz_always(ctx) { pdf_drop_obj(ctx, page_obj); fz_drop_buffer(ctx, contents); } fz_catch(ctx) { fz_drop_document(ctx, (fz_document *) pdf); return 1; } app->doc = (fz_document*)pdf; return 0; }
static int make_fake_doc(pdfapp_t *app) { fz_context *ctx = app->ctx; pdf_document *pdf = NULL; fz_buffer *contents = NULL; fz_try(ctx) { fz_rect mediabox = { 0, 0, app->winw, app->winh }; pdf_obj *page_obj; int i; contents = fz_new_buffer(ctx, 100); pdf = pdf_create_document(ctx); app->doc = (fz_document*)pdf; fz_buffer_printf(ctx, contents, "1 0 0 rg %f w 0 0 m %f %f l 0 %f m %f 0 l\n", fz_min(mediabox.x1, mediabox.y1) / 4, mediabox.x1, mediabox.y1, mediabox.y1, mediabox.x1); /* Create enough copies of our blank(ish) page so that the * page number is preserved if and when a subsequent load * works. */ page_obj = pdf_add_page(ctx, pdf, &mediabox, 0, contents, NULL); for (i = 0; i < app->pagecount; i++) pdf_insert_page(ctx, pdf, -1, page_obj); pdf_drop_obj(ctx, page_obj); } fz_always(ctx) { fz_drop_buffer(ctx, contents); } fz_catch(ctx) { fz_rethrow(ctx); } return 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; }
static void cmyk_to_rgb(fz_context *ctx, fz_colorspace *cs, const float *cmyk, float *rgb) { #ifdef SLOWCMYK /* from poppler */ float c = cmyk[0], m = cmyk[1], y = cmyk[2], k = cmyk[3]; float r, g, b, x; float cm = c * m; float c1m = m - cm; float cm1 = c - cm; float c1m1 = 1 - m - cm1; float c1m1y = c1m1 * y; float c1m1y1 = c1m1 - c1m1y; float c1my = c1m * y; float c1my1 = c1m - c1my; float cm1y = cm1 * y; float cm1y1 = cm1 - cm1y; float cmy = cm * y; float cmy1 = cm - cmy; /* this is a matrix multiplication, unrolled for performance */ x = c1m1y1 * k; /* 0 0 0 1 */ r = g = b = c1m1y1 - x; /* 0 0 0 0 */ r += 0.1373 * x; g += 0.1216 * x; b += 0.1255 * x; x = c1m1y * k; /* 0 0 1 1 */ r += 0.1098 * x; g += 0.1020 * x; x = c1m1y - x; /* 0 0 1 0 */ r += x; g += 0.9490 * x; x = c1my1 * k; /* 0 1 0 1 */ r += 0.1412 * x; x = c1my1 - x; /* 0 1 0 0 */ r += 0.9255 * x; b += 0.5490 * x; x = c1my * k; /* 0 1 1 1 */ r += 0.1333 * x; x = c1my - x; /* 0 1 1 0 */ r += 0.9294 * x; g += 0.1098 * x; b += 0.1412 * x; x = cm1y1 * k; /* 1 0 0 1 */ g += 0.0588 * x; b += 0.1412 * x; x = cm1y1 - x; /* 1 0 0 0 */ g += 0.6784 * x; b += 0.9373 * x; x = cm1y * k; /* 1 0 1 1 */ g += 0.0745 * x; x = cm1y - x; /* 1 0 1 0 */ g += 0.6510 * x; b += 0.3137 * x; x = cmy1 * k; /* 1 1 0 1 */ b += 0.0078 * x; x = cmy1 - x; /* 1 1 0 0 */ r += 0.1804 * x; g += 0.1922 * x; b += 0.5725 * x; x = cmy * (1-k); /* 1 1 1 0 */ r += 0.2118 * x; g += 0.2119 * x; b += 0.2235 * x; rgb[0] = fz_clamp(r, 0, 1); rgb[1] = fz_clamp(g, 0, 1); rgb[2] = fz_clamp(b, 0, 1); #else rgb[0] = 1 - fz_min(1, cmyk[0] + cmyk[3]); rgb[1] = 1 - fz_min(1, cmyk[1] + cmyk[3]); rgb[2] = 1 - fz_min(1, cmyk[2] + cmyk[3]); #endif }
pdf_page * pdf_create_page(pdf_document *doc, fz_rect mediabox, int res, int rotate) { pdf_page *page = NULL; pdf_obj *pageobj, *obj; float userunit = 1; fz_context *ctx = doc->ctx; fz_matrix ctm, tmp; fz_rect realbox; page = fz_malloc_struct(ctx, pdf_page); obj = NULL; fz_var(obj); fz_try(ctx) { page->resources = NULL; page->contents = NULL; page->transparency = 0; page->links = NULL; page->annots = NULL; page->me = pageobj = pdf_new_dict(doc, 4); pdf_dict_puts_drop(pageobj, "Type", pdf_new_name(doc, "Page")); 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; pdf_dict_puts_drop(pageobj, "MediaBox", pdf_new_rect(doc, &page->mediabox)); /* 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; pdf_dict_puts_drop(pageobj, "Rotate", pdf_new_int(doc, page->rotate)); fz_pre_rotate(fz_scale(&ctm, 1, -1), -page->rotate); realbox = page->mediabox; fz_transform_rect(&realbox, &ctm); fz_pre_scale(fz_translate(&tmp, -realbox.x0, -realbox.y0), userunit, userunit); fz_concat(&ctm, &ctm, &tmp); page->ctm = ctm; obj = pdf_new_dict(doc, 4); page->contents = pdf_new_ref(doc, obj); pdf_drop_obj(obj); obj = NULL; pdf_dict_puts(pageobj, "Contents", page->contents); } fz_catch(ctx) { pdf_drop_obj(page->me); pdf_drop_obj(obj); fz_free(ctx, page); fz_rethrow_message(ctx, "Failed to create page"); } return page; }
static int make_fake_doc(pdfapp_t *app) { fz_context *ctx = app->ctx; fz_matrix ctm = { 1, 0, 0, 1, 0, 0 }; fz_rect bounds; pdf_page *newpage = NULL; pdf_document *pdf = NULL; fz_device *dev = NULL; fz_path *path = NULL; fz_stroke_state stroke = fz_default_stroke_state; float red[3] = { 1, 0, 0 }; int i; fz_var(pdf); fz_var(dev); fz_var(newpage); fz_try(ctx) { pdf = pdf_create_document(ctx); app->doc = &pdf->super; bounds.x0 = 0; bounds.y0 = 0; bounds.x1 = app->winw; bounds.y1 = app->winh; newpage = pdf_create_page(ctx, pdf, bounds, 72, 0); dev = pdf_page_write(ctx, pdf, newpage); /* Now the page content */ fz_begin_page(ctx, dev, &bounds, &ctm); path = fz_new_path(ctx); fz_moveto(ctx, path, 0, 0); fz_lineto(ctx, path, bounds.x1, bounds.y1); fz_moveto(ctx, path, 0, bounds.y1); fz_lineto(ctx, path, bounds.x1, 0); stroke.linewidth = fz_min(bounds.x1, bounds.y1)/4; fz_stroke_path(ctx, dev, path, &stroke, &ctm, fz_device_rgb(ctx), red, 1); fz_end_page(ctx, dev); fz_drop_device(ctx, dev); dev = NULL; /* Create enough copies of our blank(ish) page so that the * page number is preserved if and when a subsequent load * works. */ for (i = 0; i < app->pagecount; i++) pdf_insert_page(ctx, pdf, newpage, INT_MAX); } fz_always(ctx) { fz_drop_path(ctx, path); pdf_drop_page(ctx, newpage); fz_drop_device(ctx, dev); dev = NULL; } fz_catch(ctx) { fz_rethrow(ctx); } return 0; }
static void fz_text_extract(fz_context *ctx, fz_text_device *dev, fz_text *text, const fz_matrix *ctm, fz_text_style *style) { fz_point *pen = &dev->point; fz_font *font = text->font; FT_Face face = font->ft_face; fz_matrix tm = text->trm; fz_matrix trm; float size; float adv; fz_rect rect; fz_point dir, ndir; fz_point delta, ndelta; float dist, dot; float ascender = 1; float descender = 0; int multi; int i, j, err; if (text->len == 0) return; if (font->ft_face) { fz_lock(ctx, FZ_LOCK_FREETYPE); err = FT_Set_Char_Size(font->ft_face, 64, 64, 72, 72); if (err) fz_warn(ctx, "freetype set character size: %s", ft_error_string(err)); ascender = (float)face->ascender / face->units_per_EM; descender = (float)face->descender / face->units_per_EM; fz_unlock(ctx, FZ_LOCK_FREETYPE); } else if (font->t3procs && !fz_is_empty_rect(&font->bbox)) { ascender = font->bbox.y1; descender = font->bbox.y0; } rect = fz_empty_rect; /* SumatraPDF: TODO: make this depend on the per-glyph displacement vector */ if (text->wmode == 0) { dir.x = 1; dir.y = 0; } else { dir.x = 0; dir.y = 1; } tm.e = 0; tm.f = 0; fz_concat(&trm, &tm, ctm); fz_transform_vector(&dir, &trm); dist = sqrtf(dir.x * dir.x + dir.y * dir.y); ndir.x = dir.x / dist; ndir.y = dir.y / dist; size = fz_matrix_expansion(&trm); for (i = 0; i < text->len; i++) { /* Calculate new pen location and delta */ tm.e = text->items[i].x; tm.f = text->items[i].y; fz_concat(&trm, &tm, ctm); delta.x = pen->x - trm.e; delta.y = pen->y - trm.f; if (pen->x == -1 && pen->y == -1) delta.x = delta.y = 0; dist = sqrtf(delta.x * delta.x + delta.y * delta.y); /* Add space and newlines based on pen movement */ if (dist > 0) { /* SumatraPDF: don't add spaces for large overlapping glyphs */ fz_text_span *last = &dev->cur_span; if (last->len == 0 && dev->cur_line.len > 0) last = &dev->cur_line.spans[dev->cur_line.len - 1]; ndelta.x = delta.x / dist; ndelta.y = delta.y / dist; dot = ndelta.x * ndir.x + ndelta.y * ndir.y; /* SumatraPDF: don't merge multiple lines into one */ if (dist > size * LINE_DIST && hypotf(delta.y * ndir.x, delta.x * ndir.y) > size * 0.5f) { fz_flush_text_line(ctx, dev, style); dev->lastchar = ' '; } else /* SumatraPDF: use 0.95f instead of 0.9995f for slightly better results */ if (fabsf(dot) > 0.95f && dist > size * SPACE_DIST && dist < size * SPACE_MAX_DIST) { if (dev->lastchar != ' ' && /* SumatraPDF: don't add spaces before spaces or for large overlapping glyphs */ text->items[i].ucs != ' ' && !fz_maps_into_rect(trm, last->text[last->len - 1].bbox)) { fz_rect spacerect; spacerect.x0 = -0.2f; spacerect.y0 = descender; spacerect.x1 = 0; spacerect.y1 = ascender; fz_transform_rect(&spacerect, &trm); fz_add_text_char(ctx, dev, style, ' ', spacerect); dev->lastchar = ' '; } } else if (dist > size * LINE_DIST) { fz_flush_text_line(ctx, dev, style); dev->lastchar = ' '; } } /* Calculate bounding box and new pen position based on font metrics */ if (font->ft_face) { FT_Fixed ftadv = 0; int mask = FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING | FT_LOAD_IGNORE_TRANSFORM; /* TODO: freetype returns broken vertical metrics */ /* if (text->wmode) mask |= FT_LOAD_VERTICAL_LAYOUT; */ fz_lock(ctx, FZ_LOCK_FREETYPE); err = FT_Set_Char_Size(font->ft_face, 64, 64, 72, 72); if (err) fz_warn(ctx, "freetype set character size: %s", ft_error_string(err)); FT_Get_Advance(font->ft_face, text->items[i].gid, mask, &ftadv); adv = ftadv / 65536.0f; fz_unlock(ctx, FZ_LOCK_FREETYPE); rect.x0 = 0; rect.y0 = descender; rect.x1 = adv; rect.y1 = ascender; } /* SumatraPDF: TODO: this check might no longer be needed */ else if (text->items[i].gid < 256) { adv = font->t3widths[text->items[i].gid]; rect.x0 = 0; rect.y0 = descender; rect.x1 = adv; rect.y1 = ascender; } fz_transform_rect(&rect, &trm); /* cf. http://code.google.com/p/sumatrapdf/issues/detail?id=1839 */ if (font->ft_face) { fz_rect bbox; fz_bound_glyph(ctx, font, text->items[i].gid, &trm, &bbox); rect.y0 = fz_min(rect.y0, bbox.y0); rect.y1 = fz_max(rect.y1, bbox.y1); } pen->x = trm.e + dir.x * adv; pen->y = trm.f + dir.y * adv; /* Check for one glyph to many char mapping */ for (j = i + 1; j < text->len; j++) if (text->items[j].gid >= 0) break; multi = j - i; if (multi == 1) { fz_add_text_char(ctx, dev, style, text->items[i].ucs, rect); } else { for (j = 0; j < multi; j++) { fz_rect part = fz_split_bbox(rect, j, multi); fz_add_text_char(ctx, dev, style, text->items[i + j].ucs, part); } i += j - 1; } dev->lastchar = text->items[i].ucs; } }
void fz_convert_color(fz_context *ctx, fz_colorspace *ds, float *dv, fz_colorspace *ss, float *sv) { if (ss == fz_device_gray) { if ((ds == fz_device_rgb) || (ds == fz_device_bgr)) { dv[0] = sv[0]; dv[1] = sv[0]; dv[2] = sv[0]; } else if (ds == fz_device_cmyk) { dv[0] = 0; dv[1] = 0; dv[2] = 0; dv[3] = sv[0]; } else fz_std_conv_color(ctx, ss, sv, ds, dv); } else if (ss == fz_device_rgb) { if (ds == fz_device_gray) { dv[0] = sv[0] * 0.3f + sv[1] * 0.59f + sv[2] * 0.11f; } else if (ds == fz_device_bgr) { dv[0] = sv[2]; dv[1] = sv[1]; dv[2] = sv[0]; } else if (ds == fz_device_cmyk) { float c = 1 - sv[0]; float m = 1 - sv[1]; float y = 1 - sv[2]; float k = fz_min(c, fz_min(m, y)); dv[0] = c - k; dv[1] = m - k; dv[2] = y - k; dv[3] = k; } else fz_std_conv_color(ctx, ss, sv, ds, dv); } else if (ss == fz_device_bgr) { if (ds == fz_device_gray) { dv[0] = sv[0] * 0.11f + sv[1] * 0.59f + sv[2] * 0.3f; } else if (ds == fz_device_bgr) { dv[0] = sv[2]; dv[1] = sv[1]; dv[2] = sv[0]; } else if (ds == fz_device_cmyk) { float c = 1 - sv[2]; float m = 1 - sv[1]; float y = 1 - sv[0]; float k = fz_min(c, fz_min(m, y)); dv[0] = c - k; dv[1] = m - k; dv[2] = y - k; dv[3] = k; } else fz_std_conv_color(ctx, ss, sv, ds, dv); } else if (ss == fz_device_cmyk) { if (ds == fz_device_gray) { float c = sv[0] * 0.3f; float m = sv[1] * 0.59f; float y = sv[2] * 0.11f; dv[0] = 1 - fz_min(c + m + y + sv[3], 1); } else if (ds == fz_device_rgb) { #ifdef SLOWCMYK cmyk_to_rgb(ctx, NULL, sv, dv); #else dv[0] = 1 - fz_min(sv[0] + sv[3], 1); dv[1] = 1 - fz_min(sv[1] + sv[3], 1); dv[2] = 1 - fz_min(sv[2] + sv[3], 1); #endif } else if (ds == fz_device_bgr) { #ifdef SLOWCMYK float rgb[3]; cmyk_to_rgb(ctx, NULL, sv, rgb); dv[0] = rgb[2]; dv[1] = rgb[1]; dv[2] = rgb[0]; #else dv[0] = 1 - fz_min(sv[2] + sv[3], 1); dv[1] = 1 - fz_min(sv[1] + sv[3], 1); dv[2] = 1 - fz_min(sv[0] + sv[3], 1); #endif } else fz_std_conv_color(ctx, ss, sv, ds, dv); } else fz_std_conv_color(ctx, ss, sv, ds, dv); }