7 #define MATRIX_COEFS (6)
8 #define STRIKE_HEIGHT (0.375f)
9 #define UNDERLINE_HEIGHT (0.075f)
10 #define LINE_THICKNESS (0.07f)
11 #define SMALL_FLOAT (0.00001)
29 typedef struct font_info_s
36 typedef struct text_widget_info_s
47 static const char *fmt_re = "%f %f %f %f re\n";
48 static const char *fmt_f = "f\n";
49 static const char *fmt_s = "s\n";
50 static const char *fmt_g = "%f g\n";
51 static const char *fmt_m = "%f %f m\n";
52 static const char *fmt_l = "%f %f l\n";
53 static const char *fmt_w = "%f w\n";
54 static const char *fmt_Tx_BMC = "/Tx BMC\n";
55 static const char *fmt_q = "q\n";
56 static const char *fmt_W = "W\n";
57 static const char *fmt_n = "n\n";
58 static const char *fmt_BT = "BT\n";
59 static const char *fmt_Tm = "%f %f %f %f %f %f Tm\n";
60 static const char *fmt_Td = "%f %f Td\n";
61 static const char *fmt_Tj = " Tj\n";
62 static const char *fmt_ET = "ET\n";
63 static const char *fmt_Q = "Q\n";
64 static const char *fmt_EMC = "EMC\n";
66 void pdf_da_info_fin(fz_context *ctx, pdf_da_info *di)
68 fz_free(ctx, di->font_name);
72 static void da_check_stack(float *stack, int *top)
76 memmove(stack, stack + 1, 31 * sizeof(stack[0]));
81 void pdf_parse_da(fz_context *ctx, char *da, pdf_da_info *di)
83 float stack[32] = { 0.0f };
88 fz_stream *str = fz_open_memory(ctx, (unsigned char *)da, strlen(da));
90 pdf_lexbuf_init(ctx, &lbuf, PDF_LEXBUF_SMALL);
96 for (tok = pdf_lex(str, &lbuf); tok != PDF_TOK_EOF; tok = pdf_lex(str, &lbuf))
102 name = fz_strdup(ctx, lbuf.scratch);
106 da_check_stack(stack, &top);
112 da_check_stack(stack, &top);
117 case PDF_TOK_KEYWORD:
118 if (!strcmp(lbuf.scratch, "Tf"))
120 di->font_size = stack[0];
121 di->font_name = name;
124 else if (!strcmp(lbuf.scratch, "rg"))
126 di->col[0] = stack[0];
127 di->col[1] = stack[1];
128 di->col[2] = stack[2];
131 else if (!strcmp(lbuf.scratch, "g"))
133 di->col[0] = stack[0];
151 pdf_lexbuf_fin(&lbuf);
159 static void get_font_info(pdf_document *doc, pdf_obj *dr, char *da, font_info *font_rec)
161 fz_context *ctx = doc->ctx;
164 pdf_parse_da(ctx, da, &font_rec->da_rec);
165 if (font_rec->da_rec.font_name == NULL)
166 fz_throw(ctx, FZ_ERROR_GENERIC, "No font name in default appearance");
168 font_rec->font = font = pdf_load_font(doc, dr, pdf_dict_gets(pdf_dict_gets(dr, "Font"), font_rec->da_rec.font_name), 0);
169 font_rec->lineheight = 1.0;
170 if (font && font->ascent != 0.0f && font->descent != 0.0f)
171 font_rec->lineheight = (font->ascent - font->descent) / 1000.0;
174 static void font_info_fin(fz_context *ctx, font_info *font_rec)
176 pdf_drop_font(ctx, font_rec->font);
177 font_rec->font = NULL;
178 pdf_da_info_fin(ctx, &font_rec->da_rec);
181 static void get_text_widget_info(pdf_document *doc, pdf_obj *widget, text_widget_info *info)
183 char *da = pdf_to_str_buf(pdf_get_inheritable(doc, widget, "DA"));
184 int ff = pdf_get_field_flags(doc, widget);
185 pdf_obj *ml = pdf_get_inheritable(doc, widget, "MaxLen");
187 info->dr = pdf_get_inheritable(doc, widget, "DR");
188 info->col = pdf_dict_getp(widget, "MK/BG");
189 info->q = pdf_to_int(pdf_get_inheritable(doc, widget, "Q"));
190 info->multiline = (ff & Ff_Multiline) != 0;
191 info->comb = (ff & (Ff_Multiline|Ff_Password|Ff_FileSelect|Ff_Comb)) == Ff_Comb;
196 info->max_len = pdf_to_int(ml);
198 get_font_info(doc, info->dr, da, &info->font_rec);
201 void pdf_fzbuf_print_da(fz_context *ctx, fz_buffer *fzbuf, pdf_da_info *di)
203 if (di->font_name != NULL && di->font_size != 0)
204 fz_buffer_printf(ctx, fzbuf, "/%s %d Tf", di->font_name, di->font_size);
206 switch (di->col_size)
209 fz_buffer_printf(ctx, fzbuf, " %f g", di->col[0]);
213 fz_buffer_printf(ctx, fzbuf, " %f %f %f rg", di->col[0], di->col[1], di->col[2]);
217 fz_buffer_printf(ctx, fzbuf, " %f %f %f %f k", di->col[0], di->col[1], di->col[2], di->col[3]);
221 fz_buffer_printf(ctx, fzbuf, " 0 g");
226 static fz_rect *measure_text(pdf_document *doc, font_info *font_rec, const fz_matrix *tm, char *text, fz_rect *bbox)
228 pdf_measure_text(doc->ctx, font_rec->font, (unsigned char *)text, strlen(text), bbox);
230 bbox->x0 *= font_rec->da_rec.font_size * tm->a;
231 bbox->y0 *= font_rec->da_rec.font_size * tm->d;
232 bbox->x1 *= font_rec->da_rec.font_size * tm->a;
233 bbox->y1 *= font_rec->da_rec.font_size * tm->d;
238 static void fzbuf_print_color(fz_context *ctx, fz_buffer *fzbuf, pdf_obj *arr, int stroke, float adj)
240 switch (pdf_array_len(arr))
243 fz_buffer_printf(ctx, fzbuf, stroke?"%f G\n":"%f g\n",
244 pdf_to_real(pdf_array_get(arr, 0)) + adj);
247 fz_buffer_printf(ctx, fzbuf, stroke?"%f %f %f RG\n":"%f %f %f rg\n",
248 pdf_to_real(pdf_array_get(arr, 0)) + adj,
249 pdf_to_real(pdf_array_get(arr, 1)) + adj,
250 pdf_to_real(pdf_array_get(arr, 2)) + adj);
253 fz_buffer_printf(ctx, fzbuf, stroke?"%f %f %f %f K\n":"%f %f %f %f k\n",
254 pdf_to_real(pdf_array_get(arr, 0)),
255 pdf_to_real(pdf_array_get(arr, 1)),
256 pdf_to_real(pdf_array_get(arr, 2)),
257 pdf_to_real(pdf_array_get(arr, 3)));
262 static void fzbuf_print_text(fz_context *ctx, fz_buffer *fzbuf, const fz_rect *clip, pdf_obj *col, font_info *font_rec, const fz_matrix *tm, char *text)
264 fz_buffer_printf(ctx, fzbuf, fmt_q);
267 fz_buffer_printf(ctx, fzbuf, fmt_re, clip->x0, clip->y0, clip->x1 - clip->x0, clip->y1 - clip->y0);
268 fz_buffer_printf(ctx, fzbuf, fmt_W);
271 fzbuf_print_color(ctx, fzbuf, col, 0, 0.0);
272 fz_buffer_printf(ctx, fzbuf, fmt_f);
276 fz_buffer_printf(ctx, fzbuf, fmt_n);
280 fz_buffer_printf(ctx, fzbuf, fmt_BT);
282 pdf_fzbuf_print_da(ctx, fzbuf, &font_rec->da_rec);
284 fz_buffer_printf(ctx, fzbuf, "\n");
286 fz_buffer_printf(ctx, fzbuf, fmt_Tm, tm->a, tm->b, tm->c, tm->d, tm->e, tm->f);
288 fz_buffer_cat_pdf_string(ctx, fzbuf, text);
289 fz_buffer_printf(ctx, fzbuf, fmt_Tj);
290 fz_buffer_printf(ctx, fzbuf, fmt_ET);
291 fz_buffer_printf(ctx, fzbuf, fmt_Q);
294 static fz_buffer *create_text_buffer(fz_context *ctx, const fz_rect *clip, text_widget_info *info, const fz_matrix *tm, char *text)
296 fz_buffer *fzbuf = fz_new_buffer(ctx, 0);
300 fz_buffer_printf(ctx, fzbuf, fmt_Tx_BMC);
301 fzbuf_print_text(ctx, fzbuf, clip, info->col, &info->font_rec, tm, text);
302 fz_buffer_printf(ctx, fzbuf, fmt_EMC);
306 fz_drop_buffer(ctx, fzbuf);
313 static fz_buffer *create_aligned_text_buffer(pdf_document *doc, const fz_rect *clip, text_widget_info *info, const fz_matrix *tm, char *text)
315 fz_context *ctx = doc->ctx;
318 if (info->q != Q_Left)
322 measure_text(doc, &info->font_rec, tm, text, &rect);
323 atm.e -= info->q == Q_Right ? rect.x1 : (rect.x1 - rect.x0) / 2;
326 return create_text_buffer(ctx, clip, info, &atm, text);
329 static void measure_ascent_descent(pdf_document *doc, font_info *finf, char *text, float *ascent, float *descent)
331 fz_context *ctx = doc->ctx;
332 char *testtext = NULL;
334 font_info tinf = *finf;
339 /* Heuristic: adding "My" to text will in most cases
340 * produce a measurement that will encompass all chars */
341 testtext = fz_malloc(ctx, strlen(text) + 3);
342 strcpy(testtext, "My");
343 strcat(testtext, text);
344 tinf.da_rec.font_size = 1;
345 measure_text(doc, &tinf, &fz_identity, testtext, &bbox);
351 fz_free(ctx, testtext);
359 typedef struct text_splitter_s
365 float unscaled_width;
380 static void text_splitter_init(text_splitter *splitter, font_info *info, char *text, float width, float height, int variable)
382 float fontsize = info->da_rec.font_size;
384 memset(splitter, 0, sizeof(*splitter));
385 splitter->info = info;
386 splitter->text = text;
387 splitter->width = width;
388 splitter->unscaled_width = width;
389 splitter->height = height;
390 splitter->fontsize = fontsize;
391 splitter->scale = 1.0;
392 splitter->lineheight = fontsize * info->lineheight ;
393 /* RJW: The cast in the following line is important, as otherwise
394 * under MSVC in the variable = 0 case, splitter->max_lines becomes
396 splitter->max_lines = variable ? (int)(height/splitter->lineheight) : INT_MAX;
399 static void text_splitter_start_pass(text_splitter *splitter)
401 splitter->text_end = 0;
402 splitter->x_orig = 0;
403 splitter->y_orig = 0;
406 static void text_splitter_start_line(text_splitter *splitter)
411 static int text_splitter_layout(fz_context *ctx, text_splitter *splitter)
418 float fontsize = splitter->info->da_rec.font_size;
420 splitter->x = splitter->x_end;
421 splitter->text_start = splitter->text_end;
423 text = splitter->text + splitter->text_start;
424 room = splitter->unscaled_width - splitter->x;
426 if (strchr("\r\n", text[0]))
428 /* Consume return chars and report end of line */
429 splitter->text_end += strspn(text, "\r\n");
430 splitter->text_start = splitter->text_end;
431 splitter->done = (splitter->text[splitter->text_end] == '\0');
434 else if (text[0] == ' ')
436 /* Treat each space as a word */
442 while (text[len] != '\0' && !strchr(" \r\n", text[len]))
446 stride = pdf_text_stride(ctx, splitter->info->font, fontsize, (unsigned char *)text, len, room, &count);
448 /* If not a single char fits although the line is empty, then force one char */
449 if (count == 0 && splitter->x == 0.0)
450 stride = pdf_text_stride(ctx, splitter->info->font, fontsize, (unsigned char *)text, 1, FLT_MAX, &count);
452 if (count < len && splitter->retry)
454 /* The word didn't fit and we are in retry mode. Work out the
455 * least additional scaling that may help */
456 float fitwidth; /* width if we force the word in */
457 float hstretchwidth; /* width if we just bump by 10% */
458 float vstretchwidth; /* width resulting from forcing in another line */
461 fitwidth = splitter->x +
462 pdf_text_stride(ctx, splitter->info->font, fontsize, (unsigned char *)text, len, FLT_MAX, &count);
463 /* FIXME: temporary fiddle factor. Would be better to work in integers */
466 /* Stretching by 10% is worth trying only if processing the first word on the line */
467 hstretchwidth = splitter->x == 0.0
468 ? splitter->width * 1.1 / splitter->scale
471 vstretchwidth = splitter->width * (splitter->max_lines + 1) * splitter->lineheight
474 bestwidth = fz_min(fitwidth, fz_min(hstretchwidth, vstretchwidth));
476 if (bestwidth == vstretchwidth)
477 splitter->max_lines ++;
479 splitter->scale = splitter->width / bestwidth;
480 splitter->unscaled_width = bestwidth;
485 room = splitter->unscaled_width - splitter->x;
486 stride = pdf_text_stride(ctx, splitter->info->font, fontsize, (unsigned char *)text, len, room, &count);
489 /* This is not the first word on the line. Best to give up on this line and push
490 * the word onto the next */
491 if (count < len && splitter->x > 0.0)
494 splitter->text_end = splitter->text_start + count;
495 splitter->x_end = splitter->x + stride;
496 splitter->done = (splitter->text[splitter->text_end] == '\0');
500 static void text_splitter_move(text_splitter *splitter, float newy, float *relx, float *rely)
502 *relx = splitter->x - splitter->x_orig;
503 *rely = newy * splitter->lineheight - splitter->y_orig;
505 splitter->x_orig = splitter->x;
506 splitter->y_orig = newy * splitter->lineheight;
509 static void text_splitter_retry(text_splitter *splitter)
513 /* Already tried expanding lines. Overflow must
514 * be caused by carriage control */
515 splitter->max_lines ++;
517 splitter->unscaled_width = splitter->width * splitter->max_lines * splitter->lineheight
519 splitter->scale = splitter->width / splitter->unscaled_width;
527 static void fzbuf_print_text_start(fz_context *ctx, fz_buffer *fzbuf, const fz_rect *clip, pdf_obj *col, font_info *font, const fz_matrix *tm)
529 fz_buffer_printf(ctx, fzbuf, fmt_Tx_BMC);
530 fz_buffer_printf(ctx, fzbuf, fmt_q);
534 fz_buffer_printf(ctx, fzbuf, fmt_re, clip->x0, clip->y0, clip->x1 - clip->x0, clip->y1 - clip->y0);
535 fz_buffer_printf(ctx, fzbuf, fmt_W);
538 fzbuf_print_color(ctx, fzbuf, col, 0, 0.0);
539 fz_buffer_printf(ctx, fzbuf, fmt_f);
543 fz_buffer_printf(ctx, fzbuf, fmt_n);
547 fz_buffer_printf(ctx, fzbuf, fmt_BT);
549 pdf_fzbuf_print_da(ctx, fzbuf, &font->da_rec);
550 fz_buffer_printf(ctx, fzbuf, "\n");
552 fz_buffer_printf(ctx, fzbuf, fmt_Tm, tm->a, tm->b, tm->c, tm->d, tm->e, tm->f);
555 static void fzbuf_print_text_end(fz_context *ctx, fz_buffer *fzbuf)
557 fz_buffer_printf(ctx, fzbuf, fmt_ET);
558 fz_buffer_printf(ctx, fzbuf, fmt_Q);
559 fz_buffer_printf(ctx, fzbuf, fmt_EMC);
562 static void fzbuf_print_text_word(fz_context *ctx, fz_buffer *fzbuf, float x, float y, char *text, int count)
566 fz_buffer_printf(ctx, fzbuf, fmt_Td, x, y);
567 fz_buffer_printf(ctx, fzbuf, "(");
569 for (i = 0; i < count; i++)
570 fz_buffer_printf(ctx, fzbuf, "%c", text[i]);
572 fz_buffer_printf(ctx, fzbuf, ") Tj\n");
575 static fz_buffer *create_text_appearance(pdf_document *doc, const fz_rect *bbox, const fz_matrix *oldtm, text_widget_info *info, char *text)
577 fz_context *ctx = doc->ctx;
580 float height, width, full_width;
581 fz_buffer *fzbuf = NULL;
582 fz_buffer *fztmp = NULL;
587 if (rect.x1 - rect.x0 > 3.0 && rect.y1 - rect.y0 > 3.0)
595 height = rect.y1 - rect.y0;
596 width = rect.x1 - rect.x0;
597 full_width = bbox->x1 - bbox->x0;
603 float ascent, descent;
606 variable = (info->font_rec.da_rec.font_size == 0);
608 ? (info->multiline ? 14.0 : height / info->font_rec.lineheight)
609 : info->font_rec.da_rec.font_size;
611 info->font_rec.da_rec.font_size = fontsize;
613 measure_ascent_descent(doc, &info->font_rec, text, &ascent, &descent);
617 text_splitter splitter;
619 text_splitter_init(&splitter, &info->font_rec, text, width, height, variable);
621 while (!splitter.done)
623 /* Try a layout pass */
626 fz_drop_buffer(ctx, fztmp);
628 fztmp = fz_new_buffer(ctx, 0);
630 text_splitter_start_pass(&splitter);
632 /* Layout unscaled text to a scaled-up width, so that
633 * the scaled-down text will fit the unscaled width */
635 while (!splitter.done && line < splitter.max_lines)
638 text_splitter_start_line(&splitter);
640 while (!splitter.done && text_splitter_layout(ctx, &splitter))
642 if (splitter.text[splitter.text_start] != ' ')
645 char *word = text+splitter.text_start;
646 int wordlen = splitter.text_end-splitter.text_start;
648 text_splitter_move(&splitter, -line, &x, &y);
649 fzbuf_print_text_word(ctx, fztmp, x, y, word, wordlen);
657 text_splitter_retry(&splitter);
660 fzbuf = fz_new_buffer(ctx, 0);
662 tm.a = splitter.scale;
665 tm.d = splitter.scale;
667 tm.f = rect.y1 - (1.0+ascent-descent)*fontsize*splitter.scale/2.0;
669 fzbuf_print_text_start(ctx, fzbuf, &rect, info->col, &info->font_rec, &tm);
671 fz_buffer_cat(ctx, fzbuf, fztmp);
673 fzbuf_print_text_end(ctx, fzbuf);
677 int i, n = fz_mini((int)strlen(text), info->max_len);
678 float comb_width = full_width/info->max_len;
679 float char_width = pdf_text_stride(ctx, info->font_rec.font, fontsize, (unsigned char *)"M", 1, FLT_MAX, NULL);
680 float init_skip = (comb_width - char_width)/2.0;
682 fz_translate(&tm, rect.x0, rect.y1 - (height+(ascent-descent)*fontsize)/2.0);
684 fzbuf = fz_new_buffer(ctx, 0);
686 fzbuf_print_text_start(ctx, fzbuf, &rect, info->col, &info->font_rec, &tm);
688 for (i = 0; i < n; i++)
689 fzbuf_print_text_word(ctx, fzbuf, i == 0 ? init_skip : comb_width, 0.0, text+i, 1);
691 fzbuf_print_text_end(ctx, fzbuf);
701 fz_translate(&tm, rect.x0, rect.y1 - (height+(ascent-descent)*fontsize)/2.0);
705 case Q_Right: tm.e += width; break;
706 case Q_Cent: tm.e += width/2; break;
712 measure_text(doc, &info->font_rec, &tm, text, &tbox);
714 if (tbox.x1 - tbox.x0 > width)
716 /* Scale the text to fit but use the same offset
717 * to keep the baseline constant */
718 tm.a *= width / (tbox.x1 - tbox.x0);
719 tm.d *= width / (tbox.x1 - tbox.x0);
723 fzbuf = create_aligned_text_buffer(doc, &rect, info, &tm, text);
728 fz_drop_buffer(ctx, fztmp);
732 fz_drop_buffer(ctx, fzbuf);
739 static int get_matrix(pdf_document *doc, pdf_xobject *form, int q, fz_matrix *mt)
741 fz_context *ctx = doc->ctx;
746 str = pdf_open_stream(doc, pdf_to_num(form->contents), pdf_to_gen(form->contents));
748 pdf_lexbuf_init(ctx, &lbuf, PDF_LEXBUF_SMALL);
753 float coefs[MATRIX_COEFS];
756 /* Look for the text matrix Tm in the stream */
757 for (tok = pdf_lex(str, &lbuf); tok != PDF_TOK_EOF; tok = pdf_lex(str, &lbuf))
759 if (tok == PDF_TOK_INT || tok == PDF_TOK_REAL)
761 if (coef_i >= MATRIX_COEFS)
764 for (i = 0; i < MATRIX_COEFS-1; i++)
765 coefs[i] = coefs[i+1];
767 coef_i = MATRIX_COEFS-1;
770 coefs[coef_i++] = tok == PDF_TOK_INT ? lbuf.i : lbuf.f;
774 if (tok == PDF_TOK_KEYWORD && !strcmp(lbuf.scratch, "Tm") && coef_i == MATRIX_COEFS)
792 pdf_to_rect(ctx, pdf_dict_gets(form->contents, "BBox"), &bbox);
801 mt->e = (bbox.x1 - bbox.x0) / 2;
813 pdf_lexbuf_fin(&lbuf);
823 static char *to_font_encoding(fz_context *ctx, pdf_font_desc *font, char *utf8)
826 int needs_converting = 0;
828 /* Temporay partial solution. We are using a slow lookup in the conversion
829 * below, so we avoid performing the conversion unnecessarily. We check for
830 * top-bit-set chars, and convert only if they are present. We should also
831 * check that the font encoding is one that agrees with utf8 from 0 to 7f,
832 * but for now we get away without doing so. This is after all an improvement
834 for (i = 0; utf8[i] != '\0'; i++)
837 needs_converting = 1;
840 /* Even if we need to convert, we cannot do so if the font has no cid_to_ucs mapping */
841 if (needs_converting && font->cid_to_ucs)
843 char *buf = fz_malloc(ctx, strlen(utf8) + 1);
854 utf8 += fz_chartorune(&rune, utf8);
856 /* Slow search for the cid that maps to the unicode value held in 'rune" */
857 for (i = 0; i < font->cid_to_ucs_len && font->cid_to_ucs[i] != rune; i++)
860 /* If found store the cid */
861 if (i < font->cid_to_ucs_len)
882 /* If either no conversion is needed or the font has no cid_to_ucs
883 * mapping then leave unconverted, although in the latter case the result
884 * is likely incorrect */
885 return fz_strdup(ctx, utf8);
889 static void account_for_rot(fz_rect *rect, fz_matrix *mat, int rot)
891 float width = rect->x1;
892 float height = rect->y1;
900 fz_pre_rotate(fz_translate(mat, width, 0), rot);
905 fz_pre_rotate(fz_translate(mat, width, height), rot);
908 fz_pre_rotate(fz_translate(mat, 0, height), rot);
915 static void copy_resources(pdf_obj *dst, pdf_obj *src)
919 len = pdf_dict_len(src);
920 for (i = 0; i < len; i++)
922 pdf_obj *key = pdf_dict_get_key(src, i);
924 if (!pdf_dict_get(dst, key))
925 pdf_dict_put(dst, key, pdf_dict_get_val(src, i));
929 static pdf_xobject *load_or_create_form(pdf_document *doc, pdf_obj *obj, fz_rect *rect)
931 fz_context *ctx = doc->ctx;
935 pdf_obj *formobj = NULL;
936 pdf_xobject *form = NULL;
938 fz_buffer *fzbuf = NULL;
946 rot = pdf_to_int(pdf_dict_getp(obj, "MK/R"));
947 pdf_to_rect(ctx, pdf_dict_gets(obj, "Rect"), rect);
948 rect->x1 -= rect->x0;
949 rect->y1 -= rect->y0;
950 rect->x0 = rect->y0 = 0;
951 account_for_rot(rect, &mat, rot);
953 ap = pdf_dict_gets(obj, "AP");
956 ap = pdf_new_dict(doc, 1);
957 pdf_dict_puts_drop(obj, "AP", ap);
960 formobj = pdf_dict_gets(ap, dn);
963 formobj = pdf_new_xobject(doc, rect, &mat);
964 pdf_dict_puts_drop(ap, dn, formobj);
968 form = pdf_load_xobject(doc, formobj);
971 fzbuf = fz_new_buffer(ctx, 1);
972 pdf_update_xobject_contents(doc, form, fzbuf);
975 copy_resources(form->resources, pdf_get_inheritable(doc, obj, "DR"));
979 fz_drop_buffer(ctx, fzbuf);
983 pdf_drop_xobject(ctx, form);
990 static void update_marked_content(pdf_document *doc, pdf_xobject *form, fz_buffer *fzbuf)
992 fz_context *ctx = doc->ctx;
995 fz_stream *str_outer = NULL;
996 fz_stream *str_inner = NULL;
999 fz_buffer *newbuf = NULL;
1001 pdf_lexbuf_init(ctx, &lbuf, PDF_LEXBUF_SMALL);
1011 newbuf = fz_new_buffer(ctx, 0);
1012 str_outer = pdf_open_stream(doc, pdf_to_num(form->contents), pdf_to_gen(form->contents));
1013 len = fz_buffer_storage(ctx, fzbuf, &buf);
1014 str_inner = fz_open_memory(ctx, buf, len);
1016 /* Copy the existing appearance stream to newbuf while looking for BMC */
1017 for (tok = pdf_lex(str_outer, &lbuf); tok != PDF_TOK_EOF; tok = pdf_lex(str_outer, &lbuf))
1022 fz_buffer_printf(ctx, newbuf, " ");
1024 pdf_print_token(ctx, newbuf, tok, &lbuf);
1025 if (tok == PDF_TOK_KEYWORD && !strcmp(lbuf.scratch, "BMC"))
1029 bmc_found = (tok != PDF_TOK_EOF);
1033 /* Drop Tx BMC from the replacement appearance stream */
1034 (void)pdf_lex(str_inner, &lbuf);
1035 (void)pdf_lex(str_inner, &lbuf);
1038 /* Copy the replacement appearance stream to newbuf */
1039 for (tok = pdf_lex(str_inner, &lbuf); tok != PDF_TOK_EOF; tok = pdf_lex(str_inner, &lbuf))
1041 fz_buffer_printf(ctx, newbuf, " ");
1042 pdf_print_token(ctx, newbuf, tok, &lbuf);
1047 /* Drop the rest of the existing appearance stream until EMC found */
1048 for (tok = pdf_lex(str_outer, &lbuf); tok != PDF_TOK_EOF; tok = pdf_lex(str_outer, &lbuf))
1050 if (tok == PDF_TOK_KEYWORD && !strcmp(lbuf.scratch, "EMC"))
1054 /* Copy the rest of the existing appearance stream to newbuf */
1055 for (tok = pdf_lex(str_outer, &lbuf); tok != PDF_TOK_EOF; tok = pdf_lex(str_outer, &lbuf))
1057 fz_buffer_printf(ctx, newbuf, " ");
1058 pdf_print_token(ctx, newbuf, tok, &lbuf);
1062 /* Use newbuf in place of the existing appearance stream */
1063 pdf_update_xobject_contents(doc, form, newbuf);
1067 fz_close(str_outer);
1068 fz_close(str_inner);
1069 fz_drop_buffer(ctx, newbuf);
1070 pdf_lexbuf_fin(&lbuf);
1078 static int get_border_style(pdf_obj *obj)
1080 char *sname = pdf_to_name(pdf_dict_getp(obj, "BS/S"));
1082 if (!strcmp(sname, "D"))
1084 else if (!strcmp(sname, "B"))
1086 else if (!strcmp(sname, "I"))
1088 else if (!strcmp(sname, "U"))
1089 return BS_Underline;
1094 static float get_border_width(pdf_obj *obj)
1096 float w = pdf_to_real(pdf_dict_getp(obj, "BS/W"));
1097 return w == 0.0 ? 1.0 : w;
1100 void pdf_update_text_appearance(pdf_document *doc, pdf_obj *obj, char *eventValue)
1102 fz_context *ctx = doc->ctx;
1103 text_widget_info info;
1104 pdf_xobject *form = NULL;
1105 fz_buffer *fzbuf = NULL;
1111 memset(&info, 0, sizeof(info));
1119 get_text_widget_info(doc, obj, &info);
1122 text = to_font_encoding(ctx, info.font_rec.font, eventValue);
1124 text = pdf_field_value(doc, obj);
1126 form = load_or_create_form(doc, obj, &rect);
1128 has_tm = get_matrix(doc, form, info.q, &tm);
1129 fzbuf = create_text_appearance(doc, &form->bbox, has_tm ? &tm : NULL, &info,
1131 update_marked_content(doc, form, fzbuf);
1136 pdf_drop_xobject(ctx, form);
1137 fz_drop_buffer(ctx, fzbuf);
1138 font_info_fin(ctx, &info.font_rec);
1142 fz_warn(ctx, "update_text_appearance failed");
1146 void pdf_update_combobox_appearance(pdf_document *doc, pdf_obj *obj)
1148 fz_context *ctx = doc->ctx;
1149 text_widget_info info;
1150 pdf_xobject *form = NULL;
1151 fz_buffer *fzbuf = NULL;
1158 memset(&info, 0, sizeof(info));
1165 get_text_widget_info(doc, obj, &info);
1167 val = pdf_get_inheritable(doc, obj, "V");
1169 if (pdf_is_array(val))
1170 val = pdf_array_get(val, 0);
1172 text = pdf_to_str_buf(val);
1177 form = load_or_create_form(doc, obj, &rect);
1179 has_tm = get_matrix(doc, form, info.q, &tm);
1180 fzbuf = create_text_appearance(doc, &form->bbox, has_tm ? &tm : NULL, &info,
1182 update_marked_content(doc, form, fzbuf);
1186 pdf_drop_xobject(ctx, form);
1187 fz_drop_buffer(ctx, fzbuf);
1188 font_info_fin(ctx, &info.font_rec);
1192 fz_warn(ctx, "update_text_appearance failed");
1196 void pdf_update_pushbutton_appearance(pdf_document *doc, pdf_obj *obj)
1198 fz_context *ctx = doc->ctx;
1200 pdf_xobject *form = NULL;
1201 fz_buffer *fzbuf = NULL;
1202 pdf_obj *tobj = NULL;
1208 memset(&font_rec, 0, sizeof(font_rec));
1215 form = load_or_create_form(doc, obj, &rect);
1216 fzbuf = fz_new_buffer(ctx, 0);
1217 tobj = pdf_dict_getp(obj, "MK/BG");
1218 if (pdf_is_array(tobj))
1220 fzbuf_print_color(ctx, fzbuf, tobj, 0, 0.0);
1221 fz_buffer_printf(ctx, fzbuf, fmt_re,
1222 rect.x0, rect.y0, rect.x1, rect.y1);
1223 fz_buffer_printf(ctx, fzbuf, fmt_f);
1225 bstyle = get_border_style(obj);
1226 bwidth = get_border_width(obj);
1228 if (bstyle == BS_Beveled || bstyle == BS_Inset)
1232 if (bstyle == BS_Beveled)
1233 fz_buffer_printf(ctx, fzbuf, fmt_g, 1.0);
1235 fz_buffer_printf(ctx, fzbuf, fmt_g, 0.33);
1236 fz_buffer_printf(ctx, fzbuf, fmt_m, bwidth, bwidth);
1237 fz_buffer_printf(ctx, fzbuf, fmt_l, bwidth, rect.y1 - bwidth);
1238 fz_buffer_printf(ctx, fzbuf, fmt_l, rect.x1 - bwidth, rect.y1 - bwidth);
1239 fz_buffer_printf(ctx, fzbuf, fmt_l, rect.x1 - 2 * bwidth, rect.y1 - 2 * bwidth);
1240 fz_buffer_printf(ctx, fzbuf, fmt_l, 2 * bwidth, rect.y1 - 2 * bwidth);
1241 fz_buffer_printf(ctx, fzbuf, fmt_l, 2 * bwidth, 2 * bwidth);
1242 fz_buffer_printf(ctx, fzbuf, fmt_f);
1243 if (bstyle == BS_Beveled)
1244 fzbuf_print_color(ctx, fzbuf, tobj, 0, -0.25);
1246 fz_buffer_printf(ctx, fzbuf, fmt_g, 0.66);
1247 fz_buffer_printf(ctx, fzbuf, fmt_m, rect.x1 - bwidth, rect.y1 - bwidth);
1248 fz_buffer_printf(ctx, fzbuf, fmt_l, rect.x1 - bwidth, bwidth);
1249 fz_buffer_printf(ctx, fzbuf, fmt_l, bwidth, bwidth);
1250 fz_buffer_printf(ctx, fzbuf, fmt_l, 2 * bwidth, 2 * bwidth);
1251 fz_buffer_printf(ctx, fzbuf, fmt_l, rect.x1 - 2 * bwidth, 2 * bwidth);
1252 fz_buffer_printf(ctx, fzbuf, fmt_l, rect.x1 - 2 * bwidth, rect.y1 - 2 * bwidth);
1253 fz_buffer_printf(ctx, fzbuf, fmt_f);
1256 tobj = pdf_dict_getp(obj, "MK/BC");
1259 fzbuf_print_color(ctx, fzbuf, tobj, 1, 0.0);
1260 fz_buffer_printf(ctx, fzbuf, fmt_w, bwidth);
1261 fz_buffer_printf(ctx, fzbuf, fmt_re,
1263 rect.x1 -bwidth/2, rect.y1 - bwidth/2);
1264 fz_buffer_printf(ctx, fzbuf, fmt_s);
1267 tobj = pdf_dict_getp(obj, "MK/CA");
1270 fz_rect clip = rect;
1273 char *da = pdf_to_str_buf(pdf_get_inheritable(doc, obj, "DA"));
1274 char *text = pdf_to_str_buf(tobj);
1281 get_font_info(doc, form->resources, da, &font_rec);
1282 measure_text(doc, &font_rec, &fz_identity, text, &bounds);
1283 fz_translate(&mat, (rect.x1 - bounds.x1)/2, (rect.y1 - bounds.y1)/2);
1284 fzbuf_print_text(ctx, fzbuf, &clip, NULL, &font_rec, &mat, text);
1287 pdf_update_xobject_contents(doc, form, fzbuf);
1291 font_info_fin(ctx, &font_rec);
1292 fz_drop_buffer(ctx, fzbuf);
1293 pdf_drop_xobject(ctx, form);
1301 void pdf_update_text_markup_appearance(pdf_document *doc, pdf_annot *annot, fz_annot_type type)
1306 float line_thickness;
1310 case FZ_ANNOT_HIGHLIGHT:
1315 line_thickness = 1.0;
1318 case FZ_ANNOT_UNDERLINE:
1323 line_thickness = LINE_THICKNESS;
1324 line_height = UNDERLINE_HEIGHT;
1326 case FZ_ANNOT_STRIKEOUT:
1331 line_thickness = LINE_THICKNESS;
1332 line_height = STRIKE_HEIGHT;
1338 pdf_set_markup_appearance(doc, annot, color, alpha, line_thickness, line_height);
1341 static void update_rect(fz_context *ctx, pdf_annot *annot)
1343 pdf_to_rect(ctx, pdf_dict_gets(annot->obj, "Rect"), &annot->rect);
1344 annot->pagerect = annot->rect;
1345 fz_transform_rect(&annot->pagerect, &annot->page->ctm);
1348 void pdf_set_annot_appearance(pdf_document *doc, pdf_annot *annot, fz_rect *rect, fz_display_list *disp_list)
1350 fz_context *ctx = doc->ctx;
1351 pdf_obj *obj = annot->obj;
1352 const fz_matrix *page_ctm = &annot->page->ctm;
1354 fz_matrix mat = fz_identity;
1355 fz_device *dev = NULL;
1356 pdf_xobject *xobj = NULL;
1358 fz_invert_matrix(&ctm, page_ctm);
1364 fz_rect trect = *rect;
1366 fz_transform_rect(&trect, &ctm);
1368 pdf_dict_puts_drop(obj, "Rect", pdf_new_rect(doc, &trect));
1370 /* See if there is a current normal appearance */
1371 ap_obj = pdf_dict_getp(obj, "AP/N");
1372 if (!pdf_is_stream(doc, pdf_to_num(ap_obj), pdf_to_gen(ap_obj)))
1377 ap_obj = pdf_new_xobject(doc, &trect, &mat);
1378 pdf_dict_putp_drop(obj, "AP/N", ap_obj);
1382 pdf_xref_ensure_incremental_object(doc, pdf_to_num(ap_obj));
1383 /* Update bounding box and matrix in reused xobject obj */
1384 pdf_dict_puts_drop(ap_obj, "BBox", pdf_new_rect(doc, &trect));
1385 pdf_dict_puts_drop(ap_obj, "Matrix", pdf_new_matrix(doc, &mat));
1388 dev = pdf_new_pdf_device(doc, ap_obj, pdf_dict_gets(ap_obj, "Resources"), &mat);
1389 fz_run_display_list(disp_list, dev, &ctm, &fz_infinite_rect, NULL);
1390 fz_free_device(dev);
1392 /* Mark the appearance as changed - required for partial update */
1393 xobj = pdf_load_xobject(doc, ap_obj);
1396 /* Update bounding box and matrix also in the xobject structure */
1400 pdf_drop_xobject(ctx, xobj);
1405 update_rect(ctx, annot);
1409 fz_free_device(dev);
1415 quadpoints(pdf_document *doc, pdf_obj *annot, int *nout)
1417 fz_context *ctx = doc->ctx;
1418 pdf_obj *quad = pdf_dict_gets(annot, "QuadPoints");
1419 fz_point *qp = NULL;
1425 n = pdf_array_len(quad);
1433 qp = fz_malloc_array(ctx, n/2, sizeof(fz_point));
1435 for (i = 0; i < n; i += 2)
1437 qp[i/2].x = pdf_to_real(pdf_array_get(quad, i));
1438 qp[i/2].y = pdf_to_real(pdf_array_get(quad, i+1));
1452 void pdf_set_markup_appearance(pdf_document *doc, pdf_annot *annot, float color[3], float alpha, float line_thickness, float line_height)
1454 fz_context *ctx = doc->ctx;
1455 const fz_matrix *page_ctm = &annot->page->ctm;
1456 fz_path *path = NULL;
1457 fz_stroke_state *stroke = NULL;
1458 fz_device *dev = NULL;
1459 fz_display_list *strike_list = NULL;
1461 fz_point *qp = quadpoints(doc, annot->obj, &n);
1469 fz_var(strike_list);
1472 fz_rect rect = fz_empty_rect;
1474 rect.x0 = rect.x1 = qp[0].x;
1475 rect.y0 = rect.y1 = qp[0].y;
1476 for (i = 0; i < n; i++)
1477 fz_include_point_in_rect(&rect, &qp[i]);
1479 strike_list = fz_new_display_list(ctx);
1480 dev = fz_new_list_device(ctx, strike_list);
1482 for (i = 0; i < n; i += 4)
1484 fz_point pt0 = qp[i];
1485 fz_point pt1 = qp[i+1];
1489 up.x = qp[i+2].x - qp[i+1].x;
1490 up.y = qp[i+2].y - qp[i+1].y;
1492 pt0.x += line_height * up.x;
1493 pt0.y += line_height * up.y;
1494 pt1.x += line_height * up.x;
1495 pt1.y += line_height * up.y;
1497 thickness = sqrtf(up.x * up.x + up.y * up.y) * line_thickness;
1499 if (!stroke || fz_abs(stroke->linewidth - thickness) < SMALL_FLOAT)
1504 fz_stroke_path(dev, path, stroke, page_ctm, fz_device_rgb(ctx), color, alpha);
1505 fz_drop_stroke_state(ctx, stroke);
1507 fz_free_path(ctx, path);
1511 stroke = fz_new_stroke_state(ctx);
1512 stroke->linewidth = thickness;
1513 path = fz_new_path(ctx);
1516 fz_moveto(ctx, path, pt0.x, pt0.y);
1517 fz_lineto(ctx, path, pt1.x, pt1.y);
1522 fz_stroke_path(dev, path, stroke, page_ctm, fz_device_rgb(ctx), color, alpha);
1525 fz_transform_rect(&rect, page_ctm);
1526 pdf_set_annot_appearance(doc, annot, &rect, strike_list);
1531 fz_free_device(dev);
1532 fz_drop_stroke_state(ctx, stroke);
1533 fz_free_path(ctx, path);
1534 fz_drop_display_list(ctx, strike_list);
1542 static fz_colorspace *pdf_to_color(pdf_document *doc, pdf_obj *col, float color[4])
1545 int i, ncol = pdf_array_len(col);
1549 case 1: cs = fz_device_gray(doc->ctx); break;
1550 case 3: cs = fz_device_rgb(doc->ctx); break;
1551 case 4: cs = fz_device_cmyk(doc->ctx); break;
1552 default: return NULL;
1555 for (i = 0; i < ncol; i++)
1556 color[i] = pdf_to_real(pdf_array_get(col, i));
1561 void pdf_update_ink_appearance(pdf_document *doc, pdf_annot *annot)
1563 fz_context *ctx = doc->ctx;
1564 const fz_matrix *page_ctm = &annot->page->ctm;
1565 fz_path *path = NULL;
1566 fz_stroke_state *stroke = NULL;
1567 fz_device *dev = NULL;
1568 fz_display_list *strike_list = NULL;
1569 fz_colorspace *cs = NULL;
1574 fz_var(strike_list);
1578 fz_rect rect = fz_empty_rect;
1585 cs = pdf_to_color(doc, pdf_dict_gets(annot->obj, "C"), color);
1588 cs = fz_device_rgb(ctx);
1594 width = pdf_to_real(pdf_dict_gets(pdf_dict_gets(annot->obj, "BS"), "W"));
1598 list = pdf_dict_gets(annot->obj, "InkList");
1600 n = pdf_array_len(list);
1602 strike_list = fz_new_display_list(ctx);
1603 dev = fz_new_list_device(ctx, strike_list);
1604 path = fz_new_path(ctx);
1605 stroke = fz_new_stroke_state(ctx);
1606 stroke->linewidth = width;
1607 stroke->start_cap = stroke->end_cap = FZ_LINECAP_ROUND;
1608 stroke->linejoin = FZ_LINEJOIN_ROUND;
1610 for (i = 0; i < n; i ++)
1613 pdf_obj *arc = pdf_array_get(list, i);
1614 m = pdf_array_len(arc);
1616 for (j = 0; j < m-1; j += 2)
1619 pt.x = pdf_to_real(pdf_array_get(arc, j));
1620 pt.y = pdf_to_real(pdf_array_get(arc, j+1));
1622 if (i == 0 && j == 0)
1624 rect.x0 = rect.x1 = pt.x;
1625 rect.y0 = rect.y1 = pt.y;
1630 fz_include_point_in_rect(&rect, &pt);
1634 fz_moveto(ctx, path, pt.x, pt.y);
1636 fz_curvetov(ctx, path, pt_last.x, pt_last.y, (pt.x + pt_last.x) / 2, (pt.y + pt_last.y) / 2);
1639 fz_lineto(ctx, path, pt_last.x, pt_last.y);
1642 fz_stroke_path(dev, path, stroke, page_ctm, cs, color, 1.0f);
1644 fz_expand_rect(&rect, width);
1646 Expand the rectangle by width all around. We cannot use
1647 fz_expand_rect because the rectangle might be empty in the
1659 fz_transform_rect(&rect, page_ctm);
1660 pdf_set_annot_appearance(doc, annot, &rect, strike_list);
1664 fz_drop_colorspace(ctx, cs);
1665 fz_free_device(dev);
1666 fz_drop_stroke_state(ctx, stroke);
1667 fz_free_path(ctx, path);
1668 fz_drop_display_list(ctx, strike_list);
1676 static void add_text(fz_context *ctx, font_info *font_rec, fz_text *text, char *str, int str_len, float x, float y)
1678 fz_font *font = font_rec->font->font;
1679 int mask = FT_LOAD_NO_SCALE | FT_LOAD_IGNORE_TRANSFORM;
1685 /* FIXME: convert str from utf8 to WinAnsi */
1686 int gid = FT_Get_Char_Index(font->ft_face, *str);
1687 fz_add_text(ctx, text, gid, *str++, x, y);
1689 FT_Get_Advance(font->ft_face, gid, mask, &adv);
1690 x += ((float)adv) * font_rec->da_rec.font_size / ((FT_Face)font->ft_face)->units_per_EM;
1694 static fz_text *layout_text(fz_context *ctx, font_info *font_rec, char *str, float x, float y)
1697 fz_font *font = font_rec->font->font;
1700 fz_scale(&tm, font_rec->da_rec.font_size, font_rec->da_rec.font_size);
1701 text = fz_new_text(ctx, font, &tm, 0);
1705 add_text(ctx, font_rec, text, str, strlen(str), x, y);
1709 fz_free_text(ctx, text);
1716 static fz_text *fit_text(fz_context *ctx, font_info *font_rec, char *str, fz_rect *bounds)
1718 float width = bounds->x1 - bounds->x0;
1719 float height = bounds->y1 - bounds->y0;
1721 fz_text *text = NULL;
1722 text_splitter splitter;
1725 /* Initially aim for one-line of text */
1726 font_rec->da_rec.font_size = height / font_rec->lineheight;
1728 text_splitter_init(&splitter, font_rec, str, width, height, 1);
1734 while (!splitter.done)
1736 /* Try a layout pass */
1743 fz_free_text(ctx, text);
1745 font_size = font_rec->da_rec.font_size;
1746 fz_scale(&tm, font_size, font_size);
1747 text = fz_new_text(ctx, font_rec->font->font, &tm, 0);
1749 text_splitter_start_pass(&splitter);
1751 /* Layout unscaled text to a scaled-up width, so that
1752 * the scaled-down text will fit the unscaled width */
1754 while (!splitter.done && line < splitter.max_lines)
1757 text_splitter_start_line(&splitter);
1759 while (!splitter.done && text_splitter_layout(ctx, &splitter))
1761 if (splitter.text[splitter.text_start] != ' ')
1764 char *word = str+splitter.text_start;
1765 int wordlen = splitter.text_end-splitter.text_start;
1767 text_splitter_move(&splitter, -line, &dx, &dy);
1770 add_text(ctx, font_rec, text, word, wordlen, x, y);
1778 text_splitter_retry(&splitter);
1781 /* Post process text with the scale determined by the splitter
1782 * and with the required offst */
1783 fz_pre_scale(&text->trm, splitter.scale, splitter.scale);
1784 ascender = font_rec->font->ascent * font_rec->da_rec.font_size * splitter.scale / 1000.0f;
1785 for (i = 0; i < text->len; i++)
1787 text->items[i].x = text->items[i].x * splitter.scale + bounds->x0;
1788 text->items[i].y = text->items[i].y * splitter.scale + bounds->y1 - ascender;
1793 fz_free_text(ctx, text);
1800 static void rect_center(const fz_rect *rect, fz_point *c)
1802 c->x = (rect->x0 + rect->x1) / 2.0f;
1803 c->y = (rect->y0 + rect->y1) / 2.0f;
1806 static void center_rect_within_rect(const fz_rect *tofit, const fz_rect *within, fz_matrix *mat)
1808 float xscale = (within->x1 - within->x0) / (tofit->x1 - tofit->x0);
1809 float yscale = (within->y1 - within->y0) / (tofit->y1 - tofit->y0);
1810 float scale = fz_min(xscale, yscale);
1811 fz_point tofit_center;
1812 fz_point within_center;
1814 rect_center(within, &within_center);
1815 rect_center(tofit, &tofit_center);
1817 /* Translate "tofit" to be centered on the origin
1818 * Scale "tofit" to a size that fits within "within"
1819 * Translate "tofit" to "within's" center
1820 * Do all the above in reverse order so that we can use the fz_pre_xx functions */
1821 fz_translate(mat, within_center.x, within_center.y);
1822 fz_pre_scale(mat, scale, scale);
1823 fz_pre_translate(mat, -tofit_center.x, -tofit_center.y);
1826 static const float outline_thickness = 15.0f;
1828 static void draw_rounded_rect(fz_context *ctx, fz_path *path)
1830 fz_moveto(ctx, path, 20.0, 60.0);
1831 fz_curveto(ctx, path, 20.0, 30.0, 30.0, 20.0, 60.0, 20.0);
1832 fz_lineto(ctx, path, 340.0, 20.0);
1833 fz_curveto(ctx, path, 370.0, 20.0, 380.0, 30.0, 380.0, 60.0);
1834 fz_lineto(ctx, path, 380.0, 340.0);
1835 fz_curveto(ctx, path, 380.0, 370.0, 370.0, 380.0, 340.0, 380.0);
1836 fz_lineto(ctx, path, 60.0, 380.0);
1837 fz_curveto(ctx, path, 30.0, 380.0, 20.0, 370.0, 20.0, 340.0);
1838 fz_closepath(ctx, path);
1841 static void draw_speech_bubble(fz_context *ctx, fz_path *path)
1843 fz_moveto(ctx, path, 199.0f, 315.6f);
1844 fz_curveto(ctx, path, 35.6f, 315.6f, 27.0f, 160.8f, 130.2f, 131.77f);
1845 fz_curveto(ctx, path, 130.2f, 93.07f, 113.0f, 83.4f, 113.0f, 83.4f);
1846 fz_curveto(ctx, path, 138.8f, 73.72f, 173.2f, 83.4f, 190.4f, 122.1f);
1847 fz_curveto(ctx, path, 391.64f, 122.1f, 362.4f, 315.6f, 199.0f, 315.6f);
1848 fz_closepath(ctx, path);
1851 void pdf_update_text_annot_appearance(pdf_document *doc, pdf_annot *annot)
1853 static float white[3] = {1.0, 1.0, 1.0};
1854 static float yellow[3] = {1.0, 1.0, 0.0};
1855 static float black[3] = {0.0, 0.0, 0.0};
1856 fz_context *ctx = doc->ctx;
1857 const fz_matrix *page_ctm = &annot->page->ctm;
1858 fz_display_list *dlist = NULL;
1859 fz_device *dev = NULL;
1860 fz_colorspace *cs = NULL;
1861 fz_path *path = NULL;
1862 fz_stroke_state *stroke = NULL;
1875 pdf_to_rect(ctx, pdf_dict_gets(annot->obj, "Rect"), &rect);
1876 dlist = fz_new_display_list(ctx);
1877 dev = fz_new_list_device(ctx, dlist);
1878 stroke = fz_new_stroke_state(ctx);
1879 stroke->linewidth = outline_thickness;
1880 stroke->linejoin = FZ_LINEJOIN_ROUND;
1882 path = fz_new_path(ctx);
1883 draw_rounded_rect(ctx, path);
1884 fz_bound_path(ctx, path, NULL, &fz_identity, &bounds);
1885 fz_expand_rect(&bounds, outline_thickness);
1886 center_rect_within_rect(&bounds, &rect, &tm);
1887 fz_concat(&tm, &tm, page_ctm);
1888 cs = fz_device_rgb(ctx);
1889 fz_fill_path(dev, path, 0, &tm, cs, yellow, 1.0f);
1890 fz_stroke_path(dev, path, stroke, &tm, cs, black, 1.0f);
1891 fz_free_path(ctx, path);
1894 path = fz_new_path(ctx);
1895 draw_speech_bubble(ctx, path);
1896 fz_fill_path(dev, path, 0, &tm, cs, white, 1.0f);
1897 fz_stroke_path(dev, path, stroke, &tm, cs, black, 1.0f);
1899 fz_transform_rect(&rect, page_ctm);
1900 pdf_set_annot_appearance(doc, annot, &rect, dlist);
1902 /* Drop the cached xobject from the annotation structure to
1903 * force a redraw on next pdf_update_page call */
1904 pdf_drop_xobject(ctx, annot->ap);
1909 fz_free_device(dev);
1910 fz_drop_display_list(ctx, dlist);
1911 fz_drop_stroke_state(ctx, stroke);
1912 fz_free_path(ctx, path);
1913 fz_drop_colorspace(ctx, cs);
1921 void pdf_update_free_text_annot_appearance(pdf_document *doc, pdf_annot *annot)
1923 fz_context *ctx = doc->ctx;
1924 const fz_matrix *page_ctm = &annot->page->ctm;
1925 pdf_obj *obj = annot->obj;
1926 pdf_obj *dr = pdf_dict_getp(annot->page->me, "Resources");
1927 fz_display_list *dlist = NULL;
1928 fz_device *dev = NULL;
1930 fz_text *text = NULL;
1931 fz_colorspace *cs = NULL;
1933 memset(&font_rec, 0, sizeof(font_rec));
1935 /* Set some sane defaults in case the parsing of the font_rec fails */
1936 font_rec.da_rec.col_size = 1; /* Default to greyscale */
1937 font_rec.da_rec.font_size = 12; /* Default to 12 point */
1945 char *contents = pdf_to_str_buf(pdf_dict_gets(obj, "Contents"));
1946 char *da = pdf_to_str_buf(pdf_dict_gets(obj, "DA"));
1947 fz_rect rect = annot->rect;
1950 get_font_info(doc, dr, da, &font_rec);
1952 switch (font_rec.da_rec.col_size)
1954 default: cs = fz_device_gray(doc->ctx); break;
1955 case 3: cs = fz_device_rgb(doc->ctx); break;
1956 case 4: cs = fz_device_cmyk(doc->ctx); break;
1959 /* Adjust for the descender */
1961 pos.y = rect.y0 - font_rec.font->descent * font_rec.da_rec.font_size / 1000.0f;
1963 text = layout_text(ctx, &font_rec, contents, pos.x, pos.y);
1965 dlist = fz_new_display_list(ctx);
1966 dev = fz_new_list_device(ctx, dlist);
1967 fz_fill_text(dev, text, page_ctm, cs, font_rec.da_rec.col, 1.0f);
1969 fz_transform_rect(&rect, page_ctm);
1970 pdf_set_annot_appearance(doc, annot, &rect, dlist);
1974 fz_free_device(dev);
1975 fz_drop_display_list(ctx, dlist);
1976 font_info_fin(ctx, &font_rec);
1977 fz_free_text(ctx, text);
1978 fz_drop_colorspace(ctx, cs);
1986 static void draw_logo(fz_context *ctx, fz_path *path)
1988 fz_moveto(ctx, path, 122.25f, 0.0f);
1989 fz_lineto(ctx, path, 122.25f, 14.249f);
1990 fz_curveto(ctx, path, 125.98f, 13.842f, 129.73f, 13.518f, 133.5f, 13.277f);
1991 fz_lineto(ctx, path, 133.5f, 0.0f);
1992 fz_lineto(ctx, path, 122.25f, 0.0f);
1993 fz_closepath(ctx, path);
1994 fz_moveto(ctx, path, 140.251f, 0.0f);
1995 fz_lineto(ctx, path, 140.251f, 12.935f);
1996 fz_curveto(ctx, path, 152.534f, 12.477f, 165.03f, 12.899f, 177.75f, 14.249f);
1997 fz_lineto(ctx, path, 177.75f, 21.749f);
1998 fz_curveto(ctx, path, 165.304f, 20.413f, 152.809f, 19.871f, 140.251f, 20.348f);
1999 fz_lineto(ctx, path, 140.251f, 39.0f);
2000 fz_lineto(ctx, path, 133.5f, 39.0f);
2001 fz_lineto(ctx, path, 133.5f, 20.704f);
2002 fz_curveto(ctx, path, 129.756f, 20.956f, 126.006f, 21.302f, 122.25f, 21.749f);
2003 fz_lineto(ctx, path, 122.25f, 50.999f);
2004 fz_lineto(ctx, path, 177.751f, 50.999f);
2005 fz_lineto(ctx, path, 177.751f, 0.0f);
2006 fz_lineto(ctx, path, 140.251f, 0.0f);
2007 fz_closepath(ctx, path);
2008 fz_moveto(ctx, path, 23.482f, 129.419f);
2009 fz_curveto(ctx, path, -20.999f, 199.258f, -0.418f, 292.039f, 69.42f, 336.519f);
2010 fz_curveto(ctx, path, 139.259f, 381.0f, 232.04f, 360.419f, 276.52f, 290.581f);
2011 fz_curveto(ctx, path, 321.001f, 220.742f, 300.42f, 127.961f, 230.582f, 83.481f);
2012 fz_curveto(ctx, path, 160.743f, 39.0f, 67.962f, 59.581f, 23.482f, 129.419f);
2013 fz_closepath(ctx, path);
2014 fz_moveto(ctx, path, 254.751f, 128.492f);
2015 fz_curveto(ctx, path, 303.074f, 182.82f, 295.364f, 263.762f, 237.541f, 309.165f);
2016 fz_curveto(ctx, path, 179.718f, 354.568f, 93.57f, 347.324f, 45.247f, 292.996f);
2017 fz_curveto(ctx, path, -3.076f, 238.668f, 4.634f, 157.726f, 62.457f, 112.323f);
2018 fz_curveto(ctx, path, 120.28f, 66.92f, 206.428f, 74.164f, 254.751f, 128.492f);
2019 fz_closepath(ctx, path);
2020 fz_moveto(ctx, path, 111.0f, 98.999f);
2021 fz_curveto(ctx, path, 87.424f, 106.253f, 68.25f, 122.249f, 51.75f, 144.749f);
2022 fz_lineto(ctx, path, 103.5f, 297.749f);
2023 fz_lineto(ctx, path, 213.75f, 298.499f);
2024 fz_curveto(ctx, path, 206.25f, 306.749f, 195.744f, 311.478f, 185.25f, 314.249f);
2025 fz_curveto(ctx, path, 164.22f, 319.802f, 141.22f, 319.775f, 120.0f, 314.999f);
2026 fz_curveto(ctx, path, 96.658f, 309.745f, 77.25f, 298.499f, 55.5f, 283.499f);
2027 fz_curveto(ctx, path, 69.75f, 299.249f, 84.617f, 311.546f, 102.75f, 319.499f);
2028 fz_curveto(ctx, path, 117.166f, 325.822f, 133.509f, 327.689f, 149.25f, 327.749f);
2029 fz_curveto(ctx, path, 164.21f, 327.806f, 179.924f, 326.532f, 193.5f, 320.249f);
2030 fz_curveto(ctx, path, 213.95f, 310.785f, 232.5f, 294.749f, 245.25f, 276.749f);
2031 fz_lineto(ctx, path, 227.25f, 276.749f);
2032 fz_curveto(ctx, path, 213.963f, 276.749f, 197.25f, 263.786f, 197.25f, 250.499f);
2033 fz_lineto(ctx, path, 197.25f, 112.499f);
2034 fz_curveto(ctx, path, 213.75f, 114.749f, 228.0f, 127.499f, 241.5f, 140.999f);
2035 fz_curveto(ctx, path, 231.75f, 121.499f, 215.175f, 109.723f, 197.25f, 101.249f);
2036 fz_curveto(ctx, path, 181.5f, 95.249f, 168.412f, 94.775f, 153.0f, 94.499f);
2037 fz_curveto(ctx, path, 139.42f, 94.256f, 120.75f, 95.999f, 111.0f, 98.999f);
2038 fz_closepath(ctx, path);
2039 fz_moveto(ctx, path, 125.25f, 105.749f);
2040 fz_lineto(ctx, path, 125.25f, 202.499f);
2041 fz_lineto(ctx, path, 95.25f, 117.749f);
2042 fz_curveto(ctx, path, 105.75f, 108.749f, 114.0f, 105.749f, 125.25f, 105.749f);
2043 fz_closepath(ctx, path);
2046 static void insert_signature_appearance_layers(pdf_document *doc, pdf_annot *annot)
2048 fz_context *ctx = doc->ctx;
2049 pdf_obj *ap = pdf_dict_getp(annot->obj, "AP/N");
2050 pdf_obj *main_ap = NULL;
2051 pdf_obj *frm = NULL;
2054 fz_buffer *fzbuf = NULL;
2056 pdf_to_rect(ctx, pdf_dict_gets(ap, "BBox"), &bbox);
2064 main_ap = pdf_new_xobject(doc, &bbox, &fz_identity);
2065 frm = pdf_new_xobject(doc, &bbox, &fz_identity);
2066 n0 = pdf_new_xobject(doc, &bbox, &fz_identity);
2068 pdf_dict_putp(main_ap, "Resources/XObject/FRM", frm);
2069 fzbuf = fz_new_buffer(ctx, 8);
2070 fz_buffer_printf(ctx, fzbuf, "/FRM Do");
2071 pdf_update_stream(doc, pdf_to_num(main_ap), fzbuf);
2072 pdf_dict_puts_drop(main_ap, "Length", pdf_new_int(doc, fzbuf->len));
2073 fz_drop_buffer(ctx, fzbuf);
2076 pdf_dict_putp(frm, "Resources/XObject/n0", n0);
2077 pdf_dict_putp(frm, "Resources/XObject/n2", ap);
2078 fzbuf = fz_new_buffer(ctx, 8);
2079 fz_buffer_printf(ctx, fzbuf, "q 1 0 0 1 0 0 cm /n0 Do Q q 1 0 0 1 0 0 cm /n2 Do Q");
2080 pdf_update_stream(doc, pdf_to_num(frm), fzbuf);
2081 pdf_dict_puts_drop(frm, "Length", pdf_new_int(doc, fzbuf->len));
2082 fz_drop_buffer(ctx, fzbuf);
2085 fzbuf = fz_new_buffer(ctx, 8);
2086 fz_buffer_printf(ctx, fzbuf, "%% DSBlank");
2087 pdf_update_stream(doc, pdf_to_num(n0), fzbuf);
2088 pdf_dict_puts_drop(n0, "Length", pdf_new_int(doc, fzbuf->len));
2089 fz_drop_buffer(ctx, fzbuf);
2092 pdf_dict_putp(annot->obj, "AP/N", main_ap);
2096 pdf_drop_obj(main_ap);
2102 fz_drop_buffer(ctx, fzbuf);
2108 static float logo_color[3] = {(float)0x25/(float)0xFF, (float)0x72/(float)0xFF, (float)0xAC/(float)0xFF};
2110 void pdf_set_signature_appearance(pdf_document *doc, pdf_annot *annot, char *name, char *dn, char *date)
2112 fz_context *ctx = doc->ctx;
2113 const fz_matrix *page_ctm = &annot->page->ctm;
2114 pdf_obj *obj = annot->obj;
2115 pdf_obj *dr = pdf_dict_getp(pdf_trailer(doc), "Root/AcroForm/DR");
2116 fz_display_list *dlist = NULL;
2117 fz_device *dev = NULL;
2119 fz_text *text = NULL;
2120 fz_colorspace *cs = NULL;
2121 fz_path *path = NULL;
2122 fz_buffer *fzbuf = NULL;
2125 pdf_dict_putp_drop(pdf_trailer(doc), "Root/AcroForm/DR", pdf_new_dict(doc, 1));
2127 memset(&font_rec, 0, sizeof(font_rec));
2137 char *da = pdf_to_str_buf(pdf_dict_gets(obj, "DA"));
2138 fz_rect rect = annot->rect;
2139 fz_rect logo_bounds;
2141 unsigned char *bufstr;
2143 dlist = fz_new_display_list(ctx);
2144 dev = fz_new_list_device(ctx, dlist);
2146 path = fz_new_path(ctx);
2147 draw_logo(ctx, path);
2148 fz_bound_path(ctx, path, NULL, &fz_identity, &logo_bounds);
2149 center_rect_within_rect(&logo_bounds, &rect, &logo_tm);
2150 fz_concat(&logo_tm, &logo_tm, page_ctm);
2151 cs = fz_device_rgb(ctx);
2152 fz_fill_path(dev, path, 0, &logo_tm, cs, logo_color, 1.0f);
2153 fz_drop_colorspace(ctx, cs);
2156 get_font_info(doc, dr, da, &font_rec);
2158 switch (font_rec.da_rec.col_size)
2160 case 1: cs = fz_device_gray(ctx); break;
2161 case 3: cs = fz_device_rgb(ctx); break;
2162 case 4: cs = fz_device_cmyk(ctx); break;
2165 /* Display the name in the left-hand half of the form field */
2166 rect.x1 = (rect.x0 + rect.x1)/2.0f;
2167 text = fit_text(ctx, &font_rec, name, &rect);
2168 fz_fill_text(dev, text, page_ctm, cs, font_rec.da_rec.col, 1.0f);
2169 fz_free_text(ctx, text);
2172 /* Display the distinguished name in the right-hand half */
2173 fzbuf = fz_new_buffer(ctx, 256);
2174 fz_buffer_printf(ctx, fzbuf, "Digitally signed by %s", name);
2175 fz_buffer_printf(ctx, fzbuf, "\nDN: %s", dn);
2177 fz_buffer_printf(ctx, fzbuf, "\nDate: %s", date);
2178 (void)fz_buffer_storage(ctx, fzbuf, &bufstr);
2180 rect.x0 = (rect.x0 + rect.x1)/2.0f;
2181 text = fit_text(ctx, &font_rec, (char *)bufstr, &rect);
2182 fz_fill_text(dev, text, page_ctm, cs, font_rec.da_rec.col, 1.0f);
2185 fz_transform_rect(&rect, page_ctm);
2186 pdf_set_annot_appearance(doc, annot, &rect, dlist);
2188 /* Drop the cached xobject from the annotation structure to
2189 * force a redraw on next pdf_update_page call */
2190 pdf_drop_xobject(ctx, annot->ap);
2193 insert_signature_appearance_layers(doc, annot);
2197 fz_free_device(dev);
2198 fz_drop_display_list(ctx, dlist);
2199 font_info_fin(ctx, &font_rec);
2200 fz_free_path(ctx, path);
2201 fz_free_text(ctx, text);
2202 fz_drop_colorspace(ctx, cs);
2203 fz_drop_buffer(ctx, fzbuf);
2211 void pdf_update_appearance(pdf_document *doc, pdf_annot *annot)
2213 pdf_obj *obj = annot->obj;
2214 if (!pdf_dict_gets(obj, "AP") || pdf_obj_is_dirty(obj))
2216 fz_annot_type type = pdf_annot_obj_type(obj);
2219 case FZ_ANNOT_WIDGET:
2220 switch (pdf_field_type(doc, obj))
2222 case PDF_WIDGET_TYPE_TEXT:
2225 pdf_obj *formatting = pdf_dict_getp(obj, "AA/F");
2226 if (formatting && doc->js)
2228 /* Apply formatting */
2230 fz_context *ctx = doc->ctx;
2233 e.value = pdf_field_value(doc, obj);
2236 pdf_js_setup_event(doc->js, &e);
2240 fz_free(ctx, e.value);
2246 execute_action(doc, obj, formatting);
2247 /* Update appearance from JS event.value */
2248 pdf_update_text_appearance(doc, obj, pdf_js_get_event(doc->js)->value);
2253 /* Update appearance from field value */
2254 pdf_update_text_appearance(doc, obj, NULL);
2258 case PDF_WIDGET_TYPE_PUSHBUTTON:
2259 pdf_update_pushbutton_appearance(doc, obj);
2261 case PDF_WIDGET_TYPE_LISTBOX:
2262 case PDF_WIDGET_TYPE_COMBOBOX:
2263 /* Treating listbox and combobox identically for now,
2264 * and the behaviour is most appropriate for a combobox */
2265 pdf_update_combobox_appearance(doc, obj);
2270 pdf_update_text_annot_appearance(doc, annot);
2272 case FZ_ANNOT_FREETEXT:
2273 pdf_update_free_text_annot_appearance(doc, annot);
2275 case FZ_ANNOT_STRIKEOUT:
2276 case FZ_ANNOT_UNDERLINE:
2277 case FZ_ANNOT_HIGHLIGHT:
2278 pdf_update_text_markup_appearance(doc, annot, type);
2281 pdf_update_ink_appearance(doc, annot);