Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/source/pdf/pdf-annot.c @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 1:1d09e1dec1d9 | 2:b50eed0cc0ef |
|---|---|
| 1 // Copyright (C) 2004-2025 Artifex Software, Inc. | |
| 2 // | |
| 3 // This file is part of MuPDF. | |
| 4 // | |
| 5 // MuPDF is free software: you can redistribute it and/or modify it under the | |
| 6 // terms of the GNU Affero General Public License as published by the Free | |
| 7 // Software Foundation, either version 3 of the License, or (at your option) | |
| 8 // any later version. | |
| 9 // | |
| 10 // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY | |
| 11 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | |
| 12 // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more | |
| 13 // details. | |
| 14 // | |
| 15 // You should have received a copy of the GNU Affero General Public License | |
| 16 // along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html> | |
| 17 // | |
| 18 // Alternative licensing terms are available from the licensor. | |
| 19 // For commercial licensing, see <https://www.artifex.com/> or contact | |
| 20 // Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, | |
| 21 // CA 94129, USA, for further information. | |
| 22 | |
| 23 #include "mupdf/fitz.h" | |
| 24 #include "pdf-annot-imp.h" | |
| 25 | |
| 26 #include <string.h> | |
| 27 #include <float.h> | |
| 28 | |
| 29 pdf_annot * | |
| 30 pdf_keep_annot(fz_context *ctx, pdf_annot *annot) | |
| 31 { | |
| 32 return fz_keep_imp(ctx, annot, &annot->refs); | |
| 33 } | |
| 34 | |
| 35 void | |
| 36 pdf_drop_annot(fz_context *ctx, pdf_annot *annot) | |
| 37 { | |
| 38 if (fz_drop_imp(ctx, annot, &annot->refs)) | |
| 39 { | |
| 40 pdf_drop_obj(ctx, annot->obj); | |
| 41 fz_free(ctx, annot); | |
| 42 } | |
| 43 } | |
| 44 | |
| 45 void | |
| 46 pdf_drop_annots(fz_context *ctx, pdf_annot *annot) | |
| 47 { | |
| 48 while (annot) | |
| 49 { | |
| 50 pdf_annot *next = annot->next; | |
| 51 pdf_drop_annot(ctx, annot); | |
| 52 annot = next; | |
| 53 } | |
| 54 } | |
| 55 | |
| 56 pdf_obj * | |
| 57 pdf_annot_ap(fz_context *ctx, pdf_annot *annot) | |
| 58 { | |
| 59 int flags = pdf_dict_get_int(ctx, annot->obj, PDF_NAME(F)); | |
| 60 int readonly = flags & PDF_ANNOT_IS_READ_ONLY; | |
| 61 | |
| 62 pdf_obj *ap = pdf_dict_get(ctx, annot->obj, PDF_NAME(AP)); | |
| 63 pdf_obj *ap_n = pdf_dict_get(ctx, ap, PDF_NAME(N)); | |
| 64 pdf_obj *ap_r = pdf_dict_get(ctx, ap, PDF_NAME(R)); | |
| 65 pdf_obj *ap_d = pdf_dict_get(ctx, ap, PDF_NAME(D)); | |
| 66 | |
| 67 if (!readonly && annot->is_hot && annot->is_active && ap_d) | |
| 68 ap = ap_d; | |
| 69 else if (!readonly && annot->is_hot && ap_r) | |
| 70 ap = ap_r; | |
| 71 else | |
| 72 ap = ap_n; | |
| 73 | |
| 74 /* AP/N, AP/R and AP/D may be streams, or dictionaries of streams. */ | |
| 75 | |
| 76 /* If it's a stream, we have a winner! */ | |
| 77 if (pdf_is_indirect(ctx, ap) && pdf_obj_num_is_stream(ctx, annot->page->doc, pdf_to_num(ctx, ap))) | |
| 78 return ap; | |
| 79 | |
| 80 /* If it's not a stream, it may be a dictionary containing | |
| 81 * a range of possible values, that should be indexed by | |
| 82 * AS. */ | |
| 83 return pdf_dict_get(ctx, ap, pdf_resolve_indirect_chain(ctx, pdf_dict_get(ctx, annot->obj, PDF_NAME(AS)))); | |
| 84 } | |
| 85 | |
| 86 int pdf_annot_active(fz_context *ctx, pdf_annot *annot) | |
| 87 { | |
| 88 return annot ? annot->is_active : 0; | |
| 89 } | |
| 90 | |
| 91 void pdf_set_annot_active(fz_context *ctx, pdf_annot *annot, int active) | |
| 92 { | |
| 93 int old; | |
| 94 | |
| 95 if (!annot) | |
| 96 return; | |
| 97 | |
| 98 old = annot->is_active; | |
| 99 annot->is_active = !!active; | |
| 100 if (old != annot->is_active) | |
| 101 pdf_set_annot_has_changed(ctx, annot); | |
| 102 } | |
| 103 | |
| 104 int pdf_annot_hot(fz_context *ctx, pdf_annot *annot) | |
| 105 { | |
| 106 return annot ? annot->is_hot : 0; | |
| 107 } | |
| 108 | |
| 109 void pdf_set_annot_hot(fz_context *ctx, pdf_annot *annot, int hot) | |
| 110 { | |
| 111 int old; | |
| 112 | |
| 113 if (!annot) | |
| 114 return; | |
| 115 | |
| 116 old = annot->is_hot; | |
| 117 annot->is_hot = !!hot; | |
| 118 if (old != annot->is_hot) | |
| 119 pdf_set_annot_has_changed(ctx, annot); | |
| 120 } | |
| 121 | |
| 122 fz_matrix | |
| 123 pdf_annot_transform(fz_context *ctx, pdf_annot *annot) | |
| 124 { | |
| 125 fz_rect bbox, rect; | |
| 126 fz_matrix matrix; | |
| 127 float w, h, x, y; | |
| 128 pdf_obj *ap = pdf_annot_ap(ctx, annot); | |
| 129 | |
| 130 rect = pdf_dict_get_rect(ctx, annot->obj, PDF_NAME(Rect)); | |
| 131 bbox = pdf_xobject_bbox(ctx, ap); | |
| 132 matrix = pdf_xobject_matrix(ctx, ap); | |
| 133 | |
| 134 bbox = fz_transform_rect(bbox, matrix); | |
| 135 if (bbox.x1 == bbox.x0) | |
| 136 w = 0; | |
| 137 else | |
| 138 w = (rect.x1 - rect.x0) / (bbox.x1 - bbox.x0); | |
| 139 if (bbox.y1 == bbox.y0) | |
| 140 h = 0; | |
| 141 else | |
| 142 h = (rect.y1 - rect.y0) / (bbox.y1 - bbox.y0); | |
| 143 x = rect.x0 - (bbox.x0 * w); | |
| 144 y = rect.y0 - (bbox.y0 * h); | |
| 145 | |
| 146 return fz_pre_scale(fz_translate(x, y), w, h); | |
| 147 } | |
| 148 | |
| 149 /* | |
| 150 Internal function for creating a new pdf annotation. | |
| 151 */ | |
| 152 static pdf_annot * | |
| 153 pdf_new_annot(fz_context *ctx, pdf_page *page, pdf_obj *obj) | |
| 154 { | |
| 155 pdf_annot *annot; | |
| 156 | |
| 157 annot = fz_malloc_struct(ctx, pdf_annot); | |
| 158 annot->refs = 1; | |
| 159 annot->page = page; /* only borrowed, as the page owns the annot */ | |
| 160 annot->obj = pdf_keep_obj(ctx, obj); | |
| 161 | |
| 162 return annot; | |
| 163 } | |
| 164 | |
| 165 void | |
| 166 pdf_nuke_annots(fz_context *ctx, pdf_page *page) | |
| 167 { | |
| 168 pdf_annot *annot; | |
| 169 pdf_annot *next; | |
| 170 | |
| 171 for (annot = page->annots; annot; annot = next) | |
| 172 { | |
| 173 next = annot->next; | |
| 174 pdf_drop_obj(ctx, annot->obj); | |
| 175 annot->obj = NULL; | |
| 176 pdf_drop_annot(ctx, annot); | |
| 177 } | |
| 178 for (annot = page->widgets; annot; annot = next) | |
| 179 { | |
| 180 next = annot->next; | |
| 181 pdf_drop_obj(ctx, annot->obj); | |
| 182 annot->obj = NULL; | |
| 183 pdf_drop_annot(ctx, annot); | |
| 184 } | |
| 185 | |
| 186 page->annots = NULL; | |
| 187 page->widgets = NULL; | |
| 188 page->annot_tailp = &page->annots; | |
| 189 page->widget_tailp = &page->widgets; | |
| 190 } | |
| 191 | |
| 192 static pdf_annot *find_and_unlink_annot_from_list(fz_context *ctx, pdf_annot **prev, pdf_obj *obj) | |
| 193 { | |
| 194 int num = pdf_to_num(ctx, obj); | |
| 195 pdf_annot *node; | |
| 196 | |
| 197 node = *prev; | |
| 198 while (node) | |
| 199 { | |
| 200 if (pdf_to_num(ctx, node->obj) == num) | |
| 201 { | |
| 202 *prev = node->next; | |
| 203 node->next = NULL; | |
| 204 return node; | |
| 205 } | |
| 206 else | |
| 207 { | |
| 208 prev = &node->next; | |
| 209 node = node->next; | |
| 210 } | |
| 211 } | |
| 212 | |
| 213 return NULL; | |
| 214 } | |
| 215 | |
| 216 void | |
| 217 pdf_sync_annots(fz_context *ctx, pdf_page *page) | |
| 218 { | |
| 219 pdf_annot *old_annots; | |
| 220 pdf_annot *old_widgets; | |
| 221 pdf_annot *annot, *next; | |
| 222 pdf_obj *annots; | |
| 223 pdf_obj *subtype; | |
| 224 int i, n; | |
| 225 | |
| 226 // Save list of annots loaded last time (if any). | |
| 227 old_annots = page->annots; | |
| 228 old_widgets = page->widgets; | |
| 229 page->annots = NULL; | |
| 230 page->widgets = NULL; | |
| 231 page->annot_tailp = &page->annots; | |
| 232 page->widget_tailp = &page->widgets; | |
| 233 | |
| 234 // Create new list of annots (reusing old annots when possible) | |
| 235 annots = pdf_dict_get(ctx, page->obj, PDF_NAME(Annots)); | |
| 236 n = pdf_array_len(ctx, annots); | |
| 237 for (i = 0; i < n; ++i) | |
| 238 { | |
| 239 pdf_obj *obj = pdf_array_get(ctx, annots, i); | |
| 240 if (pdf_is_dict(ctx, obj)) | |
| 241 { | |
| 242 subtype = pdf_dict_get(ctx, obj, PDF_NAME(Subtype)); | |
| 243 if (pdf_name_eq(ctx, subtype, PDF_NAME(Link))) | |
| 244 continue; | |
| 245 if (pdf_name_eq(ctx, subtype, PDF_NAME(Popup))) | |
| 246 continue; | |
| 247 | |
| 248 if (pdf_name_eq(ctx, subtype, PDF_NAME(Widget))) | |
| 249 { | |
| 250 annot = find_and_unlink_annot_from_list(ctx, &old_widgets, obj); | |
| 251 if (!annot) | |
| 252 annot = pdf_new_annot(ctx, page, obj); | |
| 253 *page->widget_tailp = annot; | |
| 254 page->widget_tailp = &annot->next; | |
| 255 } | |
| 256 else | |
| 257 { | |
| 258 annot = find_and_unlink_annot_from_list(ctx, &old_annots, obj); | |
| 259 if (!annot) | |
| 260 annot = pdf_new_annot(ctx, page, obj); | |
| 261 *page->annot_tailp = annot; | |
| 262 page->annot_tailp = &annot->next; | |
| 263 } | |
| 264 } | |
| 265 } | |
| 266 | |
| 267 // Nuke the annot structs that are no longer used on the page | |
| 268 for (annot = old_annots; annot; annot = next) | |
| 269 { | |
| 270 next = annot->next; | |
| 271 pdf_drop_obj(ctx, annot->obj); | |
| 272 annot->obj = NULL; | |
| 273 pdf_drop_annot(ctx, annot); | |
| 274 } | |
| 275 for (annot = old_widgets; annot; annot = next) | |
| 276 { | |
| 277 next = annot->next; | |
| 278 pdf_drop_obj(ctx, annot->obj); | |
| 279 annot->obj = NULL; | |
| 280 pdf_drop_annot(ctx, annot); | |
| 281 } | |
| 282 } | |
| 283 | |
| 284 void | |
| 285 pdf_load_annots(fz_context *ctx, pdf_page *page) | |
| 286 { | |
| 287 pdf_sync_annots(ctx, page); | |
| 288 | |
| 289 /* We need to run a resynth pass on the annotations on this | |
| 290 * page. That means rerunning it on the complete document. */ | |
| 291 page->doc->resynth_required = 1; | |
| 292 /* And actually update the page so that any annotations required | |
| 293 * get synthesised. */ | |
| 294 pdf_update_page(ctx, page); | |
| 295 } | |
| 296 | |
| 297 pdf_annot * | |
| 298 pdf_first_annot(fz_context *ctx, pdf_page *page) | |
| 299 { | |
| 300 return page ? page->annots : NULL; | |
| 301 } | |
| 302 | |
| 303 pdf_annot * | |
| 304 pdf_next_annot(fz_context *ctx, pdf_annot *annot) | |
| 305 { | |
| 306 return annot ? annot->next : NULL; | |
| 307 } | |
| 308 | |
| 309 pdf_obj *pdf_annot_obj(fz_context *ctx, pdf_annot *annot) | |
| 310 { | |
| 311 return annot ? annot->obj : NULL; | |
| 312 } | |
| 313 | |
| 314 pdf_page *pdf_annot_page(fz_context *ctx, pdf_annot *annot) | |
| 315 { | |
| 316 return annot ? annot->page : NULL; | |
| 317 } | |
| 318 | |
| 319 fz_rect | |
| 320 pdf_bound_annot(fz_context *ctx, pdf_annot *annot) | |
| 321 { | |
| 322 fz_matrix page_ctm; | |
| 323 fz_rect rect; | |
| 324 int flags; | |
| 325 | |
| 326 pdf_annot_push_local_xref(ctx, annot); | |
| 327 | |
| 328 fz_try(ctx) | |
| 329 { | |
| 330 rect = pdf_dict_get_rect(ctx, annot->obj, PDF_NAME(Rect)); | |
| 331 pdf_page_transform(ctx, annot->page, NULL, &page_ctm); | |
| 332 | |
| 333 flags = pdf_dict_get_int(ctx, annot->obj, PDF_NAME(F)); | |
| 334 if (flags & PDF_ANNOT_IS_NO_ROTATE) | |
| 335 { | |
| 336 int rotate = pdf_dict_get_inheritable_int(ctx, annot->page->obj, PDF_NAME(Rotate)); | |
| 337 fz_point tp = fz_transform_point_xy(rect.x0, rect.y1, page_ctm); | |
| 338 page_ctm = fz_concat(page_ctm, fz_translate(-tp.x, -tp.y)); | |
| 339 page_ctm = fz_concat(page_ctm, fz_rotate(-rotate)); | |
| 340 page_ctm = fz_concat(page_ctm, fz_translate(tp.x, tp.y)); | |
| 341 } | |
| 342 } | |
| 343 fz_always(ctx) | |
| 344 pdf_annot_pop_local_xref(ctx, annot); | |
| 345 fz_catch(ctx) | |
| 346 fz_rethrow(ctx); | |
| 347 | |
| 348 return fz_transform_rect(rect, page_ctm); | |
| 349 } | |
| 350 | |
| 351 void | |
| 352 pdf_annot_request_resynthesis(fz_context *ctx, pdf_annot *annot) | |
| 353 { | |
| 354 if (annot == NULL) | |
| 355 return; | |
| 356 | |
| 357 annot->needs_new_ap = 1; | |
| 358 annot->page->doc->resynth_required = 1; | |
| 359 } | |
| 360 | |
| 361 void | |
| 362 pdf_annot_request_synthesis(fz_context *ctx, pdf_annot *annot) | |
| 363 { | |
| 364 if (annot == NULL) | |
| 365 return; | |
| 366 if (!pdf_annot_ap(ctx, annot)) | |
| 367 pdf_annot_request_resynthesis(ctx, annot); | |
| 368 } | |
| 369 | |
| 370 int | |
| 371 pdf_annot_needs_resynthesis(fz_context *ctx, pdf_annot *annot) | |
| 372 { | |
| 373 return annot ? annot->needs_new_ap : 0; | |
| 374 } | |
| 375 | |
| 376 void pdf_set_annot_resynthesised(fz_context *ctx, pdf_annot *annot) | |
| 377 { | |
| 378 if (annot == NULL) | |
| 379 return; | |
| 380 | |
| 381 annot->needs_new_ap = 0; | |
| 382 pdf_set_annot_has_changed(ctx, annot); | |
| 383 } | |
| 384 | |
| 385 void pdf_set_annot_has_changed(fz_context *ctx, pdf_annot *annot) | |
| 386 { | |
| 387 if (annot == NULL) | |
| 388 return; | |
| 389 | |
| 390 annot->has_new_ap = 1; | |
| 391 } | |
| 392 | |
| 393 void | |
| 394 pdf_dirty_annot(fz_context *ctx, pdf_annot *annot) | |
| 395 { | |
| 396 pdf_annot_request_resynthesis(ctx, annot); | |
| 397 } | |
| 398 | |
| 399 const char * | |
| 400 pdf_string_from_annot_type(fz_context *ctx, enum pdf_annot_type type) | |
| 401 { | |
| 402 switch (type) | |
| 403 { | |
| 404 case PDF_ANNOT_TEXT: return "Text"; | |
| 405 case PDF_ANNOT_LINK: return "Link"; | |
| 406 case PDF_ANNOT_FREE_TEXT: return "FreeText"; | |
| 407 case PDF_ANNOT_LINE: return "Line"; | |
| 408 case PDF_ANNOT_SQUARE: return "Square"; | |
| 409 case PDF_ANNOT_CIRCLE: return "Circle"; | |
| 410 case PDF_ANNOT_POLYGON: return "Polygon"; | |
| 411 case PDF_ANNOT_POLY_LINE: return "PolyLine"; | |
| 412 case PDF_ANNOT_HIGHLIGHT: return "Highlight"; | |
| 413 case PDF_ANNOT_UNDERLINE: return "Underline"; | |
| 414 case PDF_ANNOT_SQUIGGLY: return "Squiggly"; | |
| 415 case PDF_ANNOT_STRIKE_OUT: return "StrikeOut"; | |
| 416 case PDF_ANNOT_REDACT: return "Redact"; | |
| 417 case PDF_ANNOT_STAMP: return "Stamp"; | |
| 418 case PDF_ANNOT_CARET: return "Caret"; | |
| 419 case PDF_ANNOT_INK: return "Ink"; | |
| 420 case PDF_ANNOT_POPUP: return "Popup"; | |
| 421 case PDF_ANNOT_FILE_ATTACHMENT: return "FileAttachment"; | |
| 422 case PDF_ANNOT_SOUND: return "Sound"; | |
| 423 case PDF_ANNOT_MOVIE: return "Movie"; | |
| 424 case PDF_ANNOT_RICH_MEDIA: return "RichMedia"; | |
| 425 case PDF_ANNOT_WIDGET: return "Widget"; | |
| 426 case PDF_ANNOT_SCREEN: return "Screen"; | |
| 427 case PDF_ANNOT_PRINTER_MARK: return "PrinterMark"; | |
| 428 case PDF_ANNOT_TRAP_NET: return "TrapNet"; | |
| 429 case PDF_ANNOT_WATERMARK: return "Watermark"; | |
| 430 case PDF_ANNOT_3D: return "3D"; | |
| 431 case PDF_ANNOT_PROJECTION: return "Projection"; | |
| 432 default: return "UNKNOWN"; | |
| 433 } | |
| 434 } | |
| 435 | |
| 436 enum pdf_annot_type | |
| 437 pdf_annot_type_from_string(fz_context *ctx, const char *subtype) | |
| 438 { | |
| 439 if (!strcmp("Text", subtype)) return PDF_ANNOT_TEXT; | |
| 440 if (!strcmp("Link", subtype)) return PDF_ANNOT_LINK; | |
| 441 if (!strcmp("FreeText", subtype)) return PDF_ANNOT_FREE_TEXT; | |
| 442 if (!strcmp("Line", subtype)) return PDF_ANNOT_LINE; | |
| 443 if (!strcmp("Square", subtype)) return PDF_ANNOT_SQUARE; | |
| 444 if (!strcmp("Circle", subtype)) return PDF_ANNOT_CIRCLE; | |
| 445 if (!strcmp("Polygon", subtype)) return PDF_ANNOT_POLYGON; | |
| 446 if (!strcmp("PolyLine", subtype)) return PDF_ANNOT_POLY_LINE; | |
| 447 if (!strcmp("Highlight", subtype)) return PDF_ANNOT_HIGHLIGHT; | |
| 448 if (!strcmp("Underline", subtype)) return PDF_ANNOT_UNDERLINE; | |
| 449 if (!strcmp("Squiggly", subtype)) return PDF_ANNOT_SQUIGGLY; | |
| 450 if (!strcmp("StrikeOut", subtype)) return PDF_ANNOT_STRIKE_OUT; | |
| 451 if (!strcmp("Redact", subtype)) return PDF_ANNOT_REDACT; | |
| 452 if (!strcmp("Stamp", subtype)) return PDF_ANNOT_STAMP; | |
| 453 if (!strcmp("Caret", subtype)) return PDF_ANNOT_CARET; | |
| 454 if (!strcmp("Ink", subtype)) return PDF_ANNOT_INK; | |
| 455 if (!strcmp("Popup", subtype)) return PDF_ANNOT_POPUP; | |
| 456 if (!strcmp("FileAttachment", subtype)) return PDF_ANNOT_FILE_ATTACHMENT; | |
| 457 if (!strcmp("Sound", subtype)) return PDF_ANNOT_SOUND; | |
| 458 if (!strcmp("Movie", subtype)) return PDF_ANNOT_MOVIE; | |
| 459 if (!strcmp("RichMedia", subtype)) return PDF_ANNOT_RICH_MEDIA; | |
| 460 if (!strcmp("Widget", subtype)) return PDF_ANNOT_WIDGET; | |
| 461 if (!strcmp("Screen", subtype)) return PDF_ANNOT_SCREEN; | |
| 462 if (!strcmp("PrinterMark", subtype)) return PDF_ANNOT_PRINTER_MARK; | |
| 463 if (!strcmp("TrapNet", subtype)) return PDF_ANNOT_TRAP_NET; | |
| 464 if (!strcmp("Watermark", subtype)) return PDF_ANNOT_WATERMARK; | |
| 465 if (!strcmp("3D", subtype)) return PDF_ANNOT_3D; | |
| 466 if (!strcmp("Projection", subtype)) return PDF_ANNOT_PROJECTION; | |
| 467 return PDF_ANNOT_UNKNOWN; | |
| 468 } | |
| 469 | |
| 470 static void | |
| 471 begin_annot_op(fz_context *ctx, pdf_annot *annot, const char *op) | |
| 472 { | |
| 473 if (!annot->page) | |
| 474 fz_throw(ctx, FZ_ERROR_ARGUMENT, "annotation not bound to any page"); | |
| 475 | |
| 476 pdf_begin_operation(ctx, annot->page->doc, op); | |
| 477 } | |
| 478 | |
| 479 static void | |
| 480 end_annot_op(fz_context *ctx, pdf_annot *annot) | |
| 481 { | |
| 482 pdf_end_operation(ctx, annot->page->doc); | |
| 483 } | |
| 484 | |
| 485 static void | |
| 486 abandon_annot_op(fz_context *ctx, pdf_annot *annot) | |
| 487 { | |
| 488 pdf_abandon_operation(ctx, annot->page->doc); | |
| 489 } | |
| 490 | |
| 491 static int is_allowed_subtype(fz_context *ctx, pdf_annot *annot, pdf_obj *property, pdf_obj **allowed) | |
| 492 { | |
| 493 pdf_obj *subtype; | |
| 494 | |
| 495 subtype = pdf_dict_get(ctx, annot->obj, PDF_NAME(Subtype)); | |
| 496 while (*allowed) { | |
| 497 if (pdf_name_eq(ctx, subtype, *allowed)) | |
| 498 return 1; | |
| 499 allowed++; | |
| 500 } | |
| 501 | |
| 502 return 0; | |
| 503 } | |
| 504 | |
| 505 static int is_allowed_subtype_wrap(fz_context *ctx, pdf_annot *annot, pdf_obj *property, pdf_obj **allowed) | |
| 506 { | |
| 507 int ret; | |
| 508 | |
| 509 pdf_annot_push_local_xref(ctx, annot); | |
| 510 | |
| 511 fz_try(ctx) | |
| 512 ret = is_allowed_subtype(ctx, annot, property, allowed); | |
| 513 fz_always(ctx) | |
| 514 pdf_annot_pop_local_xref(ctx, annot); | |
| 515 fz_catch(ctx) | |
| 516 fz_rethrow(ctx); | |
| 517 | |
| 518 return ret; | |
| 519 } | |
| 520 | |
| 521 static void check_allowed_subtypes(fz_context *ctx, pdf_annot *annot, pdf_obj *property, pdf_obj **allowed) | |
| 522 { | |
| 523 pdf_obj *subtype; | |
| 524 | |
| 525 subtype = pdf_dict_get(ctx, annot->obj, PDF_NAME(Subtype)); | |
| 526 if (!is_allowed_subtype(ctx, annot, property, allowed)) | |
| 527 fz_throw(ctx, FZ_ERROR_ARGUMENT, "%s annotations have no %s property", pdf_to_name(ctx, subtype), pdf_to_name(ctx, property)); | |
| 528 } | |
| 529 | |
| 530 pdf_annot * | |
| 531 pdf_create_annot_raw(fz_context *ctx, pdf_page *page, enum pdf_annot_type type) | |
| 532 { | |
| 533 pdf_annot *annot = NULL; | |
| 534 pdf_document *doc = page->doc; | |
| 535 pdf_obj *annot_obj = pdf_new_dict(ctx, doc, 0); | |
| 536 pdf_obj *ind_obj = NULL; | |
| 537 pdf_obj *free_arr = NULL; | |
| 538 | |
| 539 fz_var(annot); | |
| 540 fz_var(ind_obj); | |
| 541 fz_var(free_arr); | |
| 542 fz_try(ctx) | |
| 543 { | |
| 544 int ind_obj_num; | |
| 545 const char *type_str; | |
| 546 pdf_obj *annot_arr; | |
| 547 | |
| 548 type_str = pdf_string_from_annot_type(ctx, type); | |
| 549 if (type == PDF_ANNOT_UNKNOWN) | |
| 550 fz_throw(ctx, FZ_ERROR_ARGUMENT, "cannot create unknown annotation"); | |
| 551 | |
| 552 annot_arr = pdf_dict_get(ctx, page->obj, PDF_NAME(Annots)); | |
| 553 if (!pdf_is_array(ctx, annot_arr)) | |
| 554 annot_arr = pdf_dict_put_array(ctx, page->obj, PDF_NAME(Annots), 0); | |
| 555 else if (pdf_is_indirect(ctx, annot_arr)) | |
| 556 { | |
| 557 free_arr = annot_arr = pdf_copy_array(ctx, annot_arr); | |
| 558 pdf_dict_put(ctx, page->obj, PDF_NAME(Annots), annot_arr); | |
| 559 } | |
| 560 | |
| 561 pdf_dict_put(ctx, annot_obj, PDF_NAME(Type), PDF_NAME(Annot)); | |
| 562 pdf_dict_put_name(ctx, annot_obj, PDF_NAME(Subtype), type_str); | |
| 563 | |
| 564 /* | |
| 565 Both annotation object and annotation structure are now created. | |
| 566 Insert the object in the hierarchy and the structure in the | |
| 567 page's array. | |
| 568 */ | |
| 569 ind_obj_num = pdf_create_object(ctx, doc); | |
| 570 pdf_update_object(ctx, doc, ind_obj_num, annot_obj); | |
| 571 ind_obj = pdf_new_indirect(ctx, doc, ind_obj_num, 0); | |
| 572 pdf_array_push(ctx, annot_arr, ind_obj); | |
| 573 | |
| 574 annot = pdf_new_annot(ctx, page, ind_obj); | |
| 575 | |
| 576 /* | |
| 577 Linking must be done after any call that might throw because | |
| 578 pdf_drop_annots below actually frees a list. Put the new annot | |
| 579 at the end of the list, so that it will be drawn last. | |
| 580 */ | |
| 581 if (type == PDF_ANNOT_WIDGET) | |
| 582 { | |
| 583 *page->widget_tailp = annot; | |
| 584 page->widget_tailp = &annot->next; | |
| 585 } | |
| 586 else | |
| 587 { | |
| 588 *page->annot_tailp = annot; | |
| 589 page->annot_tailp = &annot->next; | |
| 590 } | |
| 591 } | |
| 592 fz_always(ctx) | |
| 593 { | |
| 594 pdf_drop_obj(ctx, free_arr); | |
| 595 pdf_drop_obj(ctx, annot_obj); | |
| 596 pdf_drop_obj(ctx, ind_obj); | |
| 597 } | |
| 598 fz_catch(ctx) | |
| 599 { | |
| 600 pdf_drop_annots(ctx, annot); | |
| 601 fz_rethrow(ctx); | |
| 602 } | |
| 603 | |
| 604 return pdf_keep_annot(ctx, annot); | |
| 605 } | |
| 606 | |
| 607 fz_link * | |
| 608 pdf_create_link(fz_context *ctx, pdf_page *page, fz_rect bbox, const char *uri) | |
| 609 { | |
| 610 fz_link *link = NULL; | |
| 611 pdf_document *doc = page->doc; | |
| 612 pdf_obj *annot_obj = pdf_new_dict(ctx, doc, 0); | |
| 613 pdf_obj *ind_obj = NULL; | |
| 614 pdf_obj *bs = NULL; | |
| 615 pdf_obj *a = NULL; | |
| 616 fz_link **linkp; | |
| 617 fz_rect page_mediabox; | |
| 618 fz_matrix page_ctm; | |
| 619 fz_rect rect; | |
| 620 pdf_obj *free_arr = NULL; | |
| 621 | |
| 622 fz_var(link); | |
| 623 fz_var(ind_obj); | |
| 624 fz_var(bs); | |
| 625 fz_var(a); | |
| 626 fz_var(free_arr); | |
| 627 | |
| 628 pdf_begin_operation(ctx, page->doc, "Create Link"); | |
| 629 | |
| 630 fz_try(ctx) | |
| 631 { | |
| 632 int ind_obj_num; | |
| 633 pdf_obj *annot_arr; | |
| 634 | |
| 635 pdf_page_transform(ctx, page, &page_mediabox, &page_ctm); | |
| 636 page_ctm = fz_invert_matrix(page_ctm); | |
| 637 rect = fz_transform_rect(bbox, page_ctm); | |
| 638 | |
| 639 annot_arr = pdf_dict_get(ctx, page->obj, PDF_NAME(Annots)); | |
| 640 if (!pdf_is_array(ctx, annot_arr)) | |
| 641 annot_arr = pdf_dict_put_array(ctx, page->obj, PDF_NAME(Annots), 0); | |
| 642 else if (pdf_is_indirect(ctx, annot_arr)) | |
| 643 { | |
| 644 free_arr = annot_arr = pdf_copy_array(ctx, annot_arr); | |
| 645 pdf_dict_put(ctx, page->obj, PDF_NAME(Annots), annot_arr); | |
| 646 } | |
| 647 | |
| 648 pdf_dict_put(ctx, annot_obj, PDF_NAME(Type), PDF_NAME(Annot)); | |
| 649 pdf_dict_put(ctx, annot_obj, PDF_NAME(Subtype), PDF_NAME(Link)); | |
| 650 pdf_dict_put_rect(ctx, annot_obj, PDF_NAME(Rect), rect); | |
| 651 | |
| 652 bs = pdf_dict_put_dict(ctx, annot_obj, PDF_NAME(BS), 4); | |
| 653 pdf_dict_put(ctx, bs, PDF_NAME(S), PDF_NAME(S)); | |
| 654 pdf_dict_put(ctx, bs, PDF_NAME(Type), PDF_NAME(Border)); | |
| 655 pdf_dict_put_int(ctx, bs, PDF_NAME(W), 0); | |
| 656 | |
| 657 pdf_dict_put_drop(ctx, annot_obj, PDF_NAME(A), | |
| 658 pdf_new_action_from_link(ctx, doc, uri)); | |
| 659 | |
| 660 /* | |
| 661 Both annotation object and annotation structure are now created. | |
| 662 Insert the object in the hierarchy and the structure in the | |
| 663 page's array. | |
| 664 */ | |
| 665 ind_obj_num = pdf_create_object(ctx, doc); | |
| 666 pdf_update_object(ctx, doc, ind_obj_num, annot_obj); | |
| 667 ind_obj = pdf_new_indirect(ctx, doc, ind_obj_num, 0); | |
| 668 pdf_array_push(ctx, annot_arr, ind_obj); | |
| 669 | |
| 670 link = (fz_link *) pdf_new_link(ctx, page, bbox, uri, annot_obj); | |
| 671 | |
| 672 linkp = &page->links; | |
| 673 | |
| 674 while (*linkp != NULL) | |
| 675 linkp = &(*linkp)->next; | |
| 676 | |
| 677 *linkp = link; | |
| 678 pdf_end_operation(ctx, page->doc); | |
| 679 } | |
| 680 fz_always(ctx) | |
| 681 { | |
| 682 pdf_drop_obj(ctx, free_arr); | |
| 683 pdf_drop_obj(ctx, annot_obj); | |
| 684 pdf_drop_obj(ctx, ind_obj); | |
| 685 } | |
| 686 fz_catch(ctx) | |
| 687 { | |
| 688 pdf_abandon_operation(ctx, page->doc); | |
| 689 fz_rethrow(ctx); | |
| 690 } | |
| 691 | |
| 692 return fz_keep_link(ctx, link); | |
| 693 } | |
| 694 | |
| 695 void pdf_delete_link(fz_context *ctx, pdf_page *page, fz_link *link) | |
| 696 { | |
| 697 fz_link **linkptr; | |
| 698 pdf_obj *annots; | |
| 699 int i; | |
| 700 | |
| 701 if (link == NULL || page == NULL || page != ((pdf_link *) link)->page) | |
| 702 return; | |
| 703 | |
| 704 for (linkptr = &page->links; *linkptr; linkptr = &((*linkptr)->next)) | |
| 705 { | |
| 706 if (*linkptr == link) | |
| 707 break; | |
| 708 } | |
| 709 | |
| 710 if (*linkptr == NULL) | |
| 711 return; | |
| 712 | |
| 713 /* Link may no longer borrow page pointer, since they are separated */ | |
| 714 ((pdf_link *) link)->page = NULL; | |
| 715 | |
| 716 pdf_begin_operation(ctx, page->doc, "Delete Link"); | |
| 717 | |
| 718 fz_try(ctx) | |
| 719 { | |
| 720 | |
| 721 annots = pdf_dict_get(ctx, page->obj, PDF_NAME(Annots)); | |
| 722 i = pdf_array_find(ctx, annots, ((pdf_link *) link)->obj); | |
| 723 if (i >= 0) | |
| 724 pdf_array_delete(ctx, annots, i); | |
| 725 *linkptr = link->next; | |
| 726 link->next = NULL; | |
| 727 fz_drop_link(ctx, link); | |
| 728 pdf_end_operation(ctx, page->doc); | |
| 729 } | |
| 730 fz_catch(ctx) | |
| 731 { | |
| 732 pdf_abandon_operation(ctx, page->doc); | |
| 733 fz_rethrow(ctx); | |
| 734 } | |
| 735 } | |
| 736 | |
| 737 static pdf_obj * | |
| 738 pdf_add_popup_annot(fz_context *ctx, pdf_annot *annot) | |
| 739 { | |
| 740 pdf_obj *annots, *popup; | |
| 741 | |
| 742 popup = pdf_dict_get(ctx, annot->obj, PDF_NAME(Popup)); | |
| 743 if (popup) | |
| 744 return popup; | |
| 745 | |
| 746 annots = pdf_dict_get(ctx, annot->page->obj, PDF_NAME(Annots)); | |
| 747 if (!annots) | |
| 748 return NULL; | |
| 749 | |
| 750 popup = pdf_add_new_dict(ctx, annot->page->doc, 4); | |
| 751 pdf_array_push_drop(ctx, annots, popup); | |
| 752 | |
| 753 pdf_dict_put(ctx, popup, PDF_NAME(Type), PDF_NAME(Annot)); | |
| 754 pdf_dict_put(ctx, popup, PDF_NAME(Subtype), PDF_NAME(Popup)); | |
| 755 pdf_dict_put(ctx, popup, PDF_NAME(Parent), annot->obj); | |
| 756 pdf_dict_put_rect(ctx, popup, PDF_NAME(Rect), fz_make_rect(0,0,0,0)); | |
| 757 | |
| 758 pdf_dict_put(ctx, annot->obj, PDF_NAME(Popup), popup); | |
| 759 | |
| 760 return popup; | |
| 761 } | |
| 762 | |
| 763 static pdf_obj *popup_subtypes[] = { | |
| 764 PDF_NAME(Text), | |
| 765 PDF_NAME(FreeText), | |
| 766 PDF_NAME(Line), | |
| 767 PDF_NAME(Square), | |
| 768 PDF_NAME(Circle), | |
| 769 PDF_NAME(Polygon), | |
| 770 PDF_NAME(PolyLine), | |
| 771 PDF_NAME(Highlight), | |
| 772 PDF_NAME(Underline), | |
| 773 PDF_NAME(Squiggly), | |
| 774 PDF_NAME(StrikeOut), | |
| 775 PDF_NAME(Stamp), | |
| 776 PDF_NAME(Caret), | |
| 777 PDF_NAME(Ink), | |
| 778 PDF_NAME(FileAttachment), | |
| 779 PDF_NAME(Sound), | |
| 780 PDF_NAME(Redact), | |
| 781 NULL, | |
| 782 }; | |
| 783 | |
| 784 int | |
| 785 pdf_annot_has_popup(fz_context *ctx, pdf_annot *annot) | |
| 786 { | |
| 787 return is_allowed_subtype_wrap(ctx, annot, PDF_NAME(Popup), popup_subtypes); | |
| 788 } | |
| 789 | |
| 790 void pdf_set_annot_popup(fz_context *ctx, pdf_annot *annot, fz_rect rect) | |
| 791 { | |
| 792 fz_matrix page_ctm, inv_page_ctm; | |
| 793 pdf_obj *popup; | |
| 794 | |
| 795 begin_annot_op(ctx, annot, "Set popup"); | |
| 796 | |
| 797 fz_try(ctx) | |
| 798 { | |
| 799 check_allowed_subtypes(ctx, annot, PDF_NAME(Popup), popup_subtypes); | |
| 800 pdf_page_transform(ctx, annot->page, NULL, &page_ctm); | |
| 801 inv_page_ctm = fz_invert_matrix(page_ctm); | |
| 802 rect = fz_transform_rect(rect, inv_page_ctm); | |
| 803 popup = pdf_add_popup_annot(ctx, annot); | |
| 804 pdf_dict_put_rect(ctx, popup, PDF_NAME(Rect), rect); | |
| 805 end_annot_op(ctx, annot); | |
| 806 } | |
| 807 fz_catch(ctx) | |
| 808 { | |
| 809 abandon_annot_op(ctx, annot); | |
| 810 fz_rethrow(ctx); | |
| 811 } | |
| 812 | |
| 813 pdf_dirty_annot(ctx, annot); | |
| 814 } | |
| 815 | |
| 816 fz_rect pdf_annot_popup(fz_context *ctx, pdf_annot *annot) | |
| 817 { | |
| 818 fz_matrix page_ctm; | |
| 819 fz_rect rect; | |
| 820 pdf_obj *popup; | |
| 821 | |
| 822 pdf_annot_push_local_xref(ctx, annot); | |
| 823 | |
| 824 fz_try(ctx) | |
| 825 { | |
| 826 check_allowed_subtypes(ctx, annot, PDF_NAME(Popup), popup_subtypes); | |
| 827 pdf_page_transform(ctx, annot->page, NULL, &page_ctm); | |
| 828 popup = pdf_dict_get(ctx, annot->obj, PDF_NAME(Popup)); | |
| 829 rect = pdf_dict_get_rect(ctx, popup, PDF_NAME(Rect)); | |
| 830 rect = fz_transform_rect(rect, page_ctm); | |
| 831 } | |
| 832 fz_always(ctx) | |
| 833 pdf_annot_pop_local_xref(ctx, annot); | |
| 834 fz_catch(ctx) | |
| 835 fz_rethrow(ctx); | |
| 836 | |
| 837 return rect; | |
| 838 } | |
| 839 | |
| 840 pdf_annot * | |
| 841 pdf_create_annot(fz_context *ctx, pdf_page *page, enum pdf_annot_type type) | |
| 842 { | |
| 843 static const float black[3] = { 0, 0, 0 }; | |
| 844 static const float red[3] = { 1, 0, 0 }; | |
| 845 static const float green[3] = { 0, 1, 0 }; | |
| 846 static const float blue[3] = { 0, 0, 1 }; | |
| 847 static const float yellow[3] = { 1, 1, 0 }; | |
| 848 static const float magenta[3] = { 1, 0, 1 }; | |
| 849 | |
| 850 int flags = PDF_ANNOT_IS_PRINT; /* Make printable as default */ | |
| 851 | |
| 852 pdf_annot *annot = NULL; | |
| 853 | |
| 854 fz_var(annot); | |
| 855 | |
| 856 pdf_begin_operation(ctx, page->doc, "Create Annotation"); | |
| 857 | |
| 858 fz_try(ctx) | |
| 859 { | |
| 860 annot = pdf_create_annot_raw(ctx, page, type); | |
| 861 | |
| 862 switch (type) | |
| 863 { | |
| 864 default: | |
| 865 break; | |
| 866 | |
| 867 case PDF_ANNOT_TEXT: | |
| 868 case PDF_ANNOT_FILE_ATTACHMENT: | |
| 869 case PDF_ANNOT_SOUND: | |
| 870 { | |
| 871 fz_rect icon_rect = { 12, 12, 12+20, 12+20 }; | |
| 872 flags = PDF_ANNOT_IS_PRINT | PDF_ANNOT_IS_NO_ZOOM | PDF_ANNOT_IS_NO_ROTATE; | |
| 873 pdf_set_annot_rect(ctx, annot, icon_rect); | |
| 874 pdf_set_annot_color(ctx, annot, 3, yellow); | |
| 875 pdf_set_annot_popup(ctx, annot, fz_make_rect(32, 12, 32+200, 12+100)); | |
| 876 } | |
| 877 break; | |
| 878 | |
| 879 case PDF_ANNOT_FREE_TEXT: | |
| 880 { | |
| 881 fz_rect text_rect = { 12, 12, 12+200, 12+100 }; | |
| 882 | |
| 883 /* Use undocumented Adobe property to match page rotation. */ | |
| 884 int rot = pdf_dict_get_inheritable_int(ctx, page->obj, PDF_NAME(Rotate)); | |
| 885 if (rot != 0) | |
| 886 pdf_dict_put_int(ctx, annot->obj, PDF_NAME(Rotate), rot); | |
| 887 | |
| 888 pdf_set_annot_rect(ctx, annot, text_rect); | |
| 889 pdf_set_annot_border_width(ctx, annot, 0); | |
| 890 pdf_set_annot_default_appearance(ctx, annot, "Helv", 12, nelem(black), black); | |
| 891 } | |
| 892 break; | |
| 893 | |
| 894 case PDF_ANNOT_STAMP: | |
| 895 { | |
| 896 fz_rect stamp_rect = { 12, 12, 12+190, 12+50 }; | |
| 897 pdf_set_annot_rect(ctx, annot, stamp_rect); | |
| 898 pdf_set_annot_color(ctx, annot, 3, red); | |
| 899 pdf_set_annot_icon_name(ctx, annot, "Draft"); | |
| 900 } | |
| 901 break; | |
| 902 | |
| 903 case PDF_ANNOT_CARET: | |
| 904 { | |
| 905 fz_rect caret_rect = { 12, 12, 12+18, 12+15 }; | |
| 906 pdf_set_annot_rect(ctx, annot, caret_rect); | |
| 907 pdf_set_annot_color(ctx, annot, 3, blue); | |
| 908 } | |
| 909 break; | |
| 910 | |
| 911 case PDF_ANNOT_LINE: | |
| 912 { | |
| 913 fz_point a = { 12, 12 }, b = { 12 + 100, 12 + 50 }; | |
| 914 pdf_set_annot_line(ctx, annot, a, b); | |
| 915 pdf_set_annot_border_width(ctx, annot, 1); | |
| 916 pdf_set_annot_color(ctx, annot, 3, red); | |
| 917 } | |
| 918 break; | |
| 919 | |
| 920 case PDF_ANNOT_SQUARE: | |
| 921 case PDF_ANNOT_CIRCLE: | |
| 922 { | |
| 923 fz_rect shape_rect = { 12, 12, 12+100, 12+50 }; | |
| 924 fz_rect rd = { 0.5, 0.5, 0.5, 0.5 }; | |
| 925 pdf_set_annot_rect(ctx, annot, shape_rect); | |
| 926 pdf_dict_put_rect(ctx, annot->obj, PDF_NAME(RD), rd); | |
| 927 pdf_set_annot_border_width(ctx, annot, 1); | |
| 928 pdf_set_annot_color(ctx, annot, 3, red); | |
| 929 } | |
| 930 break; | |
| 931 | |
| 932 case PDF_ANNOT_POLYGON: | |
| 933 case PDF_ANNOT_POLY_LINE: | |
| 934 case PDF_ANNOT_INK: | |
| 935 { | |
| 936 fz_rect rd = { 0.5, 0.5, 0.5, 0.5 }; | |
| 937 pdf_set_annot_border_width(ctx, annot, 1); | |
| 938 pdf_dict_put_rect(ctx, annot->obj, PDF_NAME(RD), rd); | |
| 939 pdf_set_annot_color(ctx, annot, 3, red); | |
| 940 } | |
| 941 break; | |
| 942 | |
| 943 case PDF_ANNOT_HIGHLIGHT: | |
| 944 pdf_set_annot_color(ctx, annot, 3, yellow); | |
| 945 break; | |
| 946 case PDF_ANNOT_UNDERLINE: | |
| 947 pdf_set_annot_color(ctx, annot, 3, green); | |
| 948 break; | |
| 949 case PDF_ANNOT_STRIKE_OUT: | |
| 950 pdf_set_annot_color(ctx, annot, 3, red); | |
| 951 break; | |
| 952 case PDF_ANNOT_SQUIGGLY: | |
| 953 pdf_set_annot_color(ctx, annot, 3, magenta); | |
| 954 break; | |
| 955 } | |
| 956 | |
| 957 pdf_dict_put(ctx, annot->obj, PDF_NAME(P), page->obj); | |
| 958 pdf_dict_put_int(ctx, annot->obj, PDF_NAME(F), flags); | |
| 959 pdf_end_operation(ctx, page->doc); | |
| 960 } | |
| 961 fz_catch(ctx) | |
| 962 { | |
| 963 pdf_drop_annot(ctx, annot); | |
| 964 pdf_abandon_operation(ctx, page->doc); | |
| 965 fz_rethrow(ctx); | |
| 966 } | |
| 967 | |
| 968 return annot; | |
| 969 } | |
| 970 | |
| 971 static int | |
| 972 remove_from_tree(fz_context *ctx, pdf_obj *arr, pdf_obj *item, pdf_cycle_list *cycle_up) | |
| 973 { | |
| 974 pdf_cycle_list cycle; | |
| 975 int i, n, res = 0; | |
| 976 | |
| 977 if (arr == NULL || pdf_cycle(ctx, &cycle, cycle_up, arr)) | |
| 978 return 0; | |
| 979 | |
| 980 n = pdf_array_len(ctx, arr); | |
| 981 for (i = 0; i < n; ++i) | |
| 982 { | |
| 983 pdf_obj *obj = pdf_array_get(ctx, arr, i); | |
| 984 if (!pdf_objcmp(ctx, obj, item)) | |
| 985 { | |
| 986 pdf_array_delete(ctx, arr, i); | |
| 987 res = 1; | |
| 988 break; | |
| 989 } | |
| 990 | |
| 991 if (remove_from_tree(ctx, pdf_dict_get(ctx, obj, PDF_NAME(Kids)), item, &cycle)) | |
| 992 { | |
| 993 res = 1; | |
| 994 break; | |
| 995 } | |
| 996 } | |
| 997 | |
| 998 return res; | |
| 999 } | |
| 1000 | |
| 1001 void | |
| 1002 pdf_delete_annot(fz_context *ctx, pdf_page *page, pdf_annot *annot) | |
| 1003 { | |
| 1004 pdf_document *doc; | |
| 1005 pdf_annot **annotptr; | |
| 1006 pdf_obj *annot_arr, *popup; | |
| 1007 int i; | |
| 1008 int is_widget = 0; | |
| 1009 | |
| 1010 if (annot == NULL || page == NULL || page != annot->page) | |
| 1011 return; | |
| 1012 | |
| 1013 doc = page->doc; | |
| 1014 | |
| 1015 /* Look for the annot in the page's list */ | |
| 1016 for (annotptr = &page->annots; *annotptr; annotptr = &(*annotptr)->next) | |
| 1017 { | |
| 1018 if (*annotptr == annot) | |
| 1019 break; | |
| 1020 } | |
| 1021 | |
| 1022 if (*annotptr == NULL) | |
| 1023 { | |
| 1024 is_widget = 1; | |
| 1025 | |
| 1026 /* Look also in the widget list*/ | |
| 1027 for (annotptr = &page->widgets; *annotptr; annotptr = &(*annotptr)->next) | |
| 1028 { | |
| 1029 if (*annotptr == annot) | |
| 1030 break; | |
| 1031 } | |
| 1032 } | |
| 1033 | |
| 1034 /* Check the passed annotation was of this page */ | |
| 1035 if (*annotptr == NULL) | |
| 1036 return; | |
| 1037 | |
| 1038 pdf_begin_operation(ctx, page->doc, "Delete Annotation"); | |
| 1039 | |
| 1040 /* Remove annot from page's list */ | |
| 1041 *annotptr = annot->next; | |
| 1042 | |
| 1043 /* Annot may no longer borrow page pointer, since they are separated */ | |
| 1044 annot->page = NULL; | |
| 1045 | |
| 1046 /* If the removed annotation was the last in the list adjust the end pointer */ | |
| 1047 if (*annotptr == NULL) | |
| 1048 { | |
| 1049 if (is_widget) | |
| 1050 page->widget_tailp = annotptr; | |
| 1051 else | |
| 1052 page->annot_tailp = annotptr; | |
| 1053 } | |
| 1054 | |
| 1055 fz_try(ctx) | |
| 1056 { | |
| 1057 /* Remove the annot from the "Annots" array. */ | |
| 1058 annot_arr = pdf_dict_get(ctx, page->obj, PDF_NAME(Annots)); | |
| 1059 i = pdf_array_find(ctx, annot_arr, annot->obj); | |
| 1060 if (i >= 0) | |
| 1061 pdf_array_delete(ctx, annot_arr, i); | |
| 1062 | |
| 1063 /* Remove the associated Popup annotation from the Annots array */ | |
| 1064 popup = pdf_dict_get(ctx, annot->obj, PDF_NAME(Popup)); | |
| 1065 if (popup) | |
| 1066 { | |
| 1067 i = pdf_array_find(ctx, annot_arr, popup); | |
| 1068 if (i >= 0) | |
| 1069 pdf_array_delete(ctx, annot_arr, i); | |
| 1070 } | |
| 1071 | |
| 1072 /* For a widget, remove also from the AcroForm tree */ | |
| 1073 if (is_widget) | |
| 1074 { | |
| 1075 pdf_obj *root = pdf_dict_get(ctx, pdf_trailer(ctx, doc), PDF_NAME(Root)); | |
| 1076 pdf_obj *acroform = pdf_dict_get(ctx, root, PDF_NAME(AcroForm)); | |
| 1077 pdf_obj *fields = pdf_dict_get(ctx, acroform, PDF_NAME(Fields)); | |
| 1078 (void)remove_from_tree(ctx, fields, annot->obj, NULL); | |
| 1079 } | |
| 1080 | |
| 1081 /* The garbage collection pass when saving will remove the annot object, | |
| 1082 * removing it here may break files if multiple pages use the same annot. */ | |
| 1083 pdf_end_operation(ctx, page->doc); | |
| 1084 } | |
| 1085 fz_always(ctx) | |
| 1086 { | |
| 1087 /* Drop the reference to annot previously held by the page list. */ | |
| 1088 pdf_drop_annot(ctx, annot); | |
| 1089 } | |
| 1090 fz_catch(ctx) | |
| 1091 { | |
| 1092 pdf_abandon_operation(ctx, page->doc); | |
| 1093 fz_rethrow(ctx); | |
| 1094 } | |
| 1095 } | |
| 1096 | |
| 1097 enum pdf_annot_type | |
| 1098 pdf_annot_type(fz_context *ctx, pdf_annot *annot) | |
| 1099 { | |
| 1100 enum pdf_annot_type ret; | |
| 1101 | |
| 1102 pdf_annot_push_local_xref(ctx, annot); | |
| 1103 | |
| 1104 fz_try(ctx) | |
| 1105 { | |
| 1106 const char *subtype = pdf_dict_get_name(ctx, annot->obj, PDF_NAME(Subtype)); | |
| 1107 ret = pdf_annot_type_from_string(ctx, subtype); | |
| 1108 } | |
| 1109 fz_always(ctx) | |
| 1110 pdf_annot_pop_local_xref(ctx, annot); | |
| 1111 fz_catch(ctx) | |
| 1112 fz_rethrow(ctx); | |
| 1113 | |
| 1114 return ret; | |
| 1115 } | |
| 1116 | |
| 1117 int | |
| 1118 pdf_annot_flags(fz_context *ctx, pdf_annot *annot) | |
| 1119 { | |
| 1120 int ret; | |
| 1121 pdf_annot_push_local_xref(ctx, annot); | |
| 1122 | |
| 1123 fz_try(ctx) | |
| 1124 ret = pdf_dict_get_int(ctx, annot->obj, PDF_NAME(F)); | |
| 1125 fz_always(ctx) | |
| 1126 pdf_annot_pop_local_xref(ctx, annot); | |
| 1127 fz_catch(ctx) | |
| 1128 fz_rethrow(ctx); | |
| 1129 | |
| 1130 return ret; | |
| 1131 } | |
| 1132 | |
| 1133 void | |
| 1134 pdf_set_annot_flags(fz_context *ctx, pdf_annot *annot, int flags) | |
| 1135 { | |
| 1136 begin_annot_op(ctx, annot, "Set flags"); | |
| 1137 | |
| 1138 fz_try(ctx) | |
| 1139 { | |
| 1140 pdf_dict_put_int(ctx, annot->obj, PDF_NAME(F), flags); | |
| 1141 end_annot_op(ctx, annot); | |
| 1142 } | |
| 1143 fz_catch(ctx) | |
| 1144 { | |
| 1145 abandon_annot_op(ctx, annot); | |
| 1146 fz_rethrow(ctx); | |
| 1147 } | |
| 1148 | |
| 1149 pdf_dirty_annot(ctx, annot); | |
| 1150 } | |
| 1151 | |
| 1152 static pdf_obj *rect_subtypes[] = { | |
| 1153 PDF_NAME(Text), | |
| 1154 PDF_NAME(FreeText), | |
| 1155 PDF_NAME(Square), | |
| 1156 PDF_NAME(Circle), | |
| 1157 PDF_NAME(Redact), | |
| 1158 PDF_NAME(Stamp), | |
| 1159 PDF_NAME(Caret), | |
| 1160 PDF_NAME(Popup), | |
| 1161 PDF_NAME(FileAttachment), | |
| 1162 PDF_NAME(Sound), | |
| 1163 PDF_NAME(Movie), | |
| 1164 PDF_NAME(Widget), | |
| 1165 NULL, | |
| 1166 }; | |
| 1167 | |
| 1168 int | |
| 1169 pdf_annot_has_rect(fz_context *ctx, pdf_annot *annot) | |
| 1170 { | |
| 1171 /* True for annotations where the user can manipulate the size or location | |
| 1172 * of the annotation through the Rect. | |
| 1173 * False for annotations where the Rect is computed from other | |
| 1174 * annotation data such as InkList, QuadPoints, and Vertices. | |
| 1175 */ | |
| 1176 return is_allowed_subtype_wrap(ctx, annot, PDF_NAME(Rect), rect_subtypes); | |
| 1177 } | |
| 1178 | |
| 1179 fz_rect | |
| 1180 pdf_annot_rect(fz_context *ctx, pdf_annot *annot) | |
| 1181 { | |
| 1182 fz_matrix page_ctm; | |
| 1183 fz_rect rect; | |
| 1184 fz_rect rd; | |
| 1185 | |
| 1186 pdf_annot_push_local_xref(ctx, annot); | |
| 1187 fz_try(ctx) | |
| 1188 { | |
| 1189 check_allowed_subtypes(ctx, annot, PDF_NAME(Rect), rect_subtypes); | |
| 1190 pdf_page_transform(ctx, annot->page, NULL, &page_ctm); | |
| 1191 rect = pdf_dict_get_rect(ctx, annot->obj, PDF_NAME(Rect)); | |
| 1192 | |
| 1193 /* remove RD adjustment from bounding box to get design box */ | |
| 1194 rd = pdf_annot_rect_diff(ctx, annot); | |
| 1195 rect.x0 += rd.x0; | |
| 1196 rect.x1 -= rd.x1; | |
| 1197 rect.y0 += rd.y0; | |
| 1198 rect.y1 -= rd.y1; | |
| 1199 } | |
| 1200 fz_always(ctx) | |
| 1201 pdf_annot_pop_local_xref(ctx, annot); | |
| 1202 fz_catch(ctx) | |
| 1203 fz_rethrow(ctx); | |
| 1204 | |
| 1205 return fz_transform_rect(rect, page_ctm); | |
| 1206 } | |
| 1207 | |
| 1208 void | |
| 1209 pdf_set_annot_rect(fz_context *ctx, pdf_annot *annot, fz_rect rect) | |
| 1210 { | |
| 1211 fz_matrix page_ctm, inv_page_ctm; | |
| 1212 fz_rect rd; | |
| 1213 | |
| 1214 begin_annot_op(ctx, annot, "Set rectangle"); | |
| 1215 | |
| 1216 fz_try(ctx) | |
| 1217 { | |
| 1218 check_allowed_subtypes(ctx, annot, PDF_NAME(Rect), rect_subtypes); | |
| 1219 | |
| 1220 pdf_page_transform(ctx, annot->page, NULL, &page_ctm); | |
| 1221 inv_page_ctm = fz_invert_matrix(page_ctm); | |
| 1222 rect = fz_transform_rect(rect, inv_page_ctm); | |
| 1223 | |
| 1224 /* add RD adjustment to design box to get bounding box */ | |
| 1225 rd = pdf_annot_rect_diff(ctx, annot); | |
| 1226 rect.x0 -= rd.x0; | |
| 1227 rect.x1 += rd.x1; | |
| 1228 rect.y0 -= rd.y0; | |
| 1229 rect.y1 += rd.y1; | |
| 1230 | |
| 1231 pdf_dict_put_rect(ctx, annot->obj, PDF_NAME(Rect), rect); | |
| 1232 | |
| 1233 /* recalculate callout line as necessary */ | |
| 1234 if (pdf_annot_has_callout(ctx, annot)) | |
| 1235 { | |
| 1236 pdf_set_annot_callout_point(ctx, annot, pdf_annot_callout_point(ctx, annot)); | |
| 1237 } | |
| 1238 | |
| 1239 pdf_dirty_annot(ctx, annot); | |
| 1240 end_annot_op(ctx, annot); | |
| 1241 } | |
| 1242 fz_catch(ctx) | |
| 1243 { | |
| 1244 abandon_annot_op(ctx, annot); | |
| 1245 fz_rethrow(ctx); | |
| 1246 } | |
| 1247 } | |
| 1248 | |
| 1249 const char * | |
| 1250 pdf_annot_contents(fz_context *ctx, pdf_annot *annot) | |
| 1251 { | |
| 1252 return pdf_dict_get_text_string(ctx, annot->obj, PDF_NAME(Contents)); | |
| 1253 } | |
| 1254 | |
| 1255 void | |
| 1256 pdf_set_annot_contents(fz_context *ctx, pdf_annot *annot, const char *text) | |
| 1257 { | |
| 1258 begin_annot_op(ctx, annot, "Set contents"); | |
| 1259 | |
| 1260 fz_try(ctx) | |
| 1261 { | |
| 1262 pdf_dict_put_text_string(ctx, annot->obj, PDF_NAME(Contents), text); | |
| 1263 pdf_dict_del(ctx, annot->obj, PDF_NAME(RC)); /* not supported */ | |
| 1264 pdf_dirty_annot(ctx, annot); | |
| 1265 end_annot_op(ctx, annot); | |
| 1266 } | |
| 1267 fz_catch(ctx) | |
| 1268 { | |
| 1269 abandon_annot_op(ctx, annot); | |
| 1270 fz_rethrow(ctx); | |
| 1271 } | |
| 1272 } | |
| 1273 | |
| 1274 static pdf_obj *markup_subtypes[] = { | |
| 1275 PDF_NAME(Text), | |
| 1276 PDF_NAME(FreeText), | |
| 1277 PDF_NAME(Line), | |
| 1278 PDF_NAME(Square), | |
| 1279 PDF_NAME(Circle), | |
| 1280 PDF_NAME(Polygon), | |
| 1281 PDF_NAME(PolyLine), | |
| 1282 PDF_NAME(Highlight), | |
| 1283 PDF_NAME(Underline), | |
| 1284 PDF_NAME(Squiggly), | |
| 1285 PDF_NAME(StrikeOut), | |
| 1286 PDF_NAME(Redact), | |
| 1287 PDF_NAME(Stamp), | |
| 1288 PDF_NAME(Caret), | |
| 1289 PDF_NAME(Ink), | |
| 1290 PDF_NAME(FileAttachment), | |
| 1291 PDF_NAME(Sound), | |
| 1292 NULL, | |
| 1293 }; | |
| 1294 | |
| 1295 int | |
| 1296 pdf_annot_has_rich_contents(fz_context *ctx, pdf_annot *annot) | |
| 1297 { | |
| 1298 return is_allowed_subtype_wrap(ctx, annot, PDF_NAME(RC), markup_subtypes); | |
| 1299 } | |
| 1300 | |
| 1301 const char * | |
| 1302 pdf_annot_rich_contents(fz_context *ctx, pdf_annot *annot) | |
| 1303 { | |
| 1304 check_allowed_subtypes(ctx, annot, PDF_NAME(RC), markup_subtypes); | |
| 1305 return pdf_dict_get_text_string(ctx, annot->obj, PDF_NAME(RC)); | |
| 1306 } | |
| 1307 | |
| 1308 void | |
| 1309 pdf_set_annot_rich_contents(fz_context *ctx, pdf_annot *annot, const char *plain, const char *rich) | |
| 1310 { | |
| 1311 begin_annot_op(ctx, annot, "Set rich contents"); | |
| 1312 fz_try(ctx) | |
| 1313 { | |
| 1314 check_allowed_subtypes(ctx, annot, PDF_NAME(RC), markup_subtypes); | |
| 1315 pdf_dict_put_text_string(ctx, annot->obj, PDF_NAME(Contents), plain); | |
| 1316 pdf_dict_put_text_string(ctx, annot->obj, PDF_NAME(RC), rich); | |
| 1317 pdf_dirty_annot(ctx, annot); | |
| 1318 end_annot_op(ctx, annot); | |
| 1319 } | |
| 1320 fz_catch(ctx) | |
| 1321 { | |
| 1322 abandon_annot_op(ctx, annot); | |
| 1323 fz_rethrow(ctx); | |
| 1324 } | |
| 1325 } | |
| 1326 | |
| 1327 static pdf_obj *default_style_subtypes[] = { | |
| 1328 PDF_NAME(FreeText), | |
| 1329 PDF_NAME(Widget), | |
| 1330 NULL, | |
| 1331 }; | |
| 1332 | |
| 1333 int | |
| 1334 pdf_annot_has_rich_defaults(fz_context *ctx, pdf_annot *annot) | |
| 1335 { | |
| 1336 return is_allowed_subtype_wrap(ctx, annot, PDF_NAME(DS), default_style_subtypes); | |
| 1337 } | |
| 1338 | |
| 1339 const char * | |
| 1340 pdf_annot_rich_defaults(fz_context *ctx, pdf_annot *annot) | |
| 1341 { | |
| 1342 check_allowed_subtypes(ctx, annot, PDF_NAME(DS), default_style_subtypes); | |
| 1343 return pdf_dict_get_text_string(ctx, annot->obj, PDF_NAME(DS)); | |
| 1344 } | |
| 1345 | |
| 1346 void | |
| 1347 pdf_set_annot_rich_defaults(fz_context *ctx, pdf_annot *annot, const char *style) | |
| 1348 { | |
| 1349 begin_annot_op(ctx, annot, "Set rich defaults"); | |
| 1350 fz_try(ctx) | |
| 1351 { | |
| 1352 check_allowed_subtypes(ctx, annot, PDF_NAME(DS), default_style_subtypes); | |
| 1353 pdf_dict_put_text_string(ctx, annot->obj, PDF_NAME(DS), style); | |
| 1354 pdf_dirty_annot(ctx, annot); | |
| 1355 end_annot_op(ctx, annot); | |
| 1356 } | |
| 1357 fz_catch(ctx) | |
| 1358 { | |
| 1359 abandon_annot_op(ctx, annot); | |
| 1360 fz_rethrow(ctx); | |
| 1361 } | |
| 1362 } | |
| 1363 | |
| 1364 int | |
| 1365 pdf_annot_has_open(fz_context *ctx, pdf_annot *annot) | |
| 1366 { | |
| 1367 int ret; | |
| 1368 | |
| 1369 pdf_annot_push_local_xref(ctx, annot); | |
| 1370 | |
| 1371 fz_try(ctx) | |
| 1372 { | |
| 1373 pdf_obj *subtype = pdf_dict_get(ctx, annot->obj, PDF_NAME(Subtype)); | |
| 1374 pdf_obj *popup = pdf_dict_get(ctx, annot->obj, PDF_NAME(Popup)); | |
| 1375 ret = (subtype == PDF_NAME(Text) || popup); | |
| 1376 } | |
| 1377 fz_always(ctx) | |
| 1378 pdf_annot_pop_local_xref(ctx, annot); | |
| 1379 fz_catch(ctx) | |
| 1380 fz_rethrow(ctx); | |
| 1381 | |
| 1382 return ret; | |
| 1383 } | |
| 1384 | |
| 1385 int | |
| 1386 pdf_annot_is_open(fz_context *ctx, pdf_annot *annot) | |
| 1387 { | |
| 1388 int ret = 0; | |
| 1389 | |
| 1390 pdf_annot_push_local_xref(ctx, annot); | |
| 1391 | |
| 1392 fz_try(ctx) | |
| 1393 { | |
| 1394 pdf_obj *subtype = pdf_dict_get(ctx, annot->obj, PDF_NAME(Subtype)); | |
| 1395 pdf_obj *popup = pdf_dict_get(ctx, annot->obj, PDF_NAME(Popup)); | |
| 1396 if (popup) | |
| 1397 ret = pdf_dict_get_bool(ctx, popup, PDF_NAME(Open)); | |
| 1398 else if (subtype == PDF_NAME(Text)) | |
| 1399 ret = pdf_dict_get_bool(ctx, annot->obj, PDF_NAME(Open)); | |
| 1400 } | |
| 1401 fz_always(ctx) | |
| 1402 pdf_annot_pop_local_xref(ctx, annot); | |
| 1403 fz_catch(ctx) | |
| 1404 fz_rethrow(ctx); | |
| 1405 | |
| 1406 return ret; | |
| 1407 } | |
| 1408 | |
| 1409 void | |
| 1410 pdf_set_annot_is_open(fz_context *ctx, pdf_annot *annot, int is_open) | |
| 1411 { | |
| 1412 begin_annot_op(ctx, annot, is_open ? "Open" : "Close"); | |
| 1413 | |
| 1414 fz_try(ctx) | |
| 1415 { | |
| 1416 pdf_obj *subtype = pdf_dict_get(ctx, annot->obj, PDF_NAME(Subtype)); | |
| 1417 pdf_obj *popup = pdf_dict_get(ctx, annot->obj, PDF_NAME(Popup)); | |
| 1418 if (popup) | |
| 1419 { | |
| 1420 pdf_dict_put_bool(ctx, popup, PDF_NAME(Open), is_open); | |
| 1421 pdf_dirty_annot(ctx, annot); | |
| 1422 } | |
| 1423 else if (subtype == PDF_NAME(Text)) | |
| 1424 { | |
| 1425 pdf_dict_put_bool(ctx, annot->obj, PDF_NAME(Open), is_open); | |
| 1426 pdf_dirty_annot(ctx, annot); | |
| 1427 } | |
| 1428 end_annot_op(ctx, annot); | |
| 1429 } | |
| 1430 fz_catch(ctx) | |
| 1431 { | |
| 1432 abandon_annot_op(ctx, annot); | |
| 1433 fz_rethrow(ctx); | |
| 1434 } | |
| 1435 } | |
| 1436 | |
| 1437 static pdf_obj *icon_name_subtypes[] = { | |
| 1438 PDF_NAME(FileAttachment), | |
| 1439 PDF_NAME(Sound), | |
| 1440 PDF_NAME(Stamp), | |
| 1441 PDF_NAME(Text), | |
| 1442 NULL, | |
| 1443 }; | |
| 1444 | |
| 1445 int | |
| 1446 pdf_annot_has_icon_name(fz_context *ctx, pdf_annot *annot) | |
| 1447 { | |
| 1448 return is_allowed_subtype_wrap(ctx, annot, PDF_NAME(Name), icon_name_subtypes); | |
| 1449 } | |
| 1450 | |
| 1451 const char * | |
| 1452 pdf_annot_icon_name(fz_context *ctx, pdf_annot *annot) | |
| 1453 { | |
| 1454 const char *ret; | |
| 1455 pdf_obj *name; | |
| 1456 | |
| 1457 pdf_annot_push_local_xref(ctx, annot); | |
| 1458 | |
| 1459 fz_try(ctx) | |
| 1460 { | |
| 1461 check_allowed_subtypes(ctx, annot, PDF_NAME(Name), icon_name_subtypes); | |
| 1462 name = pdf_dict_get(ctx, annot->obj, PDF_NAME(Name)); | |
| 1463 if (!name) | |
| 1464 { | |
| 1465 pdf_obj *subtype = pdf_dict_get(ctx, annot->obj, PDF_NAME(Subtype)); | |
| 1466 if (pdf_name_eq(ctx, subtype, PDF_NAME(Text))) | |
| 1467 { | |
| 1468 ret = "Note"; | |
| 1469 break; | |
| 1470 } | |
| 1471 if (pdf_name_eq(ctx, subtype, PDF_NAME(Stamp))) | |
| 1472 { | |
| 1473 ret = ""; // Should be "Draft" according to spec | |
| 1474 break; | |
| 1475 } | |
| 1476 if (pdf_name_eq(ctx, subtype, PDF_NAME(FileAttachment))) | |
| 1477 { | |
| 1478 ret = "PushPin"; | |
| 1479 break; | |
| 1480 } | |
| 1481 if (pdf_name_eq(ctx, subtype, PDF_NAME(Sound))) | |
| 1482 { | |
| 1483 ret = "Speaker"; | |
| 1484 break; | |
| 1485 } | |
| 1486 } | |
| 1487 ret = pdf_to_name(ctx, name); | |
| 1488 } | |
| 1489 fz_always(ctx) | |
| 1490 pdf_annot_pop_local_xref(ctx, annot); | |
| 1491 fz_catch(ctx) | |
| 1492 fz_rethrow(ctx); | |
| 1493 | |
| 1494 return ret; | |
| 1495 } | |
| 1496 | |
| 1497 void | |
| 1498 pdf_set_annot_icon_name(fz_context *ctx, pdf_annot *annot, const char *name) | |
| 1499 { | |
| 1500 begin_annot_op(ctx, annot, "Set icon name"); | |
| 1501 | |
| 1502 fz_try(ctx) | |
| 1503 { | |
| 1504 check_allowed_subtypes(ctx, annot, PDF_NAME(Name), icon_name_subtypes); | |
| 1505 if (name) | |
| 1506 pdf_dict_put_name(ctx, annot->obj, PDF_NAME(Name), name); | |
| 1507 else | |
| 1508 pdf_dict_del(ctx, annot->obj, PDF_NAME(Name)); | |
| 1509 end_annot_op(ctx, annot); | |
| 1510 } | |
| 1511 fz_catch(ctx) | |
| 1512 { | |
| 1513 abandon_annot_op(ctx, annot); | |
| 1514 fz_rethrow(ctx); | |
| 1515 } | |
| 1516 | |
| 1517 pdf_dirty_annot(ctx, annot); | |
| 1518 } | |
| 1519 | |
| 1520 int | |
| 1521 pdf_annot_is_standard_stamp(fz_context *ctx, pdf_annot *annot) | |
| 1522 { | |
| 1523 pdf_obj *name = pdf_dict_get(ctx, annot->obj, PDF_NAME(Name)); | |
| 1524 if (pdf_name_eq(ctx, name, PDF_NAME(Approved))) return 1; | |
| 1525 else if (pdf_name_eq(ctx, name, PDF_NAME(AsIs))) return 1; | |
| 1526 else if (pdf_name_eq(ctx, name, PDF_NAME(Confidential))) return 1; | |
| 1527 else if (pdf_name_eq(ctx, name, PDF_NAME(Departmental))) return 1; | |
| 1528 else if (pdf_name_eq(ctx, name, PDF_NAME(Draft))) return 1; | |
| 1529 else if (pdf_name_eq(ctx, name, PDF_NAME(Experimental))) return 1; | |
| 1530 else if (pdf_name_eq(ctx, name, PDF_NAME(Expired))) return 1; | |
| 1531 else if (pdf_name_eq(ctx, name, PDF_NAME(Final))) return 1; | |
| 1532 else if (pdf_name_eq(ctx, name, PDF_NAME(ForComment))) return 1; | |
| 1533 else if (pdf_name_eq(ctx, name, PDF_NAME(ForPublicRelease))) return 1; | |
| 1534 else if (pdf_name_eq(ctx, name, PDF_NAME(NotApproved))) return 1; | |
| 1535 else if (pdf_name_eq(ctx, name, PDF_NAME(NotForPublicRelease))) return 1; | |
| 1536 else if (pdf_name_eq(ctx, name, PDF_NAME(Sold))) return 1; | |
| 1537 else if (pdf_name_eq(ctx, name, PDF_NAME(TopSecret))) return 1; | |
| 1538 else if (pdf_annot_stamp_image_obj(ctx, annot) != NULL) return 1; | |
| 1539 else return 0; | |
| 1540 } | |
| 1541 | |
| 1542 enum pdf_line_ending pdf_line_ending_from_name(fz_context *ctx, pdf_obj *end) | |
| 1543 { | |
| 1544 if (pdf_name_eq(ctx, end, PDF_NAME(None))) return PDF_ANNOT_LE_NONE; | |
| 1545 else if (pdf_name_eq(ctx, end, PDF_NAME(Square))) return PDF_ANNOT_LE_SQUARE; | |
| 1546 else if (pdf_name_eq(ctx, end, PDF_NAME(Circle))) return PDF_ANNOT_LE_CIRCLE; | |
| 1547 else if (pdf_name_eq(ctx, end, PDF_NAME(Diamond))) return PDF_ANNOT_LE_DIAMOND; | |
| 1548 else if (pdf_name_eq(ctx, end, PDF_NAME(OpenArrow))) return PDF_ANNOT_LE_OPEN_ARROW; | |
| 1549 else if (pdf_name_eq(ctx, end, PDF_NAME(ClosedArrow))) return PDF_ANNOT_LE_CLOSED_ARROW; | |
| 1550 else if (pdf_name_eq(ctx, end, PDF_NAME(Butt))) return PDF_ANNOT_LE_BUTT; | |
| 1551 else if (pdf_name_eq(ctx, end, PDF_NAME(ROpenArrow))) return PDF_ANNOT_LE_R_OPEN_ARROW; | |
| 1552 else if (pdf_name_eq(ctx, end, PDF_NAME(RClosedArrow))) return PDF_ANNOT_LE_R_CLOSED_ARROW; | |
| 1553 else if (pdf_name_eq(ctx, end, PDF_NAME(Slash))) return PDF_ANNOT_LE_SLASH; | |
| 1554 else return PDF_ANNOT_LE_NONE; | |
| 1555 } | |
| 1556 | |
| 1557 enum pdf_line_ending pdf_line_ending_from_string(fz_context *ctx, const char *end) | |
| 1558 { | |
| 1559 if (!strcmp(end, "None")) return PDF_ANNOT_LE_NONE; | |
| 1560 else if (!strcmp(end, "Square")) return PDF_ANNOT_LE_SQUARE; | |
| 1561 else if (!strcmp(end, "Circle")) return PDF_ANNOT_LE_CIRCLE; | |
| 1562 else if (!strcmp(end, "Diamond")) return PDF_ANNOT_LE_DIAMOND; | |
| 1563 else if (!strcmp(end, "OpenArrow")) return PDF_ANNOT_LE_OPEN_ARROW; | |
| 1564 else if (!strcmp(end, "ClosedArrow")) return PDF_ANNOT_LE_CLOSED_ARROW; | |
| 1565 else if (!strcmp(end, "Butt")) return PDF_ANNOT_LE_BUTT; | |
| 1566 else if (!strcmp(end, "ROpenArrow")) return PDF_ANNOT_LE_R_OPEN_ARROW; | |
| 1567 else if (!strcmp(end, "RClosedArrow")) return PDF_ANNOT_LE_R_CLOSED_ARROW; | |
| 1568 else if (!strcmp(end, "Slash")) return PDF_ANNOT_LE_SLASH; | |
| 1569 else return PDF_ANNOT_LE_NONE; | |
| 1570 } | |
| 1571 | |
| 1572 pdf_obj *pdf_name_from_line_ending(fz_context *ctx, enum pdf_line_ending end) | |
| 1573 { | |
| 1574 switch (end) | |
| 1575 { | |
| 1576 default: | |
| 1577 case PDF_ANNOT_LE_NONE: return PDF_NAME(None); | |
| 1578 case PDF_ANNOT_LE_SQUARE: return PDF_NAME(Square); | |
| 1579 case PDF_ANNOT_LE_CIRCLE: return PDF_NAME(Circle); | |
| 1580 case PDF_ANNOT_LE_DIAMOND: return PDF_NAME(Diamond); | |
| 1581 case PDF_ANNOT_LE_OPEN_ARROW: return PDF_NAME(OpenArrow); | |
| 1582 case PDF_ANNOT_LE_CLOSED_ARROW: return PDF_NAME(ClosedArrow); | |
| 1583 case PDF_ANNOT_LE_BUTT: return PDF_NAME(Butt); | |
| 1584 case PDF_ANNOT_LE_R_OPEN_ARROW: return PDF_NAME(ROpenArrow); | |
| 1585 case PDF_ANNOT_LE_R_CLOSED_ARROW: return PDF_NAME(RClosedArrow); | |
| 1586 case PDF_ANNOT_LE_SLASH: return PDF_NAME(Slash); | |
| 1587 } | |
| 1588 } | |
| 1589 | |
| 1590 const char *pdf_string_from_line_ending(fz_context *ctx, enum pdf_line_ending end) | |
| 1591 { | |
| 1592 switch (end) | |
| 1593 { | |
| 1594 default: | |
| 1595 case PDF_ANNOT_LE_NONE: return "None"; | |
| 1596 case PDF_ANNOT_LE_SQUARE: return "Square"; | |
| 1597 case PDF_ANNOT_LE_CIRCLE: return "Circle"; | |
| 1598 case PDF_ANNOT_LE_DIAMOND: return "Diamond"; | |
| 1599 case PDF_ANNOT_LE_OPEN_ARROW: return "OpenArrow"; | |
| 1600 case PDF_ANNOT_LE_CLOSED_ARROW: return "ClosedArrow"; | |
| 1601 case PDF_ANNOT_LE_BUTT: return "Butt"; | |
| 1602 case PDF_ANNOT_LE_R_OPEN_ARROW: return "ROpenArrow"; | |
| 1603 case PDF_ANNOT_LE_R_CLOSED_ARROW: return "RClosedArrow"; | |
| 1604 case PDF_ANNOT_LE_SLASH: return "Slash"; | |
| 1605 } | |
| 1606 } | |
| 1607 | |
| 1608 static pdf_obj *line_ending_subtypes[] = { | |
| 1609 PDF_NAME(FreeText), | |
| 1610 PDF_NAME(Line), | |
| 1611 PDF_NAME(PolyLine), | |
| 1612 PDF_NAME(Polygon), | |
| 1613 NULL, | |
| 1614 }; | |
| 1615 | |
| 1616 int | |
| 1617 pdf_annot_has_line_ending_styles(fz_context *ctx, pdf_annot *annot) | |
| 1618 { | |
| 1619 return is_allowed_subtype_wrap(ctx, annot, PDF_NAME(LE), line_ending_subtypes); | |
| 1620 } | |
| 1621 | |
| 1622 void | |
| 1623 pdf_annot_line_ending_styles(fz_context *ctx, pdf_annot *annot, | |
| 1624 enum pdf_line_ending *start_style, | |
| 1625 enum pdf_line_ending *end_style) | |
| 1626 { | |
| 1627 pdf_obj *style; | |
| 1628 | |
| 1629 pdf_annot_push_local_xref(ctx, annot); | |
| 1630 | |
| 1631 fz_try(ctx) | |
| 1632 { | |
| 1633 check_allowed_subtypes(ctx, annot, PDF_NAME(LE), line_ending_subtypes); | |
| 1634 | |
| 1635 style = pdf_dict_get(ctx, annot->obj, PDF_NAME(LE)); | |
| 1636 *start_style = pdf_line_ending_from_name(ctx, pdf_array_get(ctx, style, 0)); | |
| 1637 *end_style = pdf_line_ending_from_name(ctx, pdf_array_get(ctx, style, 1)); | |
| 1638 } | |
| 1639 fz_always(ctx) | |
| 1640 pdf_annot_pop_local_xref(ctx, annot); | |
| 1641 fz_catch(ctx) | |
| 1642 fz_rethrow(ctx); | |
| 1643 } | |
| 1644 | |
| 1645 enum pdf_line_ending | |
| 1646 pdf_annot_line_start_style(fz_context *ctx, pdf_annot *annot) | |
| 1647 { | |
| 1648 pdf_obj *le = pdf_dict_get(ctx, annot->obj, PDF_NAME(LE)); | |
| 1649 return pdf_line_ending_from_name(ctx, pdf_array_get(ctx, le, 0)); | |
| 1650 } | |
| 1651 | |
| 1652 enum pdf_line_ending | |
| 1653 pdf_annot_line_end_style(fz_context *ctx, pdf_annot *annot) | |
| 1654 { | |
| 1655 pdf_obj *le = pdf_dict_get(ctx, annot->obj, PDF_NAME(LE)); | |
| 1656 return pdf_line_ending_from_name(ctx, pdf_array_get(ctx, le, 1)); | |
| 1657 } | |
| 1658 | |
| 1659 void | |
| 1660 pdf_set_annot_line_ending_styles(fz_context *ctx, pdf_annot *annot, | |
| 1661 enum pdf_line_ending start_style, | |
| 1662 enum pdf_line_ending end_style) | |
| 1663 { | |
| 1664 pdf_obj *style; | |
| 1665 | |
| 1666 begin_annot_op(ctx, annot, "Set line endings"); | |
| 1667 | |
| 1668 fz_try(ctx) | |
| 1669 { | |
| 1670 check_allowed_subtypes(ctx, annot, PDF_NAME(LE), line_ending_subtypes); | |
| 1671 style = pdf_dict_put_array(ctx, annot->obj, PDF_NAME(LE), 2); | |
| 1672 pdf_array_put_drop(ctx, style, 0, pdf_name_from_line_ending(ctx, start_style)); | |
| 1673 pdf_array_put_drop(ctx, style, 1, pdf_name_from_line_ending(ctx, end_style)); | |
| 1674 end_annot_op(ctx, annot); | |
| 1675 } | |
| 1676 fz_catch(ctx) | |
| 1677 { | |
| 1678 abandon_annot_op(ctx, annot); | |
| 1679 fz_rethrow(ctx); | |
| 1680 } | |
| 1681 | |
| 1682 pdf_dirty_annot(ctx, annot); | |
| 1683 } | |
| 1684 | |
| 1685 void | |
| 1686 pdf_set_annot_line_start_style(fz_context *ctx, pdf_annot *annot, enum pdf_line_ending s) | |
| 1687 { | |
| 1688 enum pdf_line_ending e = pdf_annot_line_end_style(ctx, annot); | |
| 1689 pdf_set_annot_line_ending_styles(ctx, annot, s, e); | |
| 1690 } | |
| 1691 | |
| 1692 void | |
| 1693 pdf_set_annot_line_end_style(fz_context *ctx, pdf_annot *annot, enum pdf_line_ending e) | |
| 1694 { | |
| 1695 enum pdf_line_ending s = pdf_annot_line_start_style(ctx, annot); | |
| 1696 pdf_set_annot_line_ending_styles(ctx, annot, s, e); | |
| 1697 } | |
| 1698 | |
| 1699 static pdf_obj *border_style_subtypes[] = { | |
| 1700 PDF_NAME(Circle), | |
| 1701 PDF_NAME(FreeText), | |
| 1702 PDF_NAME(Ink), | |
| 1703 PDF_NAME(Line), | |
| 1704 PDF_NAME(Polygon), | |
| 1705 PDF_NAME(PolyLine), | |
| 1706 PDF_NAME(Square), | |
| 1707 PDF_NAME(Widget), | |
| 1708 NULL, | |
| 1709 }; | |
| 1710 | |
| 1711 static pdf_obj *border_effect_subtypes[] = { | |
| 1712 PDF_NAME(Circle), | |
| 1713 PDF_NAME(FreeText), | |
| 1714 PDF_NAME(Polygon), | |
| 1715 PDF_NAME(Square), | |
| 1716 NULL, | |
| 1717 }; | |
| 1718 | |
| 1719 int | |
| 1720 pdf_annot_has_border(fz_context *ctx, pdf_annot *annot) | |
| 1721 { | |
| 1722 return is_allowed_subtype_wrap(ctx, annot, PDF_NAME(BS), border_style_subtypes); | |
| 1723 } | |
| 1724 | |
| 1725 int | |
| 1726 pdf_annot_has_border_effect(fz_context *ctx, pdf_annot *annot) | |
| 1727 { | |
| 1728 return is_allowed_subtype_wrap(ctx, annot, PDF_NAME(BE), border_effect_subtypes); | |
| 1729 } | |
| 1730 | |
| 1731 enum pdf_border_style | |
| 1732 pdf_annot_border_style(fz_context *ctx, pdf_annot *annot) | |
| 1733 { | |
| 1734 pdf_obj *bs, *s; | |
| 1735 enum pdf_border_style style; | |
| 1736 | |
| 1737 pdf_annot_push_local_xref(ctx, annot); | |
| 1738 | |
| 1739 fz_try(ctx) | |
| 1740 { | |
| 1741 check_allowed_subtypes(ctx, annot, PDF_NAME(BS), border_style_subtypes); | |
| 1742 bs = pdf_dict_get(ctx, annot->obj, PDF_NAME(BS)); | |
| 1743 s = pdf_dict_get(ctx, bs, PDF_NAME(S)); | |
| 1744 | |
| 1745 if (s == PDF_NAME(D)) | |
| 1746 style = PDF_BORDER_STYLE_DASHED; | |
| 1747 else if (s == PDF_NAME(B)) | |
| 1748 style = PDF_BORDER_STYLE_BEVELED; | |
| 1749 else if (s == PDF_NAME(I)) | |
| 1750 style = PDF_BORDER_STYLE_INSET; | |
| 1751 else if (s == PDF_NAME(U)) | |
| 1752 style = PDF_BORDER_STYLE_UNDERLINE; | |
| 1753 else | |
| 1754 style = PDF_BORDER_STYLE_SOLID; | |
| 1755 } | |
| 1756 fz_always(ctx) | |
| 1757 pdf_annot_pop_local_xref(ctx, annot); | |
| 1758 fz_catch(ctx) | |
| 1759 fz_rethrow(ctx); | |
| 1760 | |
| 1761 return style; | |
| 1762 } | |
| 1763 | |
| 1764 float | |
| 1765 pdf_annot_border_width(fz_context *ctx, pdf_annot *annot) | |
| 1766 { | |
| 1767 pdf_obj *bs, *bs_w, *border; | |
| 1768 float ret = 1; | |
| 1769 | |
| 1770 pdf_annot_push_local_xref(ctx, annot); | |
| 1771 | |
| 1772 fz_try(ctx) | |
| 1773 { | |
| 1774 check_allowed_subtypes(ctx, annot, PDF_NAME(BS), border_style_subtypes); | |
| 1775 | |
| 1776 bs = pdf_dict_get(ctx, annot->obj, PDF_NAME(BS)); | |
| 1777 bs_w = pdf_dict_get(ctx, bs, PDF_NAME(W)); | |
| 1778 if (pdf_is_number(ctx, bs_w)) | |
| 1779 { | |
| 1780 ret = pdf_to_real(ctx, bs_w); | |
| 1781 break; | |
| 1782 } | |
| 1783 border = pdf_dict_get(ctx, annot->obj, PDF_NAME(Border)); | |
| 1784 bs_w = pdf_array_get(ctx, border, 2); | |
| 1785 if (pdf_is_number(ctx, bs_w)) | |
| 1786 ret = pdf_to_real(ctx, bs_w); | |
| 1787 } | |
| 1788 fz_always(ctx) | |
| 1789 pdf_annot_pop_local_xref(ctx, annot); | |
| 1790 fz_catch(ctx) | |
| 1791 fz_rethrow(ctx); | |
| 1792 | |
| 1793 return ret; | |
| 1794 } | |
| 1795 | |
| 1796 float | |
| 1797 pdf_annot_border(fz_context *ctx, pdf_annot *annot) | |
| 1798 { | |
| 1799 /* DEPRECATED */ | |
| 1800 return pdf_annot_border_width(ctx, annot); | |
| 1801 } | |
| 1802 | |
| 1803 int | |
| 1804 pdf_annot_border_dash_count(fz_context *ctx, pdf_annot *annot) | |
| 1805 { | |
| 1806 pdf_obj *bs, *d, *border; | |
| 1807 int count; | |
| 1808 | |
| 1809 pdf_annot_push_local_xref(ctx, annot); | |
| 1810 | |
| 1811 fz_try(ctx) | |
| 1812 { | |
| 1813 check_allowed_subtypes(ctx, annot, PDF_NAME(BS), border_style_subtypes); | |
| 1814 bs = pdf_dict_get(ctx, annot->obj, PDF_NAME(BS)); | |
| 1815 d = pdf_dict_get(ctx, bs, PDF_NAME(D)); | |
| 1816 /* Query legacy dash pattern as a fallback */ | |
| 1817 border = pdf_dict_get(ctx, annot->obj, PDF_NAME(Border)); | |
| 1818 if (!pdf_is_array(ctx, d) && pdf_is_array(ctx, border)) | |
| 1819 d = pdf_array_get(ctx, border, 3); | |
| 1820 count = pdf_array_len(ctx, d); | |
| 1821 } | |
| 1822 fz_always(ctx) | |
| 1823 pdf_annot_pop_local_xref(ctx, annot); | |
| 1824 fz_catch(ctx) | |
| 1825 fz_rethrow(ctx); | |
| 1826 | |
| 1827 return count; | |
| 1828 } | |
| 1829 | |
| 1830 float | |
| 1831 pdf_annot_border_dash_item(fz_context *ctx, pdf_annot *annot, int i) | |
| 1832 { | |
| 1833 pdf_obj *bs, *d, *border; | |
| 1834 float length; | |
| 1835 | |
| 1836 pdf_annot_push_local_xref(ctx, annot); | |
| 1837 | |
| 1838 fz_try(ctx) | |
| 1839 { | |
| 1840 check_allowed_subtypes(ctx, annot, PDF_NAME(BS), border_style_subtypes); | |
| 1841 bs = pdf_dict_get(ctx, annot->obj, PDF_NAME(BS)); | |
| 1842 d = pdf_dict_get(ctx, bs, PDF_NAME(D)); | |
| 1843 /* Query legacy dash pattern as a fallback */ | |
| 1844 border = pdf_dict_get(ctx, annot->obj, PDF_NAME(Border)); | |
| 1845 if (!pdf_is_array(ctx, d) && pdf_is_array(ctx, border)) | |
| 1846 d = pdf_array_get(ctx, border, 3); | |
| 1847 length = pdf_array_get_real(ctx, d, i); | |
| 1848 } | |
| 1849 fz_always(ctx) | |
| 1850 pdf_annot_pop_local_xref(ctx, annot); | |
| 1851 fz_catch(ctx) | |
| 1852 fz_rethrow(ctx); | |
| 1853 | |
| 1854 return length; | |
| 1855 } | |
| 1856 | |
| 1857 enum pdf_border_effect | |
| 1858 pdf_annot_border_effect(fz_context *ctx, pdf_annot *annot) | |
| 1859 { | |
| 1860 pdf_obj *be; | |
| 1861 enum pdf_border_effect effect; | |
| 1862 | |
| 1863 pdf_annot_push_local_xref(ctx, annot); | |
| 1864 | |
| 1865 fz_try(ctx) | |
| 1866 { | |
| 1867 check_allowed_subtypes(ctx, annot, PDF_NAME(BE), border_effect_subtypes); | |
| 1868 be = pdf_dict_get(ctx, annot->obj, PDF_NAME(BE)); | |
| 1869 if (pdf_dict_get(ctx, be, PDF_NAME(S)) == PDF_NAME(C)) | |
| 1870 effect = PDF_BORDER_EFFECT_CLOUDY; | |
| 1871 else | |
| 1872 effect = PDF_BORDER_EFFECT_NONE; | |
| 1873 } | |
| 1874 fz_always(ctx) | |
| 1875 pdf_annot_pop_local_xref(ctx, annot); | |
| 1876 fz_catch(ctx) | |
| 1877 fz_rethrow(ctx); | |
| 1878 | |
| 1879 return effect; | |
| 1880 } | |
| 1881 | |
| 1882 float | |
| 1883 pdf_annot_border_effect_intensity(fz_context *ctx, pdf_annot *annot) | |
| 1884 { | |
| 1885 pdf_obj *be; | |
| 1886 float intensity; | |
| 1887 | |
| 1888 pdf_annot_push_local_xref(ctx, annot); | |
| 1889 | |
| 1890 fz_try(ctx) | |
| 1891 { | |
| 1892 check_allowed_subtypes(ctx, annot, PDF_NAME(BE), border_effect_subtypes); | |
| 1893 be = pdf_dict_get(ctx, annot->obj, PDF_NAME(BE)); | |
| 1894 intensity = pdf_dict_get_real(ctx, be, PDF_NAME(I)); | |
| 1895 } | |
| 1896 fz_always(ctx) | |
| 1897 pdf_annot_pop_local_xref(ctx, annot); | |
| 1898 fz_catch(ctx) | |
| 1899 fz_rethrow(ctx); | |
| 1900 | |
| 1901 return intensity; | |
| 1902 } | |
| 1903 | |
| 1904 void | |
| 1905 pdf_set_annot_border_width(fz_context *ctx, pdf_annot *annot, float width) | |
| 1906 { | |
| 1907 pdf_obj *bs; | |
| 1908 pdf_obj *type; | |
| 1909 float old_width, adj; | |
| 1910 pdf_obj *rectobj; | |
| 1911 | |
| 1912 begin_annot_op(ctx, annot, "Set border width"); | |
| 1913 | |
| 1914 fz_try(ctx) | |
| 1915 { | |
| 1916 check_allowed_subtypes(ctx, annot, PDF_NAME(BS), border_style_subtypes); | |
| 1917 bs = pdf_dict_get(ctx, annot->obj, PDF_NAME(BS)); | |
| 1918 if (!pdf_is_dict(ctx, bs)) | |
| 1919 bs = pdf_dict_put_dict(ctx, annot->obj, PDF_NAME(BS), 1); | |
| 1920 pdf_dict_put(ctx, bs, PDF_NAME(Type), PDF_NAME(Border)); | |
| 1921 old_width = pdf_dict_get_real(ctx, bs, PDF_NAME(W)); | |
| 1922 pdf_dict_put_real(ctx, bs, PDF_NAME(W), width); | |
| 1923 rectobj = pdf_dict_get(ctx, annot->obj, PDF_NAME(Rect)); | |
| 1924 if (pdf_is_array(ctx, rectobj)) { | |
| 1925 fz_rect rect = pdf_to_rect(ctx, rectobj); | |
| 1926 adj = (width - old_width)/2; | |
| 1927 rect.x0 -= adj; | |
| 1928 rect.x1 += adj; | |
| 1929 rect.y0 -= adj; | |
| 1930 rect.y1 += adj; | |
| 1931 pdf_dict_put_rect(ctx, annot->obj, PDF_NAME(Rect), rect); | |
| 1932 /* For any of these types, we want to adjust the Rect and RD | |
| 1933 * together so that Rect+RD doesn't change, but the border stroke | |
| 1934 * stays centred on the same point. */ | |
| 1935 type = pdf_dict_get(ctx, annot->obj, PDF_NAME(Subtype)); | |
| 1936 if (pdf_name_eq(ctx, type, PDF_NAME(Square)) || | |
| 1937 pdf_name_eq(ctx, type, PDF_NAME(Circle))) | |
| 1938 { | |
| 1939 fz_rect rd = pdf_annot_rect_diff(ctx, annot); | |
| 1940 rd.x0 += adj; | |
| 1941 rd.x1 += adj; | |
| 1942 rd.y0 += adj; | |
| 1943 rd.y1 += adj; | |
| 1944 pdf_dict_put_rect(ctx, annot->obj, PDF_NAME(RD), rd); | |
| 1945 } | |
| 1946 } | |
| 1947 pdf_dict_del(ctx, annot->obj, PDF_NAME(Border)); /* deprecated */ | |
| 1948 end_annot_op(ctx, annot); | |
| 1949 } | |
| 1950 fz_catch(ctx) | |
| 1951 { | |
| 1952 abandon_annot_op(ctx, annot); | |
| 1953 fz_rethrow(ctx); | |
| 1954 } | |
| 1955 | |
| 1956 pdf_dirty_annot(ctx, annot); | |
| 1957 } | |
| 1958 | |
| 1959 void | |
| 1960 pdf_set_annot_border(fz_context *ctx, pdf_annot *annot, float w) | |
| 1961 { | |
| 1962 /* DEPRECATED */ | |
| 1963 pdf_set_annot_border_width(ctx, annot, w); | |
| 1964 } | |
| 1965 | |
| 1966 void | |
| 1967 pdf_set_annot_border_style(fz_context *ctx, pdf_annot *annot, enum pdf_border_style style) | |
| 1968 { | |
| 1969 pdf_obj *bs, *s; | |
| 1970 | |
| 1971 begin_annot_op(ctx, annot, "Set border style"); | |
| 1972 | |
| 1973 fz_try(ctx) | |
| 1974 { | |
| 1975 check_allowed_subtypes(ctx, annot, PDF_NAME(BS), border_style_subtypes); | |
| 1976 bs = pdf_dict_get(ctx, annot->obj, PDF_NAME(BS)); | |
| 1977 if (!pdf_is_dict(ctx, bs)) | |
| 1978 bs = pdf_dict_put_dict(ctx, annot->obj, PDF_NAME(BS), 1); | |
| 1979 pdf_dict_put(ctx, bs, PDF_NAME(Type), PDF_NAME(Border)); | |
| 1980 switch (style) | |
| 1981 { | |
| 1982 default: | |
| 1983 case PDF_BORDER_STYLE_SOLID: s = PDF_NAME(S); break; | |
| 1984 case PDF_BORDER_STYLE_DASHED: s = PDF_NAME(D); break; | |
| 1985 case PDF_BORDER_STYLE_BEVELED: s = PDF_NAME(B); break; | |
| 1986 case PDF_BORDER_STYLE_INSET: s = PDF_NAME(I); break; | |
| 1987 case PDF_BORDER_STYLE_UNDERLINE: s = PDF_NAME(U); break; | |
| 1988 } | |
| 1989 pdf_dict_put(ctx, bs, PDF_NAME(S), s); | |
| 1990 end_annot_op(ctx, annot); | |
| 1991 } | |
| 1992 fz_catch(ctx) | |
| 1993 { | |
| 1994 abandon_annot_op(ctx, annot); | |
| 1995 fz_rethrow(ctx); | |
| 1996 } | |
| 1997 | |
| 1998 pdf_dirty_annot(ctx, annot); | |
| 1999 } | |
| 2000 | |
| 2001 void | |
| 2002 pdf_clear_annot_border_dash(fz_context *ctx, pdf_annot *annot) | |
| 2003 { | |
| 2004 pdf_obj *bs, *border; | |
| 2005 | |
| 2006 begin_annot_op(ctx, annot, "Clear border dash pattern"); | |
| 2007 | |
| 2008 fz_try(ctx) | |
| 2009 { | |
| 2010 check_allowed_subtypes(ctx, annot, PDF_NAME(BS), border_style_subtypes); | |
| 2011 bs = pdf_dict_get(ctx, annot->obj, PDF_NAME(BS)); | |
| 2012 if (!pdf_is_dict(ctx, bs)) | |
| 2013 bs = pdf_dict_put_dict(ctx, annot->obj, PDF_NAME(BS), 1); | |
| 2014 pdf_dict_del(ctx, bs, PDF_NAME(D)); | |
| 2015 /* Remove legacy dash pattern */ | |
| 2016 border = pdf_dict_get(ctx, annot->obj, PDF_NAME(Border)); | |
| 2017 if (pdf_is_array(ctx, border)) | |
| 2018 pdf_array_delete(ctx, border, 3); | |
| 2019 end_annot_op(ctx, annot); | |
| 2020 } | |
| 2021 fz_catch(ctx) | |
| 2022 { | |
| 2023 abandon_annot_op(ctx, annot); | |
| 2024 fz_rethrow(ctx); | |
| 2025 } | |
| 2026 | |
| 2027 pdf_dirty_annot(ctx, annot); | |
| 2028 } | |
| 2029 | |
| 2030 void | |
| 2031 pdf_add_annot_border_dash_item(fz_context *ctx, pdf_annot *annot, float length) | |
| 2032 { | |
| 2033 pdf_obj *bs, *d, *border; | |
| 2034 | |
| 2035 begin_annot_op(ctx, annot, "Add border dash pattern item"); | |
| 2036 | |
| 2037 fz_try(ctx) | |
| 2038 { | |
| 2039 check_allowed_subtypes(ctx, annot, PDF_NAME(BS), border_style_subtypes); | |
| 2040 bs = pdf_dict_get(ctx, annot->obj, PDF_NAME(BS)); | |
| 2041 if (!pdf_is_dict(ctx, bs)) | |
| 2042 bs = pdf_dict_put_dict(ctx, annot->obj, PDF_NAME(BS), 1); | |
| 2043 d = pdf_dict_get(ctx, bs, PDF_NAME(D)); | |
| 2044 if (!pdf_is_array(ctx, d)) | |
| 2045 d = pdf_dict_put_array(ctx, bs, PDF_NAME(D), 1); | |
| 2046 pdf_array_push_real(ctx, d, length); | |
| 2047 /* Remove legacy dash pattern */ | |
| 2048 border = pdf_dict_get(ctx, annot->obj, PDF_NAME(Border)); | |
| 2049 if (pdf_is_array(ctx, border)) | |
| 2050 pdf_array_delete(ctx, border, 3); | |
| 2051 end_annot_op(ctx, annot); | |
| 2052 } | |
| 2053 fz_catch(ctx) | |
| 2054 { | |
| 2055 abandon_annot_op(ctx, annot); | |
| 2056 fz_rethrow(ctx); | |
| 2057 } | |
| 2058 | |
| 2059 pdf_dirty_annot(ctx, annot); | |
| 2060 } | |
| 2061 | |
| 2062 void | |
| 2063 pdf_set_annot_border_effect(fz_context *ctx, pdf_annot *annot, enum pdf_border_effect effect) | |
| 2064 { | |
| 2065 pdf_obj *be, *s; | |
| 2066 | |
| 2067 begin_annot_op(ctx, annot, "Set border effect"); | |
| 2068 | |
| 2069 fz_try(ctx) | |
| 2070 { | |
| 2071 check_allowed_subtypes(ctx, annot, PDF_NAME(BE), border_effect_subtypes); | |
| 2072 be = pdf_dict_get(ctx, annot->obj, PDF_NAME(BE)); | |
| 2073 if (!pdf_is_dict(ctx, be)) | |
| 2074 be = pdf_dict_put_dict(ctx, annot->obj, PDF_NAME(BE), 1); | |
| 2075 switch (effect) | |
| 2076 { | |
| 2077 default: | |
| 2078 case PDF_BORDER_EFFECT_NONE: s = PDF_NAME(S); break; | |
| 2079 case PDF_BORDER_EFFECT_CLOUDY: s = PDF_NAME(C); break; | |
| 2080 } | |
| 2081 pdf_dict_put(ctx, be, PDF_NAME(S), s); | |
| 2082 end_annot_op(ctx, annot); | |
| 2083 } | |
| 2084 fz_catch(ctx) | |
| 2085 { | |
| 2086 abandon_annot_op(ctx, annot); | |
| 2087 fz_rethrow(ctx); | |
| 2088 } | |
| 2089 | |
| 2090 pdf_dirty_annot(ctx, annot); | |
| 2091 } | |
| 2092 | |
| 2093 void | |
| 2094 pdf_set_annot_border_effect_intensity(fz_context *ctx, pdf_annot *annot, float intensity) | |
| 2095 { | |
| 2096 pdf_obj *be; | |
| 2097 | |
| 2098 begin_annot_op(ctx, annot, "Set border effect intensity"); | |
| 2099 | |
| 2100 fz_try(ctx) | |
| 2101 { | |
| 2102 check_allowed_subtypes(ctx, annot, PDF_NAME(BE), border_effect_subtypes); | |
| 2103 be = pdf_dict_get(ctx, annot->obj, PDF_NAME(BE)); | |
| 2104 if (!pdf_is_dict(ctx, be)) | |
| 2105 be = pdf_dict_put_dict(ctx, annot->obj, PDF_NAME(BE), 1); | |
| 2106 pdf_dict_put_real(ctx, be, PDF_NAME(I), intensity); | |
| 2107 end_annot_op(ctx, annot); | |
| 2108 } | |
| 2109 fz_catch(ctx) | |
| 2110 { | |
| 2111 abandon_annot_op(ctx, annot); | |
| 2112 fz_rethrow(ctx); | |
| 2113 } | |
| 2114 | |
| 2115 pdf_dirty_annot(ctx, annot); | |
| 2116 } | |
| 2117 | |
| 2118 fz_text_language | |
| 2119 pdf_document_language(fz_context *ctx, pdf_document *doc) | |
| 2120 { | |
| 2121 pdf_obj *trailer = pdf_trailer(ctx, doc); | |
| 2122 pdf_obj *root = pdf_dict_get(ctx, trailer, PDF_NAME(Root)); | |
| 2123 pdf_obj *lang = pdf_dict_get(ctx, root, PDF_NAME(Lang)); | |
| 2124 return fz_text_language_from_string(pdf_to_text_string(ctx, lang)); | |
| 2125 } | |
| 2126 | |
| 2127 void pdf_set_document_language(fz_context *ctx, pdf_document *doc, fz_text_language lang) | |
| 2128 { | |
| 2129 pdf_obj *trailer = pdf_trailer(ctx, doc); | |
| 2130 pdf_obj *root = pdf_dict_get(ctx, trailer, PDF_NAME(Root)); | |
| 2131 char buf[8]; | |
| 2132 if (lang == FZ_LANG_UNSET) | |
| 2133 pdf_dict_del(ctx, root, PDF_NAME(Lang)); | |
| 2134 else | |
| 2135 pdf_dict_put_text_string(ctx, root, PDF_NAME(Lang), fz_string_from_text_language(buf, lang)); | |
| 2136 } | |
| 2137 | |
| 2138 fz_text_language | |
| 2139 pdf_annot_language(fz_context *ctx, pdf_annot *annot) | |
| 2140 { | |
| 2141 fz_text_language ret; | |
| 2142 | |
| 2143 pdf_annot_push_local_xref(ctx, annot); | |
| 2144 | |
| 2145 fz_try(ctx) | |
| 2146 { | |
| 2147 pdf_obj *lang = pdf_dict_get_inheritable(ctx, annot->obj, PDF_NAME(Lang)); | |
| 2148 if (lang) | |
| 2149 ret = fz_text_language_from_string(pdf_to_str_buf(ctx, lang)); | |
| 2150 else | |
| 2151 ret = pdf_document_language(ctx, annot->page->doc); | |
| 2152 } | |
| 2153 fz_always(ctx) | |
| 2154 pdf_annot_pop_local_xref(ctx, annot); | |
| 2155 fz_catch(ctx) | |
| 2156 fz_rethrow(ctx); | |
| 2157 | |
| 2158 return ret; | |
| 2159 } | |
| 2160 | |
| 2161 void | |
| 2162 pdf_set_annot_language(fz_context *ctx, pdf_annot *annot, fz_text_language lang) | |
| 2163 { | |
| 2164 char buf[8]; | |
| 2165 | |
| 2166 begin_annot_op(ctx, annot, "Set language"); | |
| 2167 | |
| 2168 fz_try(ctx) | |
| 2169 { | |
| 2170 if (lang == FZ_LANG_UNSET) | |
| 2171 pdf_dict_del(ctx, annot->obj, PDF_NAME(Lang)); | |
| 2172 else | |
| 2173 pdf_dict_put_text_string(ctx, annot->obj, PDF_NAME(Lang), fz_string_from_text_language(buf, lang)); | |
| 2174 end_annot_op(ctx, annot); | |
| 2175 } | |
| 2176 fz_catch(ctx) | |
| 2177 { | |
| 2178 abandon_annot_op(ctx, annot); | |
| 2179 fz_rethrow(ctx); | |
| 2180 } | |
| 2181 | |
| 2182 pdf_dirty_annot(ctx, annot); | |
| 2183 } | |
| 2184 | |
| 2185 static pdf_obj *quadding_subtypes[] = { | |
| 2186 PDF_NAME(FreeText), | |
| 2187 PDF_NAME(Widget), | |
| 2188 NULL, | |
| 2189 }; | |
| 2190 | |
| 2191 int | |
| 2192 pdf_annot_has_quadding(fz_context *ctx, pdf_annot *annot) | |
| 2193 { | |
| 2194 return is_allowed_subtype_wrap(ctx, annot, PDF_NAME(Q), quadding_subtypes); | |
| 2195 } | |
| 2196 | |
| 2197 int | |
| 2198 pdf_annot_quadding(fz_context *ctx, pdf_annot *annot) | |
| 2199 { | |
| 2200 int q; | |
| 2201 | |
| 2202 pdf_annot_push_local_xref(ctx, annot); | |
| 2203 | |
| 2204 fz_try(ctx) | |
| 2205 { | |
| 2206 check_allowed_subtypes(ctx, annot, PDF_NAME(Q), quadding_subtypes); | |
| 2207 q = pdf_dict_get_int(ctx, annot->obj, PDF_NAME(Q)); | |
| 2208 q = (q < 0 || q > 2) ? 0 : q; | |
| 2209 } | |
| 2210 fz_always(ctx) | |
| 2211 pdf_annot_pop_local_xref(ctx, annot); | |
| 2212 fz_catch(ctx) | |
| 2213 fz_rethrow(ctx); | |
| 2214 | |
| 2215 return q; | |
| 2216 } | |
| 2217 | |
| 2218 void | |
| 2219 pdf_set_annot_quadding(fz_context *ctx, pdf_annot *annot, int q) | |
| 2220 { | |
| 2221 q = (q < 0 || q > 2) ? 0 : q; | |
| 2222 | |
| 2223 begin_annot_op(ctx, annot, "Set quadding"); | |
| 2224 | |
| 2225 fz_try(ctx) | |
| 2226 { | |
| 2227 check_allowed_subtypes(ctx, annot, PDF_NAME(Q), quadding_subtypes); | |
| 2228 pdf_dict_put_int(ctx, annot->obj, PDF_NAME(Q), q); | |
| 2229 end_annot_op(ctx, annot); | |
| 2230 } | |
| 2231 fz_catch(ctx) | |
| 2232 { | |
| 2233 abandon_annot_op(ctx, annot); | |
| 2234 fz_rethrow(ctx); | |
| 2235 } | |
| 2236 | |
| 2237 pdf_dirty_annot(ctx, annot); | |
| 2238 } | |
| 2239 | |
| 2240 float pdf_annot_opacity(fz_context *ctx, pdf_annot *annot) | |
| 2241 { | |
| 2242 float ret; | |
| 2243 | |
| 2244 pdf_annot_push_local_xref(ctx, annot); | |
| 2245 | |
| 2246 fz_try(ctx) | |
| 2247 ret = pdf_dict_get_real_default(ctx, annot->obj, PDF_NAME(CA), 1); | |
| 2248 fz_always(ctx) | |
| 2249 pdf_annot_pop_local_xref(ctx, annot); | |
| 2250 fz_catch(ctx) | |
| 2251 fz_rethrow(ctx); | |
| 2252 | |
| 2253 return ret; | |
| 2254 } | |
| 2255 | |
| 2256 void pdf_set_annot_opacity(fz_context *ctx, pdf_annot *annot, float opacity) | |
| 2257 { | |
| 2258 begin_annot_op(ctx, annot, "Set opacity"); | |
| 2259 | |
| 2260 fz_try(ctx) | |
| 2261 { | |
| 2262 if (opacity != 1) | |
| 2263 pdf_dict_put_real(ctx, annot->obj, PDF_NAME(CA), opacity); | |
| 2264 else | |
| 2265 pdf_dict_del(ctx, annot->obj, PDF_NAME(CA)); | |
| 2266 end_annot_op(ctx, annot); | |
| 2267 } | |
| 2268 fz_catch(ctx) | |
| 2269 { | |
| 2270 abandon_annot_op(ctx, annot); | |
| 2271 fz_rethrow(ctx); | |
| 2272 } | |
| 2273 | |
| 2274 pdf_dirty_annot(ctx, annot); | |
| 2275 } | |
| 2276 | |
| 2277 static void pdf_annot_color_imp(fz_context *ctx, pdf_obj *arr, int *n, float color[4]) | |
| 2278 { | |
| 2279 switch (pdf_array_len(ctx, arr)) | |
| 2280 { | |
| 2281 case 0: | |
| 2282 if (n) | |
| 2283 *n = 0; | |
| 2284 break; | |
| 2285 case 1: | |
| 2286 case 2: | |
| 2287 if (n) | |
| 2288 *n = 1; | |
| 2289 if (color) | |
| 2290 color[0] = pdf_array_get_real(ctx, arr, 0); | |
| 2291 break; | |
| 2292 case 3: | |
| 2293 if (n) | |
| 2294 *n = 3; | |
| 2295 if (color) | |
| 2296 { | |
| 2297 color[0] = pdf_array_get_real(ctx, arr, 0); | |
| 2298 color[1] = pdf_array_get_real(ctx, arr, 1); | |
| 2299 color[2] = pdf_array_get_real(ctx, arr, 2); | |
| 2300 } | |
| 2301 break; | |
| 2302 case 4: | |
| 2303 default: | |
| 2304 if (n) | |
| 2305 *n = 4; | |
| 2306 if (color) | |
| 2307 { | |
| 2308 color[0] = pdf_array_get_real(ctx, arr, 0); | |
| 2309 color[1] = pdf_array_get_real(ctx, arr, 1); | |
| 2310 color[2] = pdf_array_get_real(ctx, arr, 2); | |
| 2311 color[3] = pdf_array_get_real(ctx, arr, 3); | |
| 2312 } | |
| 2313 break; | |
| 2314 } | |
| 2315 } | |
| 2316 | |
| 2317 static int pdf_annot_color_rgb(fz_context *ctx, pdf_obj *arr, float rgb[3]) | |
| 2318 { | |
| 2319 float color[4]; | |
| 2320 int n; | |
| 2321 pdf_annot_color_imp(ctx, arr, &n, color); | |
| 2322 if (n == 0) | |
| 2323 { | |
| 2324 return 0; | |
| 2325 } | |
| 2326 else if (n == 1) | |
| 2327 { | |
| 2328 rgb[0] = rgb[1] = rgb[2] = color[0]; | |
| 2329 } | |
| 2330 else if (n == 3) | |
| 2331 { | |
| 2332 rgb[0] = color[0]; | |
| 2333 rgb[1] = color[1]; | |
| 2334 rgb[2] = color[2]; | |
| 2335 } | |
| 2336 else if (n == 4) | |
| 2337 { | |
| 2338 rgb[0] = 1 - fz_min(1, color[0] + color[3]); | |
| 2339 rgb[1] = 1 - fz_min(1, color[1] + color[3]); | |
| 2340 rgb[2] = 1 - fz_min(1, color[2] + color[3]); | |
| 2341 } | |
| 2342 return 1; | |
| 2343 } | |
| 2344 | |
| 2345 static void pdf_set_annot_color_imp(fz_context *ctx, pdf_annot *annot, pdf_obj *key, int n, const float *color, pdf_obj **allowed) | |
| 2346 { | |
| 2347 pdf_obj *arr; | |
| 2348 | |
| 2349 if (allowed) | |
| 2350 check_allowed_subtypes(ctx, annot, key, allowed); | |
| 2351 if (n != 0 && n != 1 && n != 3 && n != 4) | |
| 2352 fz_throw(ctx, FZ_ERROR_ARGUMENT, "color must be 0, 1, 3 or 4 components"); | |
| 2353 if (!color) | |
| 2354 fz_throw(ctx, FZ_ERROR_ARGUMENT, "no color given"); | |
| 2355 | |
| 2356 arr = pdf_dict_put_array(ctx, annot->obj, key, n); | |
| 2357 fz_try(ctx) | |
| 2358 { | |
| 2359 switch (n) | |
| 2360 { | |
| 2361 case 1: | |
| 2362 pdf_array_push_real(ctx, arr, color[0]); | |
| 2363 break; | |
| 2364 case 3: | |
| 2365 pdf_array_push_real(ctx, arr, color[0]); | |
| 2366 pdf_array_push_real(ctx, arr, color[1]); | |
| 2367 pdf_array_push_real(ctx, arr, color[2]); | |
| 2368 break; | |
| 2369 case 4: | |
| 2370 pdf_array_push_real(ctx, arr, color[0]); | |
| 2371 pdf_array_push_real(ctx, arr, color[1]); | |
| 2372 pdf_array_push_real(ctx, arr, color[2]); | |
| 2373 pdf_array_push_real(ctx, arr, color[3]); | |
| 2374 break; | |
| 2375 } | |
| 2376 } | |
| 2377 fz_catch(ctx) | |
| 2378 fz_rethrow(ctx); | |
| 2379 | |
| 2380 pdf_dirty_annot(ctx, annot); | |
| 2381 } | |
| 2382 | |
| 2383 static void | |
| 2384 do_pdf_annot_color(fz_context *ctx, pdf_annot *annot, int *n, float color[4], pdf_obj *name) | |
| 2385 { | |
| 2386 pdf_annot_push_local_xref(ctx, annot); | |
| 2387 | |
| 2388 fz_try(ctx) | |
| 2389 { | |
| 2390 pdf_obj *c = pdf_dict_get(ctx, annot->obj, name); | |
| 2391 pdf_annot_color_imp(ctx, c, n, color); | |
| 2392 } | |
| 2393 fz_always(ctx) | |
| 2394 pdf_annot_pop_local_xref(ctx, annot); | |
| 2395 fz_catch(ctx) | |
| 2396 fz_rethrow(ctx); | |
| 2397 } | |
| 2398 | |
| 2399 void | |
| 2400 pdf_annot_color(fz_context *ctx, pdf_annot *annot, int *n, float color[4]) | |
| 2401 { | |
| 2402 do_pdf_annot_color(ctx, annot, n, color, PDF_NAME(C)); | |
| 2403 } | |
| 2404 | |
| 2405 void | |
| 2406 pdf_annot_MK_BG(fz_context *ctx, pdf_annot *annot, int *n, float color[4]) | |
| 2407 { | |
| 2408 pdf_annot_push_local_xref(ctx, annot); | |
| 2409 | |
| 2410 fz_try(ctx) | |
| 2411 { | |
| 2412 pdf_obj *mk_bg = pdf_dict_get(ctx, pdf_dict_get(ctx, annot->obj, PDF_NAME(MK)), PDF_NAME(BG)); | |
| 2413 pdf_annot_color_imp(ctx, mk_bg, n, color); | |
| 2414 } | |
| 2415 fz_always(ctx) | |
| 2416 pdf_annot_pop_local_xref(ctx, annot); | |
| 2417 fz_catch(ctx) | |
| 2418 fz_rethrow(ctx); | |
| 2419 } | |
| 2420 | |
| 2421 int | |
| 2422 pdf_annot_MK_BG_rgb(fz_context *ctx, pdf_annot *annot, float rgb[3]) | |
| 2423 { | |
| 2424 int ret; | |
| 2425 | |
| 2426 pdf_annot_push_local_xref(ctx, annot); | |
| 2427 | |
| 2428 fz_try(ctx) | |
| 2429 { | |
| 2430 pdf_obj *mk_bg = pdf_dict_get(ctx, pdf_dict_get(ctx, annot->obj, PDF_NAME(MK)), PDF_NAME(BG)); | |
| 2431 ret = pdf_annot_color_rgb(ctx, mk_bg, rgb); | |
| 2432 } | |
| 2433 fz_always(ctx) | |
| 2434 pdf_annot_pop_local_xref(ctx, annot); | |
| 2435 fz_catch(ctx) | |
| 2436 fz_rethrow(ctx); | |
| 2437 | |
| 2438 return ret; | |
| 2439 } | |
| 2440 | |
| 2441 void | |
| 2442 pdf_annot_MK_BC(fz_context *ctx, pdf_annot *annot, int *n, float color[4]) | |
| 2443 { | |
| 2444 pdf_annot_push_local_xref(ctx, annot); | |
| 2445 | |
| 2446 fz_try(ctx) | |
| 2447 { | |
| 2448 pdf_obj *mk_bc = pdf_dict_get(ctx, pdf_dict_get(ctx, annot->obj, PDF_NAME(MK)), PDF_NAME(BC)); | |
| 2449 pdf_annot_color_imp(ctx, mk_bc, n, color); | |
| 2450 } | |
| 2451 fz_always(ctx) | |
| 2452 pdf_annot_pop_local_xref(ctx, annot); | |
| 2453 fz_catch(ctx) | |
| 2454 fz_rethrow(ctx); | |
| 2455 } | |
| 2456 | |
| 2457 int | |
| 2458 pdf_annot_MK_BC_rgb(fz_context *ctx, pdf_annot *annot, float rgb[3]) | |
| 2459 { | |
| 2460 int ret; | |
| 2461 | |
| 2462 pdf_annot_push_local_xref(ctx, annot); | |
| 2463 | |
| 2464 fz_try(ctx) | |
| 2465 { | |
| 2466 pdf_obj *mk_bc = pdf_dict_get(ctx, pdf_dict_get(ctx, annot->obj, PDF_NAME(MK)), PDF_NAME(BC)); | |
| 2467 ret = pdf_annot_color_rgb(ctx, mk_bc, rgb); | |
| 2468 } | |
| 2469 fz_always(ctx) | |
| 2470 pdf_annot_pop_local_xref(ctx, annot); | |
| 2471 fz_catch(ctx) | |
| 2472 fz_rethrow(ctx); | |
| 2473 | |
| 2474 return ret; | |
| 2475 } | |
| 2476 | |
| 2477 void | |
| 2478 pdf_set_annot_color(fz_context *ctx, pdf_annot *annot, int n, const float *color) | |
| 2479 { | |
| 2480 begin_annot_op(ctx, annot, "Set color"); | |
| 2481 | |
| 2482 fz_try(ctx) | |
| 2483 { | |
| 2484 pdf_set_annot_color_imp(ctx, annot, PDF_NAME(C), n, color, NULL); | |
| 2485 end_annot_op(ctx, annot); | |
| 2486 } | |
| 2487 fz_catch(ctx) | |
| 2488 { | |
| 2489 abandon_annot_op(ctx, annot); | |
| 2490 fz_rethrow(ctx); | |
| 2491 } | |
| 2492 } | |
| 2493 | |
| 2494 static pdf_obj *interior_color_subtypes[] = { | |
| 2495 PDF_NAME(Circle), | |
| 2496 PDF_NAME(Line), | |
| 2497 PDF_NAME(PolyLine), | |
| 2498 PDF_NAME(Polygon), | |
| 2499 PDF_NAME(Square), | |
| 2500 NULL, | |
| 2501 }; | |
| 2502 | |
| 2503 int | |
| 2504 pdf_annot_has_interior_color(fz_context *ctx, pdf_annot *annot) | |
| 2505 { | |
| 2506 return is_allowed_subtype_wrap(ctx, annot, PDF_NAME(IC), interior_color_subtypes); | |
| 2507 } | |
| 2508 | |
| 2509 void | |
| 2510 pdf_annot_interior_color(fz_context *ctx, pdf_annot *annot, int *n, float color[4]) | |
| 2511 { | |
| 2512 check_allowed_subtypes(ctx, annot, PDF_NAME(IC), interior_color_subtypes); | |
| 2513 do_pdf_annot_color(ctx, annot, n, color, PDF_NAME(IC)); | |
| 2514 } | |
| 2515 | |
| 2516 void | |
| 2517 pdf_set_annot_interior_color(fz_context *ctx, pdf_annot *annot, int n, const float *color) | |
| 2518 { | |
| 2519 begin_annot_op(ctx, annot, "Set interior color"); | |
| 2520 | |
| 2521 fz_try(ctx) | |
| 2522 { | |
| 2523 check_allowed_subtypes(ctx, annot, PDF_NAME(IC), interior_color_subtypes); | |
| 2524 pdf_set_annot_color_imp(ctx, annot, PDF_NAME(IC), n, color, interior_color_subtypes); | |
| 2525 end_annot_op(ctx, annot); | |
| 2526 } | |
| 2527 fz_catch(ctx) | |
| 2528 { | |
| 2529 abandon_annot_op(ctx, annot); | |
| 2530 fz_rethrow(ctx); | |
| 2531 } | |
| 2532 } | |
| 2533 | |
| 2534 static pdf_obj *line_subtypes[] = { | |
| 2535 PDF_NAME(Line), | |
| 2536 NULL, | |
| 2537 }; | |
| 2538 | |
| 2539 int | |
| 2540 pdf_annot_has_line(fz_context *ctx, pdf_annot *annot) | |
| 2541 { | |
| 2542 return is_allowed_subtype_wrap(ctx, annot, PDF_NAME(L), line_subtypes); | |
| 2543 } | |
| 2544 | |
| 2545 void | |
| 2546 pdf_annot_line(fz_context *ctx, pdf_annot *annot, fz_point *a, fz_point *b) | |
| 2547 { | |
| 2548 fz_matrix page_ctm; | |
| 2549 pdf_obj *line; | |
| 2550 | |
| 2551 pdf_annot_push_local_xref(ctx, annot); | |
| 2552 | |
| 2553 fz_try(ctx) | |
| 2554 { | |
| 2555 check_allowed_subtypes(ctx, annot, PDF_NAME(L), line_subtypes); | |
| 2556 | |
| 2557 pdf_page_transform(ctx, annot->page, NULL, &page_ctm); | |
| 2558 | |
| 2559 line = pdf_dict_get(ctx, annot->obj, PDF_NAME(L)); | |
| 2560 a->x = pdf_array_get_real(ctx, line, 0); | |
| 2561 a->y = pdf_array_get_real(ctx, line, 1); | |
| 2562 b->x = pdf_array_get_real(ctx, line, 2); | |
| 2563 b->y = pdf_array_get_real(ctx, line, 3); | |
| 2564 *a = fz_transform_point(*a, page_ctm); | |
| 2565 *b = fz_transform_point(*b, page_ctm); | |
| 2566 } | |
| 2567 fz_always(ctx) | |
| 2568 pdf_annot_pop_local_xref(ctx, annot); | |
| 2569 fz_catch(ctx) | |
| 2570 fz_rethrow(ctx); | |
| 2571 } | |
| 2572 | |
| 2573 void | |
| 2574 pdf_set_annot_line(fz_context *ctx, pdf_annot *annot, fz_point a, fz_point b) | |
| 2575 { | |
| 2576 fz_matrix page_ctm, inv_page_ctm; | |
| 2577 pdf_obj *line; | |
| 2578 | |
| 2579 begin_annot_op(ctx, annot, "Set line"); | |
| 2580 | |
| 2581 fz_try(ctx) | |
| 2582 { | |
| 2583 check_allowed_subtypes(ctx, annot, PDF_NAME(L), line_subtypes); | |
| 2584 | |
| 2585 pdf_page_transform(ctx, annot->page, NULL, &page_ctm); | |
| 2586 inv_page_ctm = fz_invert_matrix(page_ctm); | |
| 2587 | |
| 2588 a = fz_transform_point(a, inv_page_ctm); | |
| 2589 b = fz_transform_point(b, inv_page_ctm); | |
| 2590 | |
| 2591 line = pdf_dict_put_array(ctx, annot->obj, PDF_NAME(L), 4); | |
| 2592 pdf_array_push_real(ctx, line, a.x); | |
| 2593 pdf_array_push_real(ctx, line, a.y); | |
| 2594 pdf_array_push_real(ctx, line, b.x); | |
| 2595 pdf_array_push_real(ctx, line, b.y); | |
| 2596 end_annot_op(ctx, annot); | |
| 2597 } | |
| 2598 fz_catch(ctx) | |
| 2599 { | |
| 2600 abandon_annot_op(ctx, annot); | |
| 2601 fz_rethrow(ctx); | |
| 2602 } | |
| 2603 | |
| 2604 pdf_dirty_annot(ctx, annot); | |
| 2605 } | |
| 2606 | |
| 2607 float | |
| 2608 pdf_annot_line_leader(fz_context *ctx, pdf_annot *annot) | |
| 2609 { | |
| 2610 float value; | |
| 2611 pdf_annot_push_local_xref(ctx, annot); | |
| 2612 fz_try(ctx) | |
| 2613 { | |
| 2614 check_allowed_subtypes(ctx, annot, PDF_NAME(LL), line_subtypes); | |
| 2615 value = pdf_dict_get_real(ctx, annot->obj, PDF_NAME(LL)); | |
| 2616 } | |
| 2617 fz_always(ctx) | |
| 2618 pdf_annot_pop_local_xref(ctx, annot); | |
| 2619 fz_catch(ctx) | |
| 2620 fz_rethrow(ctx); | |
| 2621 return value; | |
| 2622 } | |
| 2623 | |
| 2624 float | |
| 2625 pdf_annot_line_leader_extension(fz_context *ctx, pdf_annot *annot) | |
| 2626 { | |
| 2627 float value; | |
| 2628 pdf_annot_push_local_xref(ctx, annot); | |
| 2629 fz_try(ctx) | |
| 2630 { | |
| 2631 check_allowed_subtypes(ctx, annot, PDF_NAME(LLE), line_subtypes); | |
| 2632 value = pdf_dict_get_real(ctx, annot->obj, PDF_NAME(LLE)); | |
| 2633 } | |
| 2634 fz_always(ctx) | |
| 2635 pdf_annot_pop_local_xref(ctx, annot); | |
| 2636 fz_catch(ctx) | |
| 2637 fz_rethrow(ctx); | |
| 2638 return value; | |
| 2639 } | |
| 2640 | |
| 2641 float | |
| 2642 pdf_annot_line_leader_offset(fz_context *ctx, pdf_annot *annot) | |
| 2643 { | |
| 2644 float value; | |
| 2645 pdf_annot_push_local_xref(ctx, annot); | |
| 2646 fz_try(ctx) | |
| 2647 { | |
| 2648 check_allowed_subtypes(ctx, annot, PDF_NAME(LLO), line_subtypes); | |
| 2649 value = pdf_dict_get_real(ctx, annot->obj, PDF_NAME(LLO)); | |
| 2650 } | |
| 2651 fz_always(ctx) | |
| 2652 pdf_annot_pop_local_xref(ctx, annot); | |
| 2653 fz_catch(ctx) | |
| 2654 fz_rethrow(ctx); | |
| 2655 return value; | |
| 2656 } | |
| 2657 | |
| 2658 void | |
| 2659 pdf_set_annot_line_leader(fz_context *ctx, pdf_annot *annot, float value) | |
| 2660 { | |
| 2661 begin_annot_op(ctx, annot, "Set line leader"); | |
| 2662 fz_try(ctx) | |
| 2663 { | |
| 2664 check_allowed_subtypes(ctx, annot, PDF_NAME(LL), line_subtypes); | |
| 2665 if (value) | |
| 2666 pdf_dict_put_real(ctx, annot->obj, PDF_NAME(LL), value); | |
| 2667 else | |
| 2668 pdf_dict_del(ctx, annot->obj, PDF_NAME(LL)); | |
| 2669 end_annot_op(ctx, annot); | |
| 2670 } | |
| 2671 fz_catch(ctx) | |
| 2672 { | |
| 2673 abandon_annot_op(ctx, annot); | |
| 2674 fz_rethrow(ctx); | |
| 2675 } | |
| 2676 pdf_dirty_annot(ctx, annot); | |
| 2677 } | |
| 2678 | |
| 2679 void | |
| 2680 pdf_set_annot_line_leader_extension(fz_context *ctx, pdf_annot *annot, float value) | |
| 2681 { | |
| 2682 begin_annot_op(ctx, annot, "Set line leader_extension"); | |
| 2683 fz_try(ctx) | |
| 2684 { | |
| 2685 check_allowed_subtypes(ctx, annot, PDF_NAME(LLE), line_subtypes); | |
| 2686 if (value) | |
| 2687 pdf_dict_put_real(ctx, annot->obj, PDF_NAME(LLE), value); | |
| 2688 else | |
| 2689 pdf_dict_del(ctx, annot->obj, PDF_NAME(LLE)); | |
| 2690 end_annot_op(ctx, annot); | |
| 2691 } | |
| 2692 fz_catch(ctx) | |
| 2693 { | |
| 2694 abandon_annot_op(ctx, annot); | |
| 2695 fz_rethrow(ctx); | |
| 2696 } | |
| 2697 pdf_dirty_annot(ctx, annot); | |
| 2698 } | |
| 2699 | |
| 2700 void | |
| 2701 pdf_set_annot_line_leader_offset(fz_context *ctx, pdf_annot *annot, float value) | |
| 2702 { | |
| 2703 begin_annot_op(ctx, annot, "Set line leader offset"); | |
| 2704 fz_try(ctx) | |
| 2705 { | |
| 2706 check_allowed_subtypes(ctx, annot, PDF_NAME(LLO), line_subtypes); | |
| 2707 if (value) | |
| 2708 pdf_dict_put_real(ctx, annot->obj, PDF_NAME(LLO), value); | |
| 2709 else | |
| 2710 pdf_dict_del(ctx, annot->obj, PDF_NAME(LLO)); | |
| 2711 end_annot_op(ctx, annot); | |
| 2712 } | |
| 2713 fz_catch(ctx) | |
| 2714 { | |
| 2715 abandon_annot_op(ctx, annot); | |
| 2716 fz_rethrow(ctx); | |
| 2717 } | |
| 2718 pdf_dirty_annot(ctx, annot); | |
| 2719 } | |
| 2720 | |
| 2721 int | |
| 2722 pdf_annot_line_caption(fz_context *ctx, pdf_annot *annot) | |
| 2723 { | |
| 2724 int cap = 0; | |
| 2725 | |
| 2726 pdf_annot_push_local_xref(ctx, annot); | |
| 2727 | |
| 2728 fz_try(ctx) | |
| 2729 { | |
| 2730 check_allowed_subtypes(ctx, annot, PDF_NAME(Cap), line_subtypes); | |
| 2731 | |
| 2732 cap = pdf_dict_get_bool(ctx, annot->obj, PDF_NAME(Cap)); | |
| 2733 } | |
| 2734 fz_always(ctx) | |
| 2735 pdf_annot_pop_local_xref(ctx, annot); | |
| 2736 fz_catch(ctx) | |
| 2737 fz_rethrow(ctx); | |
| 2738 | |
| 2739 return cap; | |
| 2740 } | |
| 2741 | |
| 2742 void | |
| 2743 pdf_set_annot_line_caption(fz_context *ctx, pdf_annot *annot, int cap) | |
| 2744 { | |
| 2745 begin_annot_op(ctx, annot, "Set line caption"); | |
| 2746 | |
| 2747 fz_try(ctx) | |
| 2748 { | |
| 2749 check_allowed_subtypes(ctx, annot, PDF_NAME(Cap), line_subtypes); | |
| 2750 | |
| 2751 pdf_dict_put_bool(ctx, annot->obj, PDF_NAME(Cap), cap); | |
| 2752 | |
| 2753 end_annot_op(ctx, annot); | |
| 2754 } | |
| 2755 fz_catch(ctx) | |
| 2756 { | |
| 2757 abandon_annot_op(ctx, annot); | |
| 2758 fz_rethrow(ctx); | |
| 2759 } | |
| 2760 | |
| 2761 pdf_dirty_annot(ctx, annot); | |
| 2762 } | |
| 2763 | |
| 2764 fz_point | |
| 2765 pdf_annot_line_caption_offset(fz_context *ctx, pdf_annot *annot) | |
| 2766 { | |
| 2767 fz_point offset = fz_make_point(0, 0); | |
| 2768 | |
| 2769 pdf_annot_push_local_xref(ctx, annot); | |
| 2770 | |
| 2771 fz_try(ctx) | |
| 2772 { | |
| 2773 check_allowed_subtypes(ctx, annot, PDF_NAME(CO), line_subtypes); | |
| 2774 | |
| 2775 offset = pdf_dict_get_point(ctx, annot->obj, PDF_NAME(CO)); | |
| 2776 } | |
| 2777 fz_always(ctx) | |
| 2778 pdf_annot_pop_local_xref(ctx, annot); | |
| 2779 fz_catch(ctx) | |
| 2780 fz_rethrow(ctx); | |
| 2781 | |
| 2782 return offset; | |
| 2783 } | |
| 2784 | |
| 2785 void | |
| 2786 pdf_set_annot_line_caption_offset(fz_context *ctx, pdf_annot *annot, fz_point offset) | |
| 2787 { | |
| 2788 begin_annot_op(ctx, annot, "Set line caption"); | |
| 2789 | |
| 2790 fz_try(ctx) | |
| 2791 { | |
| 2792 check_allowed_subtypes(ctx, annot, PDF_NAME(CO), line_subtypes); | |
| 2793 | |
| 2794 if (offset.x == 0 && offset.y == 0) | |
| 2795 pdf_dict_del(ctx, annot->obj, PDF_NAME(CO)); | |
| 2796 else | |
| 2797 pdf_dict_put_point(ctx, annot->obj, PDF_NAME(CO), offset); | |
| 2798 | |
| 2799 end_annot_op(ctx, annot); | |
| 2800 } | |
| 2801 fz_catch(ctx) | |
| 2802 { | |
| 2803 abandon_annot_op(ctx, annot); | |
| 2804 fz_rethrow(ctx); | |
| 2805 } | |
| 2806 | |
| 2807 pdf_dirty_annot(ctx, annot); | |
| 2808 } | |
| 2809 | |
| 2810 static pdf_obj *vertices_subtypes[] = { | |
| 2811 PDF_NAME(PolyLine), | |
| 2812 PDF_NAME(Polygon), | |
| 2813 NULL, | |
| 2814 }; | |
| 2815 | |
| 2816 int | |
| 2817 pdf_annot_has_vertices(fz_context *ctx, pdf_annot *annot) | |
| 2818 { | |
| 2819 return is_allowed_subtype_wrap(ctx, annot, PDF_NAME(Vertices), vertices_subtypes); | |
| 2820 } | |
| 2821 | |
| 2822 int | |
| 2823 pdf_annot_vertex_count(fz_context *ctx, pdf_annot *annot) | |
| 2824 { | |
| 2825 pdf_obj *vertices; | |
| 2826 int ret; | |
| 2827 | |
| 2828 pdf_annot_push_local_xref(ctx, annot); | |
| 2829 | |
| 2830 fz_try(ctx) | |
| 2831 { | |
| 2832 check_allowed_subtypes(ctx, annot, PDF_NAME(Vertices), vertices_subtypes); | |
| 2833 vertices = pdf_dict_get(ctx, annot->obj, PDF_NAME(Vertices)); | |
| 2834 ret = pdf_array_len(ctx, vertices) / 2; | |
| 2835 } | |
| 2836 fz_always(ctx) | |
| 2837 pdf_annot_pop_local_xref(ctx, annot); | |
| 2838 fz_catch(ctx) | |
| 2839 fz_rethrow(ctx); | |
| 2840 | |
| 2841 return ret; | |
| 2842 } | |
| 2843 | |
| 2844 fz_point | |
| 2845 pdf_annot_vertex(fz_context *ctx, pdf_annot *annot, int i) | |
| 2846 { | |
| 2847 pdf_obj *vertices; | |
| 2848 fz_matrix page_ctm; | |
| 2849 fz_point point; | |
| 2850 | |
| 2851 pdf_annot_push_local_xref(ctx, annot); | |
| 2852 | |
| 2853 fz_try(ctx) | |
| 2854 { | |
| 2855 check_allowed_subtypes(ctx, annot, PDF_NAME(Vertices), vertices_subtypes); | |
| 2856 | |
| 2857 vertices = pdf_dict_get(ctx, annot->obj, PDF_NAME(Vertices)); | |
| 2858 | |
| 2859 pdf_page_transform(ctx, annot->page, NULL, &page_ctm); | |
| 2860 | |
| 2861 point.x = pdf_array_get_real(ctx, vertices, i * 2); | |
| 2862 point.y = pdf_array_get_real(ctx, vertices, i * 2 + 1); | |
| 2863 } | |
| 2864 fz_always(ctx) | |
| 2865 pdf_annot_pop_local_xref(ctx, annot); | |
| 2866 fz_catch(ctx) | |
| 2867 fz_rethrow(ctx); | |
| 2868 | |
| 2869 return fz_transform_point(point, page_ctm); | |
| 2870 } | |
| 2871 | |
| 2872 void | |
| 2873 pdf_set_annot_vertices(fz_context *ctx, pdf_annot *annot, int n, const fz_point *v) | |
| 2874 { | |
| 2875 fz_matrix page_ctm, inv_page_ctm; | |
| 2876 pdf_obj *vertices; | |
| 2877 fz_point point; | |
| 2878 int i; | |
| 2879 | |
| 2880 begin_annot_op(ctx, annot, "Set points"); | |
| 2881 | |
| 2882 fz_try(ctx) | |
| 2883 { | |
| 2884 check_allowed_subtypes(ctx, annot, PDF_NAME(Vertices), vertices_subtypes); | |
| 2885 if (n <= 0 || !v) | |
| 2886 fz_throw(ctx, FZ_ERROR_ARGUMENT, "invalid number of vertices"); | |
| 2887 | |
| 2888 pdf_page_transform(ctx, annot->page, NULL, &page_ctm); | |
| 2889 inv_page_ctm = fz_invert_matrix(page_ctm); | |
| 2890 | |
| 2891 vertices = pdf_dict_put_array(ctx, annot->obj, PDF_NAME(Vertices), n * 2); | |
| 2892 for (i = 0; i < n; ++i) | |
| 2893 { | |
| 2894 point = fz_transform_point(v[i], inv_page_ctm); | |
| 2895 pdf_array_push_real(ctx, vertices, point.x); | |
| 2896 pdf_array_push_real(ctx, vertices, point.y); | |
| 2897 } | |
| 2898 end_annot_op(ctx, annot); | |
| 2899 } | |
| 2900 fz_catch(ctx) | |
| 2901 { | |
| 2902 abandon_annot_op(ctx, annot); | |
| 2903 fz_rethrow(ctx); | |
| 2904 } | |
| 2905 | |
| 2906 pdf_dirty_annot(ctx, annot); | |
| 2907 } | |
| 2908 | |
| 2909 void pdf_clear_annot_vertices(fz_context *ctx, pdf_annot *annot) | |
| 2910 { | |
| 2911 begin_annot_op(ctx, annot, "Clear vertices"); | |
| 2912 | |
| 2913 fz_try(ctx) | |
| 2914 { | |
| 2915 check_allowed_subtypes(ctx, annot, PDF_NAME(Vertices), vertices_subtypes); | |
| 2916 pdf_dict_del(ctx, annot->obj, PDF_NAME(Vertices)); | |
| 2917 end_annot_op(ctx, annot); | |
| 2918 } | |
| 2919 fz_catch(ctx) | |
| 2920 { | |
| 2921 abandon_annot_op(ctx, annot); | |
| 2922 fz_rethrow(ctx); | |
| 2923 } | |
| 2924 | |
| 2925 pdf_dirty_annot(ctx, annot); | |
| 2926 } | |
| 2927 | |
| 2928 void pdf_add_annot_vertex(fz_context *ctx, pdf_annot *annot, fz_point p) | |
| 2929 { | |
| 2930 fz_matrix page_ctm, inv_page_ctm; | |
| 2931 pdf_obj *vertices; | |
| 2932 | |
| 2933 begin_annot_op(ctx, annot, "Add point"); | |
| 2934 | |
| 2935 fz_try(ctx) | |
| 2936 { | |
| 2937 check_allowed_subtypes(ctx, annot, PDF_NAME(Vertices), vertices_subtypes); | |
| 2938 | |
| 2939 pdf_page_transform(ctx, annot->page, NULL, &page_ctm); | |
| 2940 inv_page_ctm = fz_invert_matrix(page_ctm); | |
| 2941 | |
| 2942 vertices = pdf_dict_get(ctx, annot->obj, PDF_NAME(Vertices)); | |
| 2943 if (!pdf_is_array(ctx, vertices)) | |
| 2944 vertices = pdf_dict_put_array(ctx, annot->obj, PDF_NAME(Vertices), 32); | |
| 2945 | |
| 2946 p = fz_transform_point(p, inv_page_ctm); | |
| 2947 pdf_array_push_real(ctx, vertices, p.x); | |
| 2948 pdf_array_push_real(ctx, vertices, p.y); | |
| 2949 end_annot_op(ctx, annot); | |
| 2950 } | |
| 2951 fz_catch(ctx) | |
| 2952 { | |
| 2953 abandon_annot_op(ctx, annot); | |
| 2954 fz_rethrow(ctx); | |
| 2955 } | |
| 2956 | |
| 2957 pdf_dirty_annot(ctx, annot); | |
| 2958 } | |
| 2959 | |
| 2960 void pdf_set_annot_vertex(fz_context *ctx, pdf_annot *annot, int i, fz_point p) | |
| 2961 { | |
| 2962 fz_matrix page_ctm, inv_page_ctm; | |
| 2963 pdf_obj *vertices; | |
| 2964 | |
| 2965 begin_annot_op(ctx, annot, "Set point"); | |
| 2966 | |
| 2967 fz_try(ctx) | |
| 2968 { | |
| 2969 check_allowed_subtypes(ctx, annot, PDF_NAME(Vertices), vertices_subtypes); | |
| 2970 | |
| 2971 pdf_page_transform(ctx, annot->page, NULL, &page_ctm); | |
| 2972 inv_page_ctm = fz_invert_matrix(page_ctm); | |
| 2973 | |
| 2974 p = fz_transform_point(p, inv_page_ctm); | |
| 2975 | |
| 2976 vertices = pdf_dict_get(ctx, annot->obj, PDF_NAME(Vertices)); | |
| 2977 pdf_array_put_real(ctx, vertices, i * 2 + 0, p.x); | |
| 2978 pdf_array_put_real(ctx, vertices, i * 2 + 1, p.x); | |
| 2979 end_annot_op(ctx, annot); | |
| 2980 } | |
| 2981 fz_catch(ctx) | |
| 2982 { | |
| 2983 abandon_annot_op(ctx, annot); | |
| 2984 fz_rethrow(ctx); | |
| 2985 } | |
| 2986 } | |
| 2987 | |
| 2988 static pdf_obj *quad_point_subtypes[] = { | |
| 2989 PDF_NAME(Highlight), | |
| 2990 PDF_NAME(Link), | |
| 2991 PDF_NAME(Squiggly), | |
| 2992 PDF_NAME(StrikeOut), | |
| 2993 PDF_NAME(Underline), | |
| 2994 PDF_NAME(Redact), | |
| 2995 NULL, | |
| 2996 }; | |
| 2997 | |
| 2998 int | |
| 2999 pdf_annot_has_quad_points(fz_context *ctx, pdf_annot *annot) | |
| 3000 { | |
| 3001 return is_allowed_subtype_wrap(ctx, annot, PDF_NAME(QuadPoints), quad_point_subtypes); | |
| 3002 } | |
| 3003 | |
| 3004 int | |
| 3005 pdf_annot_quad_point_count(fz_context *ctx, pdf_annot *annot) | |
| 3006 { | |
| 3007 pdf_obj *quad_points; | |
| 3008 int ret; | |
| 3009 | |
| 3010 pdf_annot_push_local_xref(ctx, annot); | |
| 3011 | |
| 3012 fz_try(ctx) | |
| 3013 { | |
| 3014 check_allowed_subtypes(ctx, annot, PDF_NAME(QuadPoints), quad_point_subtypes); | |
| 3015 quad_points = pdf_dict_get(ctx, annot->obj, PDF_NAME(QuadPoints)); | |
| 3016 ret = pdf_array_len(ctx, quad_points) / 8; | |
| 3017 } | |
| 3018 fz_always(ctx) | |
| 3019 pdf_annot_pop_local_xref(ctx, annot); | |
| 3020 fz_catch(ctx) | |
| 3021 fz_rethrow(ctx); | |
| 3022 | |
| 3023 return ret; | |
| 3024 } | |
| 3025 | |
| 3026 fz_quad | |
| 3027 pdf_annot_quad_point(fz_context *ctx, pdf_annot *annot, int idx) | |
| 3028 { | |
| 3029 pdf_obj *quad_points; | |
| 3030 fz_matrix page_ctm; | |
| 3031 float v[8]; | |
| 3032 int i; | |
| 3033 | |
| 3034 pdf_annot_push_local_xref(ctx, annot); | |
| 3035 | |
| 3036 fz_try(ctx) | |
| 3037 { | |
| 3038 check_allowed_subtypes(ctx, annot, PDF_NAME(QuadPoints), quad_point_subtypes); | |
| 3039 quad_points = pdf_dict_get(ctx, annot->obj, PDF_NAME(QuadPoints)); | |
| 3040 pdf_page_transform(ctx, annot->page, NULL, &page_ctm); | |
| 3041 | |
| 3042 for (i = 0; i < 8; i += 2) | |
| 3043 { | |
| 3044 fz_point point; | |
| 3045 point.x = pdf_array_get_real(ctx, quad_points, idx * 8 + i + 0); | |
| 3046 point.y = pdf_array_get_real(ctx, quad_points, idx * 8 + i + 1); | |
| 3047 point = fz_transform_point(point, page_ctm); | |
| 3048 v[i+0] = point.x; | |
| 3049 v[i+1] = point.y; | |
| 3050 } | |
| 3051 } | |
| 3052 fz_always(ctx) | |
| 3053 pdf_annot_pop_local_xref(ctx, annot); | |
| 3054 fz_catch(ctx) | |
| 3055 fz_rethrow(ctx); | |
| 3056 | |
| 3057 return fz_make_quad(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]); | |
| 3058 } | |
| 3059 | |
| 3060 void | |
| 3061 pdf_set_annot_quad_points(fz_context *ctx, pdf_annot *annot, int n, const fz_quad *q) | |
| 3062 { | |
| 3063 fz_matrix page_ctm, inv_page_ctm; | |
| 3064 pdf_obj *quad_points; | |
| 3065 fz_quad quad; | |
| 3066 int i; | |
| 3067 | |
| 3068 begin_annot_op(ctx, annot, "Set quad points"); | |
| 3069 | |
| 3070 fz_try(ctx) | |
| 3071 { | |
| 3072 check_allowed_subtypes(ctx, annot, PDF_NAME(QuadPoints), quad_point_subtypes); | |
| 3073 if (n <= 0 || !q) | |
| 3074 fz_throw(ctx, FZ_ERROR_ARGUMENT, "invalid number of quadrilaterals"); | |
| 3075 | |
| 3076 pdf_page_transform(ctx, annot->page, NULL, &page_ctm); | |
| 3077 inv_page_ctm = fz_invert_matrix(page_ctm); | |
| 3078 | |
| 3079 quad_points = pdf_dict_put_array(ctx, annot->obj, PDF_NAME(QuadPoints), n); | |
| 3080 for (i = 0; i < n; ++i) | |
| 3081 { | |
| 3082 quad = fz_transform_quad(q[i], inv_page_ctm); | |
| 3083 pdf_array_push_real(ctx, quad_points, quad.ul.x); | |
| 3084 pdf_array_push_real(ctx, quad_points, quad.ul.y); | |
| 3085 pdf_array_push_real(ctx, quad_points, quad.ur.x); | |
| 3086 pdf_array_push_real(ctx, quad_points, quad.ur.y); | |
| 3087 pdf_array_push_real(ctx, quad_points, quad.ll.x); | |
| 3088 pdf_array_push_real(ctx, quad_points, quad.ll.y); | |
| 3089 pdf_array_push_real(ctx, quad_points, quad.lr.x); | |
| 3090 pdf_array_push_real(ctx, quad_points, quad.lr.y); | |
| 3091 } | |
| 3092 | |
| 3093 end_annot_op(ctx, annot); | |
| 3094 } | |
| 3095 fz_catch(ctx) | |
| 3096 { | |
| 3097 abandon_annot_op(ctx, annot); | |
| 3098 fz_rethrow(ctx); | |
| 3099 } | |
| 3100 | |
| 3101 pdf_dirty_annot(ctx, annot); | |
| 3102 } | |
| 3103 | |
| 3104 void | |
| 3105 pdf_clear_annot_quad_points(fz_context *ctx, pdf_annot *annot) | |
| 3106 { | |
| 3107 begin_annot_op(ctx, annot, "Clear quad points"); | |
| 3108 | |
| 3109 fz_try(ctx) | |
| 3110 { | |
| 3111 check_allowed_subtypes(ctx, annot, PDF_NAME(QuadPoints), quad_point_subtypes); | |
| 3112 pdf_dict_del(ctx, annot->obj, PDF_NAME(QuadPoints)); | |
| 3113 end_annot_op(ctx, annot); | |
| 3114 } | |
| 3115 fz_catch(ctx) | |
| 3116 { | |
| 3117 abandon_annot_op(ctx, annot); | |
| 3118 fz_rethrow(ctx); | |
| 3119 } | |
| 3120 | |
| 3121 pdf_dirty_annot(ctx, annot); | |
| 3122 } | |
| 3123 | |
| 3124 void | |
| 3125 pdf_add_annot_quad_point(fz_context *ctx, pdf_annot *annot, fz_quad quad) | |
| 3126 { | |
| 3127 fz_matrix page_ctm, inv_page_ctm; | |
| 3128 pdf_obj *quad_points; | |
| 3129 | |
| 3130 begin_annot_op(ctx, annot, "Add quad point"); | |
| 3131 | |
| 3132 fz_try(ctx) | |
| 3133 { | |
| 3134 check_allowed_subtypes(ctx, annot, PDF_NAME(QuadPoints), quad_point_subtypes); | |
| 3135 | |
| 3136 pdf_page_transform(ctx, annot->page, NULL, &page_ctm); | |
| 3137 inv_page_ctm = fz_invert_matrix(page_ctm); | |
| 3138 | |
| 3139 quad_points = pdf_dict_get(ctx, annot->obj, PDF_NAME(QuadPoints)); | |
| 3140 if (!pdf_is_array(ctx, quad_points)) | |
| 3141 quad_points = pdf_dict_put_array(ctx, annot->obj, PDF_NAME(QuadPoints), 8); | |
| 3142 | |
| 3143 /* Contrary to the specification, the points within a QuadPoint are NOT ordered | |
| 3144 * in a counterclockwise fashion. Experiments with Adobe's implementation | |
| 3145 * indicates a cross-wise ordering is intended: ul, ur, ll, lr. | |
| 3146 */ | |
| 3147 quad = fz_transform_quad(quad, inv_page_ctm); | |
| 3148 pdf_array_push_real(ctx, quad_points, quad.ul.x); | |
| 3149 pdf_array_push_real(ctx, quad_points, quad.ul.y); | |
| 3150 pdf_array_push_real(ctx, quad_points, quad.ur.x); | |
| 3151 pdf_array_push_real(ctx, quad_points, quad.ur.y); | |
| 3152 pdf_array_push_real(ctx, quad_points, quad.ll.x); | |
| 3153 pdf_array_push_real(ctx, quad_points, quad.ll.y); | |
| 3154 pdf_array_push_real(ctx, quad_points, quad.lr.x); | |
| 3155 pdf_array_push_real(ctx, quad_points, quad.lr.y); | |
| 3156 end_annot_op(ctx, annot); | |
| 3157 } | |
| 3158 fz_catch(ctx) | |
| 3159 { | |
| 3160 abandon_annot_op(ctx, annot); | |
| 3161 fz_rethrow(ctx); | |
| 3162 } | |
| 3163 | |
| 3164 pdf_dirty_annot(ctx, annot); | |
| 3165 } | |
| 3166 | |
| 3167 static pdf_obj *ink_list_subtypes[] = { | |
| 3168 PDF_NAME(Ink), | |
| 3169 NULL, | |
| 3170 }; | |
| 3171 | |
| 3172 int | |
| 3173 pdf_annot_has_ink_list(fz_context *ctx, pdf_annot *annot) | |
| 3174 { | |
| 3175 return is_allowed_subtype_wrap(ctx, annot, PDF_NAME(InkList), ink_list_subtypes); | |
| 3176 } | |
| 3177 | |
| 3178 int | |
| 3179 pdf_annot_ink_list_count(fz_context *ctx, pdf_annot *annot) | |
| 3180 { | |
| 3181 int ret; | |
| 3182 | |
| 3183 pdf_annot_push_local_xref(ctx, annot); | |
| 3184 | |
| 3185 fz_try(ctx) | |
| 3186 { | |
| 3187 pdf_obj *ink_list; | |
| 3188 check_allowed_subtypes(ctx, annot, PDF_NAME(InkList), ink_list_subtypes); | |
| 3189 ink_list = pdf_dict_get(ctx, annot->obj, PDF_NAME(InkList)); | |
| 3190 ret = pdf_array_len(ctx, ink_list); | |
| 3191 } | |
| 3192 fz_always(ctx) | |
| 3193 pdf_annot_pop_local_xref(ctx, annot); | |
| 3194 fz_catch(ctx) | |
| 3195 fz_rethrow(ctx); | |
| 3196 | |
| 3197 return ret; | |
| 3198 } | |
| 3199 | |
| 3200 int | |
| 3201 pdf_annot_ink_list_stroke_count(fz_context *ctx, pdf_annot *annot, int i) | |
| 3202 { | |
| 3203 pdf_obj *ink_list; | |
| 3204 pdf_obj *stroke; | |
| 3205 int ret; | |
| 3206 | |
| 3207 pdf_annot_push_local_xref(ctx, annot); | |
| 3208 | |
| 3209 fz_try(ctx) | |
| 3210 { | |
| 3211 check_allowed_subtypes(ctx, annot, PDF_NAME(InkList), ink_list_subtypes); | |
| 3212 ink_list = pdf_dict_get(ctx, annot->obj, PDF_NAME(InkList)); | |
| 3213 stroke = pdf_array_get(ctx, ink_list, i); | |
| 3214 ret = pdf_array_len(ctx, stroke) / 2; | |
| 3215 } | |
| 3216 fz_always(ctx) | |
| 3217 pdf_annot_pop_local_xref(ctx, annot); | |
| 3218 fz_catch(ctx) | |
| 3219 fz_rethrow(ctx); | |
| 3220 | |
| 3221 return ret; | |
| 3222 } | |
| 3223 | |
| 3224 fz_point | |
| 3225 pdf_annot_ink_list_stroke_vertex(fz_context *ctx, pdf_annot *annot, int i, int k) | |
| 3226 { | |
| 3227 pdf_obj *ink_list; | |
| 3228 pdf_obj *stroke; | |
| 3229 fz_matrix page_ctm; | |
| 3230 fz_point point; | |
| 3231 | |
| 3232 pdf_annot_push_local_xref(ctx, annot); | |
| 3233 | |
| 3234 fz_try(ctx) | |
| 3235 { | |
| 3236 check_allowed_subtypes(ctx, annot, PDF_NAME(InkList), ink_list_subtypes); | |
| 3237 | |
| 3238 ink_list = pdf_dict_get(ctx, annot->obj, PDF_NAME(InkList)); | |
| 3239 stroke = pdf_array_get(ctx, ink_list, i); | |
| 3240 | |
| 3241 pdf_page_transform(ctx, annot->page, NULL, &page_ctm); | |
| 3242 | |
| 3243 point.x = pdf_array_get_real(ctx, stroke, k * 2 + 0); | |
| 3244 point.y = pdf_array_get_real(ctx, stroke, k * 2 + 1); | |
| 3245 } | |
| 3246 fz_always(ctx) | |
| 3247 pdf_annot_pop_local_xref(ctx, annot); | |
| 3248 fz_catch(ctx) | |
| 3249 fz_rethrow(ctx); | |
| 3250 | |
| 3251 return fz_transform_point(point, page_ctm); | |
| 3252 } | |
| 3253 | |
| 3254 /* FIXME: try/catch required for memory exhaustion */ | |
| 3255 void | |
| 3256 pdf_set_annot_ink_list(fz_context *ctx, pdf_annot *annot, int n, const int *count, const fz_point *v) | |
| 3257 { | |
| 3258 fz_matrix page_ctm, inv_page_ctm; | |
| 3259 pdf_obj *ink_list = NULL, *stroke; | |
| 3260 fz_point point; | |
| 3261 int i, k; | |
| 3262 | |
| 3263 fz_var(ink_list); | |
| 3264 | |
| 3265 begin_annot_op(ctx, annot, "Set ink list"); | |
| 3266 | |
| 3267 fz_try(ctx) | |
| 3268 { | |
| 3269 check_allowed_subtypes(ctx, annot, PDF_NAME(InkList), ink_list_subtypes); | |
| 3270 | |
| 3271 pdf_page_transform(ctx, annot->page, NULL, &page_ctm); | |
| 3272 inv_page_ctm = fz_invert_matrix(page_ctm); | |
| 3273 | |
| 3274 ink_list = pdf_dict_put_array(ctx, annot->obj, PDF_NAME(InkList), n); | |
| 3275 for (i = 0; i < n; ++i) | |
| 3276 { | |
| 3277 stroke = pdf_array_push_array(ctx, ink_list, count[i] * 2); | |
| 3278 | |
| 3279 /* Although we have dropped our reference to stroke, | |
| 3280 * it's still valid because we ink_list holds one, and | |
| 3281 * we hold a reference to that. */ | |
| 3282 for (k = 0; k < count[i]; ++k) | |
| 3283 { | |
| 3284 point = fz_transform_point(*v++, inv_page_ctm); | |
| 3285 pdf_array_push_real(ctx, stroke, point.x); | |
| 3286 pdf_array_push_real(ctx, stroke, point.y); | |
| 3287 } | |
| 3288 } | |
| 3289 end_annot_op(ctx, annot); | |
| 3290 } | |
| 3291 fz_catch(ctx) | |
| 3292 { | |
| 3293 abandon_annot_op(ctx, annot); | |
| 3294 fz_rethrow(ctx); | |
| 3295 } | |
| 3296 | |
| 3297 pdf_dirty_annot(ctx, annot); | |
| 3298 } | |
| 3299 | |
| 3300 void | |
| 3301 pdf_clear_annot_ink_list(fz_context *ctx, pdf_annot *annot) | |
| 3302 { | |
| 3303 begin_annot_op(ctx, annot, "Clear ink list"); | |
| 3304 | |
| 3305 fz_try(ctx) | |
| 3306 { | |
| 3307 check_allowed_subtypes(ctx, annot, PDF_NAME(InkList), ink_list_subtypes); | |
| 3308 pdf_dict_del(ctx, annot->obj, PDF_NAME(InkList)); | |
| 3309 end_annot_op(ctx, annot); | |
| 3310 } | |
| 3311 fz_catch(ctx) | |
| 3312 { | |
| 3313 abandon_annot_op(ctx, annot); | |
| 3314 fz_rethrow(ctx); | |
| 3315 } | |
| 3316 | |
| 3317 pdf_dirty_annot(ctx, annot); | |
| 3318 } | |
| 3319 | |
| 3320 void pdf_add_annot_ink_list_stroke(fz_context *ctx, pdf_annot *annot) | |
| 3321 { | |
| 3322 pdf_obj *ink_list; | |
| 3323 | |
| 3324 begin_annot_op(ctx, annot, "Add ink list stroke"); | |
| 3325 | |
| 3326 fz_try(ctx) | |
| 3327 { | |
| 3328 check_allowed_subtypes(ctx, annot, PDF_NAME(InkList), ink_list_subtypes); | |
| 3329 ink_list = pdf_dict_get(ctx, annot->obj, PDF_NAME(InkList)); | |
| 3330 if (!pdf_is_array(ctx, ink_list)) | |
| 3331 ink_list = pdf_dict_put_array(ctx, annot->obj, PDF_NAME(InkList), 10); | |
| 3332 | |
| 3333 pdf_array_push_array(ctx, ink_list, 16); | |
| 3334 end_annot_op(ctx, annot); | |
| 3335 } | |
| 3336 fz_catch(ctx) | |
| 3337 { | |
| 3338 abandon_annot_op(ctx, annot); | |
| 3339 fz_rethrow(ctx); | |
| 3340 } | |
| 3341 | |
| 3342 pdf_dirty_annot(ctx, annot); | |
| 3343 } | |
| 3344 | |
| 3345 void pdf_add_annot_ink_list_stroke_vertex(fz_context *ctx, pdf_annot *annot, fz_point p) | |
| 3346 { | |
| 3347 fz_matrix page_ctm, inv_page_ctm; | |
| 3348 pdf_obj *ink_list, *stroke; | |
| 3349 | |
| 3350 begin_annot_op(ctx, annot, "Add ink list stroke point"); | |
| 3351 | |
| 3352 fz_try(ctx) | |
| 3353 { | |
| 3354 check_allowed_subtypes(ctx, annot, PDF_NAME(InkList), ink_list_subtypes); | |
| 3355 pdf_page_transform(ctx, annot->page, NULL, &page_ctm); | |
| 3356 inv_page_ctm = fz_invert_matrix(page_ctm); | |
| 3357 | |
| 3358 ink_list = pdf_dict_get(ctx, annot->obj, PDF_NAME(InkList)); | |
| 3359 if (!pdf_is_array(ctx, ink_list)) | |
| 3360 ink_list = pdf_dict_put_array(ctx, annot->obj, PDF_NAME(InkList), 10); | |
| 3361 stroke = pdf_array_get(ctx, ink_list, pdf_array_len(ctx, ink_list)-1); | |
| 3362 if (!pdf_is_array(ctx, stroke)) | |
| 3363 { | |
| 3364 int len = pdf_array_len(ctx, ink_list); | |
| 3365 stroke = pdf_new_array(ctx, pdf_get_bound_document(ctx, ink_list), 16); | |
| 3366 pdf_array_put_drop(ctx, ink_list, len ? len-1 : 0, stroke); | |
| 3367 } | |
| 3368 | |
| 3369 p = fz_transform_point(p, inv_page_ctm); | |
| 3370 pdf_array_push_real(ctx, stroke, p.x); | |
| 3371 pdf_array_push_real(ctx, stroke, p.y); | |
| 3372 end_annot_op(ctx, annot); | |
| 3373 } | |
| 3374 fz_catch(ctx) | |
| 3375 { | |
| 3376 abandon_annot_op(ctx, annot); | |
| 3377 fz_rethrow(ctx); | |
| 3378 } | |
| 3379 | |
| 3380 pdf_dirty_annot(ctx, annot); | |
| 3381 } | |
| 3382 | |
| 3383 void | |
| 3384 pdf_add_annot_ink_list(fz_context *ctx, pdf_annot *annot, int n, fz_point p[]) | |
| 3385 { | |
| 3386 fz_matrix page_ctm, inv_page_ctm; | |
| 3387 pdf_obj *ink_list, *stroke; | |
| 3388 int i; | |
| 3389 | |
| 3390 begin_annot_op(ctx, annot, "Add ink list"); | |
| 3391 | |
| 3392 fz_try(ctx) | |
| 3393 { | |
| 3394 check_allowed_subtypes(ctx, annot, PDF_NAME(InkList), ink_list_subtypes); | |
| 3395 | |
| 3396 pdf_page_transform(ctx, annot->page, NULL, &page_ctm); | |
| 3397 inv_page_ctm = fz_invert_matrix(page_ctm); | |
| 3398 | |
| 3399 ink_list = pdf_dict_get(ctx, annot->obj, PDF_NAME(InkList)); | |
| 3400 if (!pdf_is_array(ctx, ink_list)) | |
| 3401 ink_list = pdf_dict_put_array(ctx, annot->obj, PDF_NAME(InkList), 10); | |
| 3402 | |
| 3403 stroke = pdf_array_push_array(ctx, ink_list, n * 2); | |
| 3404 for (i = 0; i < n; ++i) | |
| 3405 { | |
| 3406 fz_point tp = fz_transform_point(p[i], inv_page_ctm); | |
| 3407 pdf_array_push_real(ctx, stroke, tp.x); | |
| 3408 pdf_array_push_real(ctx, stroke, tp.y); | |
| 3409 } | |
| 3410 end_annot_op(ctx, annot); | |
| 3411 } | |
| 3412 fz_catch(ctx) | |
| 3413 { | |
| 3414 abandon_annot_op(ctx, annot); | |
| 3415 fz_rethrow(ctx); | |
| 3416 } | |
| 3417 | |
| 3418 pdf_dirty_annot(ctx, annot); | |
| 3419 } | |
| 3420 | |
| 3421 /* | |
| 3422 Get annotation's modification date in seconds since the epoch. | |
| 3423 */ | |
| 3424 int64_t | |
| 3425 pdf_annot_modification_date(fz_context *ctx, pdf_annot *annot) | |
| 3426 { | |
| 3427 int64_t ret; | |
| 3428 | |
| 3429 pdf_annot_push_local_xref(ctx, annot); | |
| 3430 | |
| 3431 fz_try(ctx) | |
| 3432 { | |
| 3433 ret = pdf_dict_get_date(ctx, annot->obj, PDF_NAME(M)); | |
| 3434 } | |
| 3435 fz_always(ctx) | |
| 3436 pdf_annot_pop_local_xref(ctx, annot); | |
| 3437 fz_catch(ctx) | |
| 3438 fz_rethrow(ctx); | |
| 3439 | |
| 3440 return ret; | |
| 3441 } | |
| 3442 | |
| 3443 /* | |
| 3444 Get annotation's creation date in seconds since the epoch. | |
| 3445 */ | |
| 3446 int64_t | |
| 3447 pdf_annot_creation_date(fz_context *ctx, pdf_annot *annot) | |
| 3448 { | |
| 3449 int64_t ret; | |
| 3450 | |
| 3451 pdf_annot_push_local_xref(ctx, annot); | |
| 3452 | |
| 3453 fz_try(ctx) | |
| 3454 ret = pdf_dict_get_date(ctx, annot->obj, PDF_NAME(CreationDate)); | |
| 3455 fz_always(ctx) | |
| 3456 pdf_annot_pop_local_xref(ctx, annot); | |
| 3457 fz_catch(ctx) | |
| 3458 fz_rethrow(ctx); | |
| 3459 | |
| 3460 return ret; | |
| 3461 } | |
| 3462 | |
| 3463 /* | |
| 3464 Set annotation's modification date in seconds since the epoch. | |
| 3465 */ | |
| 3466 void | |
| 3467 pdf_set_annot_modification_date(fz_context *ctx, pdf_annot *annot, int64_t secs) | |
| 3468 { | |
| 3469 begin_annot_op(ctx, annot, "Set modification date"); | |
| 3470 | |
| 3471 fz_try(ctx) | |
| 3472 { | |
| 3473 pdf_dict_put_date(ctx, annot->obj, PDF_NAME(M), secs); | |
| 3474 end_annot_op(ctx, annot); | |
| 3475 } | |
| 3476 fz_catch(ctx) | |
| 3477 { | |
| 3478 abandon_annot_op(ctx, annot); | |
| 3479 fz_rethrow(ctx); | |
| 3480 } | |
| 3481 | |
| 3482 pdf_dirty_annot(ctx, annot); | |
| 3483 } | |
| 3484 | |
| 3485 /* | |
| 3486 Set annotation's creation date in seconds since the epoch. | |
| 3487 */ | |
| 3488 void | |
| 3489 pdf_set_annot_creation_date(fz_context *ctx, pdf_annot *annot, int64_t secs) | |
| 3490 { | |
| 3491 begin_annot_op(ctx, annot, "Set creation date"); | |
| 3492 | |
| 3493 fz_try(ctx) | |
| 3494 { | |
| 3495 check_allowed_subtypes(ctx, annot, PDF_NAME(CreationDate), markup_subtypes); | |
| 3496 pdf_dict_put_date(ctx, annot->obj, PDF_NAME(CreationDate), secs); | |
| 3497 end_annot_op(ctx, annot); | |
| 3498 } | |
| 3499 fz_catch(ctx) | |
| 3500 { | |
| 3501 abandon_annot_op(ctx, annot); | |
| 3502 fz_rethrow(ctx); | |
| 3503 } | |
| 3504 | |
| 3505 pdf_dirty_annot(ctx, annot); | |
| 3506 } | |
| 3507 | |
| 3508 int | |
| 3509 pdf_annot_has_author(fz_context *ctx, pdf_annot *annot) | |
| 3510 { | |
| 3511 return is_allowed_subtype_wrap(ctx, annot, PDF_NAME(T), markup_subtypes); | |
| 3512 } | |
| 3513 | |
| 3514 const char * | |
| 3515 pdf_annot_author(fz_context *ctx, pdf_annot *annot) | |
| 3516 { | |
| 3517 const char *ret; | |
| 3518 | |
| 3519 pdf_annot_push_local_xref(ctx, annot); | |
| 3520 | |
| 3521 fz_try(ctx) | |
| 3522 { | |
| 3523 check_allowed_subtypes(ctx, annot, PDF_NAME(T), markup_subtypes); | |
| 3524 ret = pdf_dict_get_text_string(ctx, annot->obj, PDF_NAME(T)); | |
| 3525 } | |
| 3526 fz_always(ctx) | |
| 3527 pdf_annot_pop_local_xref(ctx, annot); | |
| 3528 fz_catch(ctx) | |
| 3529 fz_rethrow(ctx); | |
| 3530 | |
| 3531 return ret; | |
| 3532 } | |
| 3533 | |
| 3534 void | |
| 3535 pdf_set_annot_author(fz_context *ctx, pdf_annot *annot, const char *author) | |
| 3536 { | |
| 3537 begin_annot_op(ctx, annot, "Set author"); | |
| 3538 | |
| 3539 fz_try(ctx) | |
| 3540 { | |
| 3541 check_allowed_subtypes(ctx, annot, PDF_NAME(T), markup_subtypes); | |
| 3542 pdf_dict_put_text_string(ctx, annot->obj, PDF_NAME(T), author); | |
| 3543 pdf_dirty_annot(ctx, annot); | |
| 3544 end_annot_op(ctx, annot); | |
| 3545 } | |
| 3546 fz_catch(ctx) | |
| 3547 { | |
| 3548 abandon_annot_op(ctx, annot); | |
| 3549 fz_rethrow(ctx); | |
| 3550 } | |
| 3551 } | |
| 3552 | |
| 3553 static pdf_obj *intent_subtypes[] = { | |
| 3554 PDF_NAME(FreeText), | |
| 3555 PDF_NAME(Line), | |
| 3556 PDF_NAME(Polygon), | |
| 3557 PDF_NAME(PolyLine), | |
| 3558 PDF_NAME(Stamp), | |
| 3559 NULL, | |
| 3560 }; | |
| 3561 | |
| 3562 enum pdf_intent pdf_intent_from_name(fz_context *ctx, pdf_obj *it) | |
| 3563 { | |
| 3564 if ( | |
| 3565 it == PDF_NULL || | |
| 3566 it == PDF_NAME(FreeText) || | |
| 3567 it == PDF_NAME(Line) || | |
| 3568 it == PDF_NAME(PolyLine) || | |
| 3569 it == PDF_NAME(Polygon) || | |
| 3570 it == PDF_NAME(Stamp) | |
| 3571 ) | |
| 3572 return PDF_ANNOT_IT_DEFAULT; | |
| 3573 if (it == PDF_NAME(FreeTextCallout)) | |
| 3574 return PDF_ANNOT_IT_FREETEXT_CALLOUT; | |
| 3575 if (it == PDF_NAME(FreeTextTypeWriter)) | |
| 3576 return PDF_ANNOT_IT_FREETEXT_TYPEWRITER; | |
| 3577 if (it == PDF_NAME(LineArrow)) | |
| 3578 return PDF_ANNOT_IT_LINE_ARROW; | |
| 3579 if (it == PDF_NAME(LineDimension)) | |
| 3580 return PDF_ANNOT_IT_LINE_DIMENSION; | |
| 3581 if (it == PDF_NAME(PolyLineDimension)) | |
| 3582 return PDF_ANNOT_IT_POLYLINE_DIMENSION; | |
| 3583 if (it == PDF_NAME(PolygonCloud)) | |
| 3584 return PDF_ANNOT_IT_POLYGON_CLOUD; | |
| 3585 if (it == PDF_NAME(PolygonDimension)) | |
| 3586 return PDF_ANNOT_IT_POLYGON_DIMENSION; | |
| 3587 if (it == PDF_NAME(StampImage)) | |
| 3588 return PDF_ANNOT_IT_STAMP_IMAGE; | |
| 3589 if (it == PDF_NAME(StampSnapshot)) | |
| 3590 return PDF_ANNOT_IT_STAMP_SNAPSHOT; | |
| 3591 return PDF_ANNOT_IT_UNKNOWN; | |
| 3592 } | |
| 3593 | |
| 3594 enum pdf_intent pdf_intent_from_string(fz_context *ctx, const char *it) | |
| 3595 { | |
| 3596 if ( | |
| 3597 it == NULL || | |
| 3598 !strcmp(it, "FreeText") || | |
| 3599 !strcmp(it, "Line") || | |
| 3600 !strcmp(it, "PolyLine") || | |
| 3601 !strcmp(it, "Polygon") || | |
| 3602 !strcmp(it, "Stamp") | |
| 3603 ) | |
| 3604 return PDF_ANNOT_IT_DEFAULT; | |
| 3605 if (!strcmp(it, "FreeTextCallout")) | |
| 3606 return PDF_ANNOT_IT_FREETEXT_CALLOUT; | |
| 3607 if (!strcmp(it, "FreeTextTypeWriter")) | |
| 3608 return PDF_ANNOT_IT_FREETEXT_TYPEWRITER; | |
| 3609 if (!strcmp(it, "LineArrow")) | |
| 3610 return PDF_ANNOT_IT_LINE_ARROW; | |
| 3611 if (!strcmp(it, "LineDimension")) | |
| 3612 return PDF_ANNOT_IT_LINE_DIMENSION; | |
| 3613 if (!strcmp(it, "PolyLineDimension")) | |
| 3614 return PDF_ANNOT_IT_POLYLINE_DIMENSION; | |
| 3615 if (!strcmp(it, "PolygonCloud")) | |
| 3616 return PDF_ANNOT_IT_POLYGON_CLOUD; | |
| 3617 if (!strcmp(it, "PolygonDimension")) | |
| 3618 return PDF_ANNOT_IT_POLYGON_DIMENSION; | |
| 3619 if (!strcmp(it, "StampImage")) | |
| 3620 return PDF_ANNOT_IT_STAMP_IMAGE; | |
| 3621 if (!strcmp(it, "StampSnapshot")) | |
| 3622 return PDF_ANNOT_IT_STAMP_SNAPSHOT; | |
| 3623 return PDF_ANNOT_IT_UNKNOWN; | |
| 3624 } | |
| 3625 | |
| 3626 pdf_obj *pdf_name_from_intent(fz_context *ctx, enum pdf_intent it) | |
| 3627 { | |
| 3628 switch (it) | |
| 3629 { | |
| 3630 default: | |
| 3631 case PDF_ANNOT_IT_DEFAULT: return PDF_NULL; | |
| 3632 case PDF_ANNOT_IT_FREETEXT_CALLOUT: return PDF_NAME(FreeTextCallout); | |
| 3633 case PDF_ANNOT_IT_FREETEXT_TYPEWRITER: return PDF_NAME(FreeTextTypeWriter); | |
| 3634 case PDF_ANNOT_IT_LINE_ARROW: return PDF_NAME(LineArrow); | |
| 3635 case PDF_ANNOT_IT_LINE_DIMENSION: return PDF_NAME(LineDimension); | |
| 3636 case PDF_ANNOT_IT_POLYLINE_DIMENSION: return PDF_NAME(PolyLineDimension); | |
| 3637 case PDF_ANNOT_IT_POLYGON_CLOUD: return PDF_NAME(PolygonCloud); | |
| 3638 case PDF_ANNOT_IT_POLYGON_DIMENSION: return PDF_NAME(PolygonDimension); | |
| 3639 } | |
| 3640 } | |
| 3641 | |
| 3642 const char *pdf_string_from_intent(fz_context *ctx, enum pdf_intent it) | |
| 3643 { | |
| 3644 switch (it) | |
| 3645 { | |
| 3646 default: | |
| 3647 case PDF_ANNOT_IT_DEFAULT: return NULL; | |
| 3648 case PDF_ANNOT_IT_FREETEXT_CALLOUT: return "FreeTextCallout"; | |
| 3649 case PDF_ANNOT_IT_FREETEXT_TYPEWRITER: return "FreeTextTypeWriter"; | |
| 3650 case PDF_ANNOT_IT_LINE_ARROW: return "LineArrow"; | |
| 3651 case PDF_ANNOT_IT_LINE_DIMENSION: return "LineDimension"; | |
| 3652 case PDF_ANNOT_IT_POLYLINE_DIMENSION: return "PolyLineDimension"; | |
| 3653 case PDF_ANNOT_IT_POLYGON_CLOUD: return "PolygonCloud"; | |
| 3654 case PDF_ANNOT_IT_POLYGON_DIMENSION: return "PolygonDimension"; | |
| 3655 } | |
| 3656 } | |
| 3657 | |
| 3658 int | |
| 3659 pdf_annot_has_intent(fz_context *ctx, pdf_annot *annot) | |
| 3660 { | |
| 3661 /* Only a subset of intents are defined in the spec, so we limit this API to the defined ones. | |
| 3662 * FreeText: Callout, TypeWriter | |
| 3663 * Line: Arrow, Dimension | |
| 3664 * Polygon: Cloud, Dimension | |
| 3665 * PolyLine: Dimension | |
| 3666 */ | |
| 3667 return is_allowed_subtype_wrap(ctx, annot, PDF_NAME(IT), intent_subtypes); | |
| 3668 } | |
| 3669 | |
| 3670 enum pdf_intent | |
| 3671 pdf_annot_intent(fz_context *ctx, pdf_annot *annot) | |
| 3672 { | |
| 3673 enum pdf_intent ret; | |
| 3674 | |
| 3675 pdf_annot_push_local_xref(ctx, annot); | |
| 3676 | |
| 3677 fz_try(ctx) | |
| 3678 { | |
| 3679 check_allowed_subtypes(ctx, annot, PDF_NAME(IT), intent_subtypes); | |
| 3680 ret = pdf_intent_from_name(ctx, pdf_dict_get(ctx, annot->obj, PDF_NAME(IT))); | |
| 3681 } | |
| 3682 fz_always(ctx) | |
| 3683 pdf_annot_pop_local_xref(ctx, annot); | |
| 3684 fz_catch(ctx) | |
| 3685 fz_rethrow(ctx); | |
| 3686 | |
| 3687 return ret; | |
| 3688 } | |
| 3689 | |
| 3690 void | |
| 3691 pdf_set_annot_intent(fz_context *ctx, pdf_annot *annot, enum pdf_intent it) | |
| 3692 { | |
| 3693 begin_annot_op(ctx, annot, "Set intent"); | |
| 3694 | |
| 3695 fz_try(ctx) | |
| 3696 { | |
| 3697 check_allowed_subtypes(ctx, annot, PDF_NAME(IT), intent_subtypes); | |
| 3698 pdf_dict_put(ctx, annot->obj, PDF_NAME(IT), pdf_name_from_intent(ctx, it)); | |
| 3699 pdf_dirty_annot(ctx, annot); | |
| 3700 end_annot_op(ctx, annot); | |
| 3701 } | |
| 3702 fz_catch(ctx) | |
| 3703 { | |
| 3704 abandon_annot_op(ctx, annot); | |
| 3705 fz_rethrow(ctx); | |
| 3706 } | |
| 3707 } | |
| 3708 | |
| 3709 static pdf_obj *callout_subtypes[] = { | |
| 3710 PDF_NAME(FreeText), | |
| 3711 NULL, | |
| 3712 }; | |
| 3713 | |
| 3714 int pdf_annot_has_callout(fz_context *ctx, pdf_annot *annot) | |
| 3715 { | |
| 3716 return is_allowed_subtype_wrap(ctx, annot, PDF_NAME(CL), callout_subtypes); | |
| 3717 } | |
| 3718 | |
| 3719 enum pdf_line_ending pdf_annot_callout_style(fz_context *ctx, pdf_annot *annot) | |
| 3720 { | |
| 3721 enum pdf_line_ending style = PDF_ANNOT_LE_NONE; | |
| 3722 pdf_obj *obj; | |
| 3723 pdf_annot_push_local_xref(ctx, annot); | |
| 3724 fz_try(ctx) | |
| 3725 { | |
| 3726 check_allowed_subtypes(ctx, annot, PDF_NAME(CL), callout_subtypes); | |
| 3727 obj = pdf_dict_get(ctx, annot->obj, PDF_NAME(LE)); | |
| 3728 style = pdf_line_ending_from_name(ctx, obj); | |
| 3729 } | |
| 3730 fz_always(ctx) | |
| 3731 pdf_annot_pop_local_xref(ctx, annot); | |
| 3732 fz_catch(ctx) | |
| 3733 fz_rethrow(ctx); | |
| 3734 return style; | |
| 3735 } | |
| 3736 | |
| 3737 void pdf_set_annot_callout_style(fz_context *ctx, pdf_annot *annot, enum pdf_line_ending style) | |
| 3738 { | |
| 3739 begin_annot_op(ctx, annot, "Set callout style"); | |
| 3740 | |
| 3741 fz_try(ctx) | |
| 3742 { | |
| 3743 check_allowed_subtypes(ctx, annot, PDF_NAME(CL), callout_subtypes); | |
| 3744 pdf_dict_put(ctx, annot->obj, PDF_NAME(LE), pdf_name_from_line_ending(ctx, style)); | |
| 3745 } | |
| 3746 fz_catch(ctx) | |
| 3747 { | |
| 3748 abandon_annot_op(ctx, annot); | |
| 3749 fz_rethrow(ctx); | |
| 3750 } | |
| 3751 | |
| 3752 pdf_dirty_annot(ctx, annot); | |
| 3753 } | |
| 3754 | |
| 3755 void pdf_annot_callout_line(fz_context *ctx, pdf_annot *annot, fz_point callout[3], int *np) | |
| 3756 { | |
| 3757 pdf_annot_push_local_xref(ctx, annot); | |
| 3758 fz_try(ctx) | |
| 3759 { | |
| 3760 fz_matrix page_ctm; | |
| 3761 pdf_obj *obj; | |
| 3762 int n; | |
| 3763 | |
| 3764 check_allowed_subtypes(ctx, annot, PDF_NAME(CL), callout_subtypes); | |
| 3765 | |
| 3766 pdf_page_transform(ctx, annot->page, NULL, &page_ctm); | |
| 3767 | |
| 3768 obj = pdf_dict_get(ctx, annot->obj, PDF_NAME(CL)); | |
| 3769 n = pdf_array_len(ctx, obj); | |
| 3770 if (n == 4 || n == 6) | |
| 3771 { | |
| 3772 callout[0] = fz_transform_point_xy(pdf_array_get_real(ctx, obj, 0), pdf_array_get_real(ctx, obj, 1), page_ctm); | |
| 3773 callout[1] = fz_transform_point_xy(pdf_array_get_real(ctx, obj, 2), pdf_array_get_real(ctx, obj, 3), page_ctm); | |
| 3774 if (n == 4) | |
| 3775 { | |
| 3776 *np = 2; | |
| 3777 callout[2] = fz_make_point(0, 0); | |
| 3778 } | |
| 3779 else | |
| 3780 { | |
| 3781 *np = 3; | |
| 3782 callout[2] = fz_transform_point_xy(pdf_array_get_real(ctx, obj, 4), pdf_array_get_real(ctx, obj, 5), page_ctm); | |
| 3783 } | |
| 3784 } | |
| 3785 else | |
| 3786 { | |
| 3787 callout[0] = fz_make_point(0, 0); | |
| 3788 callout[1] = fz_make_point(0, 0); | |
| 3789 callout[2] = fz_make_point(0, 0); | |
| 3790 *np = 0; | |
| 3791 } | |
| 3792 } | |
| 3793 fz_always(ctx) | |
| 3794 pdf_annot_pop_local_xref(ctx, annot); | |
| 3795 fz_catch(ctx) | |
| 3796 fz_rethrow(ctx); | |
| 3797 } | |
| 3798 | |
| 3799 void pdf_set_annot_callout_line(fz_context *ctx, pdf_annot *annot, fz_point callout[3], int n) | |
| 3800 { | |
| 3801 begin_annot_op(ctx, annot, "Set callout"); | |
| 3802 | |
| 3803 fz_try(ctx) | |
| 3804 { | |
| 3805 fz_matrix page_ctm; | |
| 3806 fz_point p; | |
| 3807 int i; | |
| 3808 pdf_obj *obj; | |
| 3809 | |
| 3810 check_allowed_subtypes(ctx, annot, PDF_NAME(CL), callout_subtypes); | |
| 3811 | |
| 3812 if (n == 2 || n == 3) | |
| 3813 { | |
| 3814 pdf_page_transform(ctx, annot->page, NULL, &page_ctm); | |
| 3815 obj = pdf_dict_put_array(ctx, annot->obj, PDF_NAME(CL), n * 2); | |
| 3816 for (i = 0; i < n; ++i) | |
| 3817 { | |
| 3818 p = fz_transform_point(callout[i], page_ctm); | |
| 3819 pdf_array_push_real(ctx, obj, p.x); | |
| 3820 pdf_array_push_real(ctx, obj, p.y); | |
| 3821 } | |
| 3822 } | |
| 3823 else | |
| 3824 { | |
| 3825 pdf_dict_del(ctx, annot->obj, PDF_NAME(CL)); | |
| 3826 } | |
| 3827 | |
| 3828 pdf_dirty_annot(ctx, annot); | |
| 3829 end_annot_op(ctx, annot); | |
| 3830 } | |
| 3831 fz_catch(ctx) | |
| 3832 { | |
| 3833 abandon_annot_op(ctx, annot); | |
| 3834 fz_rethrow(ctx); | |
| 3835 } | |
| 3836 } | |
| 3837 | |
| 3838 fz_point pdf_annot_callout_point(fz_context *ctx, pdf_annot *annot) | |
| 3839 { | |
| 3840 fz_point line[3]; | |
| 3841 int n; | |
| 3842 | |
| 3843 pdf_annot_callout_line(ctx, annot, line, &n); | |
| 3844 if (n > 0) | |
| 3845 return line[0]; | |
| 3846 return fz_make_point(0, 0); | |
| 3847 } | |
| 3848 | |
| 3849 void pdf_set_annot_callout_point(fz_context *ctx, pdf_annot *annot, fz_point p) | |
| 3850 { | |
| 3851 fz_rect rect; | |
| 3852 fz_point a, b, line[3]; | |
| 3853 float m; | |
| 3854 | |
| 3855 rect = pdf_annot_rect(ctx, annot); | |
| 3856 | |
| 3857 // Make line from center of text box to designated end point. | |
| 3858 a = fz_make_point((rect.x0 + rect.x1) / 2, (rect.y0 + rect.y1) / 2); | |
| 3859 b = p; | |
| 3860 | |
| 3861 // No CalloutLine if end point is within the text box itself. | |
| 3862 if (fz_is_point_inside_rect(p, rect)) | |
| 3863 { | |
| 3864 line[0] = p; | |
| 3865 line[1] = a; | |
| 3866 pdf_set_annot_callout_line(ctx, annot, line, 2); | |
| 3867 return; | |
| 3868 } | |
| 3869 | |
| 3870 // Simplified Cohen-Sutherland algorithm to find intersection of line and text box. | |
| 3871 m = (b.y - a.y) / (b.x - a.x); | |
| 3872 for (;;) | |
| 3873 { | |
| 3874 if (b.y < rect.y0) { | |
| 3875 b.x = a.x + (rect.y0 - a.y) / m; | |
| 3876 b.y = rect.y0; | |
| 3877 } | |
| 3878 else | |
| 3879 if (b.y > rect.y1) { | |
| 3880 b.x = a.x + (rect.y1 - a.y) / m; | |
| 3881 b.y = rect.y1; | |
| 3882 } | |
| 3883 else | |
| 3884 if (b.x < rect.x0) { | |
| 3885 b.y = a.y + (rect.x0 - a.x) * m; | |
| 3886 b.x = rect.x0; | |
| 3887 } | |
| 3888 else | |
| 3889 if (b.x > rect.x1) { | |
| 3890 b.y = a.y + (rect.x1 - a.x) * m; | |
| 3891 b.x = rect.x1; | |
| 3892 } | |
| 3893 else | |
| 3894 break; | |
| 3895 } | |
| 3896 | |
| 3897 // Draw line from intersection to end point. | |
| 3898 line[0] = p; | |
| 3899 line[1] = b; | |
| 3900 pdf_set_annot_callout_line(ctx, annot, line, 2); | |
| 3901 } | |
| 3902 | |
| 3903 void | |
| 3904 pdf_parse_default_appearance_unmapped(fz_context *ctx, const char *da, char *font_name, int font_name_size, float *size, int *n, float color[4]) | |
| 3905 { | |
| 3906 char buf[100], *p = buf, *tok, *end; | |
| 3907 float stack[4] = { 0, 0, 0, 0 }; | |
| 3908 int top = 0; | |
| 3909 | |
| 3910 fz_strlcpy(font_name, "Helv", font_name_size); | |
| 3911 *size = 12; | |
| 3912 *n = 0; | |
| 3913 color[0] = color[1] = color[2] = color[3] = 0; | |
| 3914 | |
| 3915 fz_strlcpy(buf, da, sizeof buf); | |
| 3916 while ((tok = fz_strsep(&p, " \n\r\t")) != NULL) | |
| 3917 { | |
| 3918 if (tok[0] == 0) | |
| 3919 ; | |
| 3920 else if (tok[0] == '/') | |
| 3921 { | |
| 3922 fz_strlcpy(font_name, tok+1, font_name_size); | |
| 3923 } | |
| 3924 else if (!strcmp(tok, "Tf")) | |
| 3925 { | |
| 3926 *size = stack[0]; | |
| 3927 top = 0; | |
| 3928 } | |
| 3929 else if (!strcmp(tok, "g")) | |
| 3930 { | |
| 3931 *n = 1; | |
| 3932 color[0] = stack[0]; | |
| 3933 top = 0; | |
| 3934 } | |
| 3935 else if (!strcmp(tok, "rg")) | |
| 3936 { | |
| 3937 *n = 3; | |
| 3938 color[0] = stack[0]; | |
| 3939 color[1] = stack[1]; | |
| 3940 color[2] = stack[2]; | |
| 3941 top=0; | |
| 3942 } | |
| 3943 else if (!strcmp(tok, "k")) | |
| 3944 { | |
| 3945 *n = 4; | |
| 3946 color[0] = stack[0]; | |
| 3947 color[1] = stack[1]; | |
| 3948 color[2] = stack[2]; | |
| 3949 color[3] = stack[3]; | |
| 3950 top=0; | |
| 3951 } | |
| 3952 else | |
| 3953 { | |
| 3954 float v = fz_strtof(tok, &end); | |
| 3955 if (top < 4) | |
| 3956 stack[top] = v; | |
| 3957 if (*end == 0) | |
| 3958 ++top; | |
| 3959 else | |
| 3960 top = 0; | |
| 3961 } | |
| 3962 } | |
| 3963 } | |
| 3964 | |
| 3965 void | |
| 3966 pdf_parse_default_appearance(fz_context *ctx, const char *da, const char **font, float *size, int *n, float color[4]) | |
| 3967 { | |
| 3968 char font_name[100]; | |
| 3969 | |
| 3970 pdf_parse_default_appearance_unmapped(ctx, da, font_name, sizeof font_name, size, n, color); | |
| 3971 | |
| 3972 if (!strcmp(font_name, "Cour")) *font = "Cour"; | |
| 3973 else if (!strcmp(font_name, "Helv")) *font = "Helv"; | |
| 3974 else if (!strcmp(font_name, "TiRo")) *font = "TiRo"; | |
| 3975 else if (!strcmp(font_name, "Symb")) *font = "Symb"; | |
| 3976 else if (!strcmp(font_name, "ZaDb")) *font = "ZaDb"; | |
| 3977 else *font = "Helv"; | |
| 3978 } | |
| 3979 | |
| 3980 void | |
| 3981 pdf_print_default_appearance(fz_context *ctx, char *buf, int nbuf, const char *font, float size, int n, const float *color) | |
| 3982 { | |
| 3983 if (n == 4) | |
| 3984 fz_snprintf(buf, nbuf, "/%s %g Tf %g %g %g %g k", font, size, color[0], color[1], color[2], color[3]); | |
| 3985 else if (n == 3) | |
| 3986 fz_snprintf(buf, nbuf, "/%s %g Tf %g %g %g rg", font, size, color[0], color[1], color[2]); | |
| 3987 else if (n == 1) | |
| 3988 fz_snprintf(buf, nbuf, "/%s %g Tf %g g", font, size, color[0]); | |
| 3989 else | |
| 3990 fz_snprintf(buf, nbuf, "/%s %g Tf", font, size); | |
| 3991 } | |
| 3992 | |
| 3993 void | |
| 3994 pdf_annot_default_appearance_unmapped(fz_context *ctx, pdf_annot *annot, char *font_name, int font_name_len, float *size, int *n, float color[4]) | |
| 3995 { | |
| 3996 pdf_obj *da; | |
| 3997 pdf_annot_push_local_xref(ctx, annot); | |
| 3998 | |
| 3999 fz_try(ctx) | |
| 4000 { | |
| 4001 da = pdf_dict_get_inheritable(ctx, annot->obj, PDF_NAME(DA)); | |
| 4002 if (!da) | |
| 4003 { | |
| 4004 pdf_obj *trailer = pdf_trailer(ctx, annot->page->doc); | |
| 4005 da = pdf_dict_getl(ctx, trailer, PDF_NAME(Root), PDF_NAME(AcroForm), PDF_NAME(DA), NULL); | |
| 4006 } | |
| 4007 pdf_parse_default_appearance_unmapped(ctx, pdf_to_str_buf(ctx, da), font_name, font_name_len, size, n, color); | |
| 4008 } | |
| 4009 fz_always(ctx) | |
| 4010 pdf_annot_pop_local_xref(ctx, annot); | |
| 4011 fz_catch(ctx) | |
| 4012 fz_rethrow(ctx); | |
| 4013 } | |
| 4014 | |
| 4015 static pdf_obj *default_appearance_subtypes[] = { | |
| 4016 PDF_NAME(FreeText), | |
| 4017 PDF_NAME(Widget), | |
| 4018 NULL, | |
| 4019 }; | |
| 4020 | |
| 4021 int | |
| 4022 pdf_annot_has_default_appearance(fz_context *ctx, pdf_annot *annot) | |
| 4023 { | |
| 4024 return is_allowed_subtype_wrap(ctx, annot, PDF_NAME(DA), default_appearance_subtypes); | |
| 4025 } | |
| 4026 | |
| 4027 void | |
| 4028 pdf_annot_default_appearance(fz_context *ctx, pdf_annot *annot, const char **font, float *size, int *n, float color[4]) | |
| 4029 { | |
| 4030 pdf_obj *da; | |
| 4031 pdf_annot_push_local_xref(ctx, annot); | |
| 4032 | |
| 4033 fz_try(ctx) | |
| 4034 { | |
| 4035 check_allowed_subtypes(ctx, annot, PDF_NAME(DA), default_appearance_subtypes); | |
| 4036 da = pdf_dict_get_inheritable(ctx, annot->obj, PDF_NAME(DA)); | |
| 4037 if (!da) | |
| 4038 { | |
| 4039 pdf_obj *trailer = pdf_trailer(ctx, annot->page->doc); | |
| 4040 da = pdf_dict_getl(ctx, trailer, PDF_NAME(Root), PDF_NAME(AcroForm), PDF_NAME(DA), NULL); | |
| 4041 } | |
| 4042 pdf_parse_default_appearance(ctx, pdf_to_str_buf(ctx, da), font, size, n, color); | |
| 4043 } | |
| 4044 fz_always(ctx) | |
| 4045 pdf_annot_pop_local_xref(ctx, annot); | |
| 4046 fz_catch(ctx) | |
| 4047 fz_rethrow(ctx); | |
| 4048 } | |
| 4049 | |
| 4050 void | |
| 4051 pdf_set_annot_default_appearance(fz_context *ctx, pdf_annot *annot, const char *font, float size, int n, const float *color) | |
| 4052 { | |
| 4053 char buf[100]; | |
| 4054 | |
| 4055 begin_annot_op(ctx, annot, "Set default appearance"); | |
| 4056 | |
| 4057 fz_try(ctx) | |
| 4058 { | |
| 4059 check_allowed_subtypes(ctx, annot, PDF_NAME(DA), default_appearance_subtypes); | |
| 4060 pdf_print_default_appearance(ctx, buf, sizeof buf, font, size, n, color); | |
| 4061 | |
| 4062 pdf_dict_put_string(ctx, annot->obj, PDF_NAME(DA), buf, strlen(buf)); | |
| 4063 | |
| 4064 pdf_dict_del(ctx, annot->obj, PDF_NAME(DS)); /* not supported */ | |
| 4065 pdf_dict_del(ctx, annot->obj, PDF_NAME(RC)); /* not supported */ | |
| 4066 end_annot_op(ctx, annot); | |
| 4067 } | |
| 4068 fz_catch(ctx) | |
| 4069 { | |
| 4070 abandon_annot_op(ctx, annot); | |
| 4071 fz_rethrow(ctx); | |
| 4072 } | |
| 4073 | |
| 4074 pdf_dirty_annot(ctx, annot); | |
| 4075 } | |
| 4076 | |
| 4077 int pdf_annot_field_flags(fz_context *ctx, pdf_annot *annot) | |
| 4078 { | |
| 4079 int ret; | |
| 4080 | |
| 4081 pdf_annot_push_local_xref(ctx, annot); | |
| 4082 | |
| 4083 fz_try(ctx) | |
| 4084 ret = pdf_field_flags(ctx, annot->obj); | |
| 4085 fz_always(ctx) | |
| 4086 pdf_annot_pop_local_xref(ctx, annot); | |
| 4087 fz_catch(ctx) | |
| 4088 fz_rethrow(ctx); | |
| 4089 | |
| 4090 return ret; | |
| 4091 } | |
| 4092 | |
| 4093 const char *pdf_annot_field_value(fz_context *ctx, pdf_annot *widget) | |
| 4094 { | |
| 4095 const char *ret; | |
| 4096 | |
| 4097 pdf_annot_push_local_xref(ctx, widget); | |
| 4098 | |
| 4099 fz_try(ctx) | |
| 4100 ret = pdf_field_value(ctx, widget->obj); | |
| 4101 fz_always(ctx) | |
| 4102 pdf_annot_pop_local_xref(ctx, widget); | |
| 4103 fz_catch(ctx) | |
| 4104 fz_rethrow(ctx); | |
| 4105 | |
| 4106 return ret; | |
| 4107 } | |
| 4108 | |
| 4109 const char *pdf_annot_field_label(fz_context *ctx, pdf_annot *widget) | |
| 4110 { | |
| 4111 const char *ret; | |
| 4112 | |
| 4113 pdf_annot_push_local_xref(ctx, widget); | |
| 4114 | |
| 4115 fz_try(ctx) | |
| 4116 ret = pdf_field_label(ctx, widget->obj); | |
| 4117 fz_always(ctx) | |
| 4118 pdf_annot_pop_local_xref(ctx, widget); | |
| 4119 fz_catch(ctx) | |
| 4120 fz_rethrow(ctx); | |
| 4121 | |
| 4122 return ret; | |
| 4123 } | |
| 4124 | |
| 4125 int pdf_set_annot_field_value(fz_context *ctx, pdf_document *doc, pdf_annot *annot, const char *text, int ignore_trigger_events) | |
| 4126 { | |
| 4127 int ret; | |
| 4128 | |
| 4129 begin_annot_op(ctx, annot, "Set field value"); | |
| 4130 | |
| 4131 fz_try(ctx) | |
| 4132 { | |
| 4133 ret = pdf_set_field_value(ctx, doc, annot->obj, text, ignore_trigger_events); | |
| 4134 end_annot_op(ctx, annot); | |
| 4135 } | |
| 4136 fz_catch(ctx) | |
| 4137 { | |
| 4138 abandon_annot_op(ctx, annot); | |
| 4139 fz_rethrow(ctx); | |
| 4140 } | |
| 4141 | |
| 4142 pdf_dirty_annot(ctx, annot); | |
| 4143 | |
| 4144 return ret; | |
| 4145 } | |
| 4146 | |
| 4147 void | |
| 4148 pdf_set_annot_appearance(fz_context *ctx, pdf_annot *annot, const char *appearance, const char *state, fz_matrix ctm, fz_rect bbox, pdf_obj *res, fz_buffer *contents) | |
| 4149 { | |
| 4150 pdf_obj *form = NULL; | |
| 4151 pdf_obj *ap, *app; | |
| 4152 pdf_obj *app_name = NULL; | |
| 4153 | |
| 4154 begin_annot_op(ctx, annot, "Set appearance stream"); | |
| 4155 | |
| 4156 if (!appearance) | |
| 4157 appearance = "N"; | |
| 4158 | |
| 4159 fz_var(form); | |
| 4160 fz_var(app_name); | |
| 4161 | |
| 4162 fz_try(ctx) | |
| 4163 { | |
| 4164 ap = pdf_dict_get(ctx, annot->obj, PDF_NAME(AP)); | |
| 4165 if (!ap) | |
| 4166 ap = pdf_dict_put_dict(ctx, annot->obj, PDF_NAME(AP), 1); | |
| 4167 | |
| 4168 if (!state) | |
| 4169 form = pdf_keep_obj(ctx, pdf_dict_gets(ctx, ap, appearance)); | |
| 4170 else | |
| 4171 { | |
| 4172 if (strcmp(appearance, "N") && strcmp(appearance, "R") && strcmp(appearance, "D")) | |
| 4173 fz_throw(ctx, FZ_ERROR_ARGUMENT, "Unknown annotation appearance"); | |
| 4174 | |
| 4175 app_name = pdf_new_name(ctx, appearance); | |
| 4176 app = pdf_dict_get(ctx, ap, app_name); | |
| 4177 if (!app) | |
| 4178 app = pdf_dict_put_dict(ctx, ap, app_name, 2); | |
| 4179 form = pdf_keep_obj(ctx, pdf_dict_gets(ctx, ap, appearance)); | |
| 4180 } | |
| 4181 /* Care required here. Some files have multiple annotations, which share | |
| 4182 * appearance streams. As such, we must NOT reuse such appearance streams. | |
| 4183 * On the other hand, we cannot afford to always recreate appearance | |
| 4184 * streams, as this can lead to leakage of partial edits into the document. | |
| 4185 * Any appearance we generate will be in the incremental section, and we | |
| 4186 * will never generate shared appearances. As such, we can reuse an | |
| 4187 * appearance object only if it is in the incremental section. */ | |
| 4188 if (!pdf_obj_is_incremental(ctx, form)) | |
| 4189 { | |
| 4190 pdf_drop_obj(ctx, form); | |
| 4191 form = NULL; | |
| 4192 } | |
| 4193 if (!pdf_is_dict(ctx, form)) | |
| 4194 { | |
| 4195 pdf_drop_obj(ctx, form); | |
| 4196 form = NULL; | |
| 4197 form = pdf_new_xobject(ctx, annot->page->doc, bbox, ctm, res, contents); | |
| 4198 } | |
| 4199 else | |
| 4200 pdf_update_xobject(ctx, annot->page->doc, form, bbox, ctm, res, contents); | |
| 4201 | |
| 4202 if (!state) | |
| 4203 pdf_dict_puts(ctx, ap, appearance, form); | |
| 4204 else | |
| 4205 pdf_dict_puts(ctx, app, state, form); | |
| 4206 end_annot_op(ctx, annot); | |
| 4207 } | |
| 4208 fz_always(ctx) | |
| 4209 { | |
| 4210 pdf_drop_obj(ctx, form); | |
| 4211 pdf_drop_obj(ctx, app_name); | |
| 4212 } | |
| 4213 fz_catch(ctx) | |
| 4214 { | |
| 4215 abandon_annot_op(ctx, annot); | |
| 4216 fz_rethrow(ctx); | |
| 4217 } | |
| 4218 | |
| 4219 pdf_set_annot_resynthesised(ctx, annot); | |
| 4220 } | |
| 4221 | |
| 4222 void | |
| 4223 pdf_set_annot_appearance_from_display_list(fz_context *ctx, pdf_annot *annot, const char *appearance, const char *state, fz_matrix ctm, fz_display_list *list) | |
| 4224 { | |
| 4225 pdf_document *doc; | |
| 4226 fz_device *dev = NULL; | |
| 4227 pdf_obj *res = NULL; | |
| 4228 fz_buffer *contents = NULL; | |
| 4229 | |
| 4230 /* Convert fitz-space mediabox to pdf-space bbox */ | |
| 4231 fz_rect mediabox = fz_bound_display_list(ctx, list); | |
| 4232 fz_matrix transform = { 1, 0, 0, -1, -mediabox.x0, mediabox.y1 }; | |
| 4233 fz_rect bbox = fz_transform_rect(mediabox, transform); | |
| 4234 | |
| 4235 fz_var(dev); | |
| 4236 fz_var(contents); | |
| 4237 fz_var(res); | |
| 4238 | |
| 4239 begin_annot_op(ctx, annot, "Set appearance stream"); | |
| 4240 doc = annot->page->doc; | |
| 4241 | |
| 4242 fz_try(ctx) | |
| 4243 { | |
| 4244 res = pdf_new_dict(ctx, doc, 1); | |
| 4245 contents = fz_new_buffer(ctx, 0); | |
| 4246 dev = pdf_new_pdf_device(ctx, doc, transform, res, contents); | |
| 4247 fz_run_display_list(ctx, list, dev, fz_identity, fz_infinite_rect, NULL); | |
| 4248 fz_close_device(ctx, dev); | |
| 4249 fz_drop_device(ctx, dev); | |
| 4250 dev = NULL; | |
| 4251 | |
| 4252 pdf_set_annot_appearance(ctx, annot, appearance, state, ctm, bbox, res, contents); | |
| 4253 end_annot_op(ctx, annot); | |
| 4254 } | |
| 4255 fz_always(ctx) | |
| 4256 { | |
| 4257 fz_drop_device(ctx, dev); | |
| 4258 fz_drop_buffer(ctx, contents); | |
| 4259 pdf_drop_obj(ctx, res); | |
| 4260 } | |
| 4261 fz_catch(ctx) | |
| 4262 { | |
| 4263 abandon_annot_op(ctx, annot); | |
| 4264 fz_rethrow(ctx); | |
| 4265 } | |
| 4266 } | |
| 4267 | |
| 4268 static pdf_obj *stamp_subtypes[] = { | |
| 4269 PDF_NAME(Stamp), | |
| 4270 NULL, | |
| 4271 }; | |
| 4272 | |
| 4273 pdf_obj * | |
| 4274 pdf_annot_stamp_image_obj(fz_context *ctx, pdf_annot *annot) | |
| 4275 { | |
| 4276 pdf_obj *obj, *imgobj = NULL; | |
| 4277 | |
| 4278 pdf_annot_push_local_xref(ctx, annot); | |
| 4279 | |
| 4280 fz_try(ctx) | |
| 4281 { | |
| 4282 obj = pdf_dict_getp(ctx, annot->obj, "AP/N/Resources/XObject"); | |
| 4283 if (pdf_dict_len(ctx, obj) == 1) | |
| 4284 { | |
| 4285 obj = pdf_dict_get_val(ctx, obj, 0); | |
| 4286 if (pdf_is_image_stream(ctx, obj)) | |
| 4287 imgobj = obj; | |
| 4288 } | |
| 4289 } | |
| 4290 fz_always(ctx) | |
| 4291 pdf_annot_pop_local_xref(ctx, annot); | |
| 4292 fz_catch(ctx) | |
| 4293 fz_rethrow(ctx); | |
| 4294 | |
| 4295 return imgobj; | |
| 4296 } | |
| 4297 | |
| 4298 void pdf_set_annot_stamp_image_obj(fz_context *ctx, pdf_annot *annot, pdf_obj *ref) | |
| 4299 { | |
| 4300 begin_annot_op(ctx, annot, "Set stamp image"); | |
| 4301 | |
| 4302 fz_try(ctx) | |
| 4303 { | |
| 4304 check_allowed_subtypes(ctx, annot, PDF_NAME(Stamp), stamp_subtypes); | |
| 4305 | |
| 4306 pdf_dict_del(ctx, annot->obj, PDF_NAME(AP)); | |
| 4307 pdf_dict_putp(ctx, annot->obj, "AP/N/Resources/XObject/I", ref); | |
| 4308 | |
| 4309 end_annot_op(ctx, annot); | |
| 4310 } | |
| 4311 fz_catch(ctx) | |
| 4312 { | |
| 4313 abandon_annot_op(ctx, annot); | |
| 4314 fz_rethrow(ctx); | |
| 4315 } | |
| 4316 | |
| 4317 pdf_dirty_annot(ctx, annot); | |
| 4318 } | |
| 4319 | |
| 4320 void pdf_set_annot_stamp_image(fz_context *ctx, pdf_annot *annot, fz_image *img) | |
| 4321 { | |
| 4322 pdf_obj *ref = pdf_add_image(ctx, annot->page->doc, img); | |
| 4323 fz_try(ctx) | |
| 4324 pdf_set_annot_stamp_image_obj(ctx, annot, ref); | |
| 4325 fz_always(ctx) | |
| 4326 pdf_drop_obj(ctx, ref); | |
| 4327 fz_catch(ctx) | |
| 4328 fz_rethrow(ctx); | |
| 4329 } | |
| 4330 | |
| 4331 static pdf_obj *filespec_subtypes[] = { | |
| 4332 PDF_NAME(FileAttachment), | |
| 4333 NULL, | |
| 4334 }; | |
| 4335 | |
| 4336 int | |
| 4337 pdf_annot_has_filespec(fz_context *ctx, pdf_annot *annot) | |
| 4338 { | |
| 4339 return is_allowed_subtype_wrap(ctx, annot, PDF_NAME(FS), filespec_subtypes); | |
| 4340 } | |
| 4341 | |
| 4342 pdf_obj * | |
| 4343 pdf_annot_filespec(fz_context *ctx, pdf_annot *annot) | |
| 4344 { | |
| 4345 pdf_obj *filespec; | |
| 4346 | |
| 4347 pdf_annot_push_local_xref(ctx, annot); | |
| 4348 | |
| 4349 fz_try(ctx) | |
| 4350 { | |
| 4351 check_allowed_subtypes(ctx, annot, PDF_NAME(FS), filespec_subtypes); | |
| 4352 filespec = pdf_dict_get(ctx, annot->obj, PDF_NAME(FS)); | |
| 4353 } | |
| 4354 fz_always(ctx) | |
| 4355 pdf_annot_pop_local_xref(ctx, annot); | |
| 4356 fz_catch(ctx) | |
| 4357 fz_rethrow(ctx); | |
| 4358 | |
| 4359 return filespec; | |
| 4360 } | |
| 4361 | |
| 4362 void | |
| 4363 pdf_set_annot_filespec(fz_context *ctx, pdf_annot *annot, pdf_obj *fs) | |
| 4364 { | |
| 4365 if (fs != PDF_NULL && !pdf_is_embedded_file(ctx, fs)) | |
| 4366 fz_throw(ctx, FZ_ERROR_ARGUMENT, "cannot set non-filespec as annotation filespec"); | |
| 4367 | |
| 4368 begin_annot_op(ctx, annot, "Set filespec"); | |
| 4369 | |
| 4370 fz_try(ctx) | |
| 4371 { | |
| 4372 check_allowed_subtypes(ctx, annot, PDF_NAME(M), filespec_subtypes); | |
| 4373 pdf_dict_put(ctx, pdf_annot_obj(ctx, annot), PDF_NAME(FS), fs); | |
| 4374 end_annot_op(ctx, annot); | |
| 4375 } | |
| 4376 fz_catch(ctx) | |
| 4377 { | |
| 4378 abandon_annot_op(ctx, annot); | |
| 4379 fz_rethrow(ctx); | |
| 4380 } | |
| 4381 | |
| 4382 pdf_dirty_annot(ctx, annot); | |
| 4383 } | |
| 4384 | |
| 4385 int | |
| 4386 pdf_annot_hidden_for_editing(fz_context *ctx, pdf_annot *annot) | |
| 4387 { | |
| 4388 return annot->hidden_editing; | |
| 4389 } | |
| 4390 | |
| 4391 void | |
| 4392 pdf_set_annot_hidden_for_editing(fz_context *ctx, pdf_annot *annot, int hidden) | |
| 4393 { | |
| 4394 annot->hidden_editing = hidden; | |
| 4395 } |
