comparison mupdf-source/scripts/wrap/classes.py @ 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 '''
2 Extra information to customise how we wrap MuPDF structs into C++ classes.
3 '''
4
5 import textwrap
6
7 import jlib
8
9 from . import rename
10 from . import state
11 from . import util
12
13
14 class ExtraMethod:
15 '''
16 Defines a prototype and implementation of a custom method in a generated
17 class.
18 '''
19 def __init__( self, return_, name_args, body, comment, overload=None):
20 '''
21 return_:
22 Return type as a string.
23 name_args:
24 A string describing name and args of the method:
25 <method-name>(<args>)
26 body:
27 Implementation code including the enclosing '{...}'.
28 comment:
29 Optional comment; should include /* and */ or //.
30 overload:
31 If true, we allow auto-generation of methods with same name.
32 '''
33 assert name_args
34 self.return_ = return_
35 self.name_args = name_args
36 self.body = body
37 self.comment = comment
38 self.overload = overload
39 assert '\t' not in body
40 def __str__(self):
41 return f'{self.name_args} => {self.return_}'
42
43
44 class ExtraConstructor:
45 '''
46 Defines a prototype and implementation of a custom constructor in a
47 generated class.
48 '''
49 def __init__( self, name_args, body, comment):
50 '''
51 name_args:
52 A string of the form: (<args>)
53 body:
54 Implementation code including the enclosing '{...}'.
55 comment:
56 Optional comment; should include /* and */ or //.
57 '''
58 self.return_ = ''
59 self.name_args = name_args
60 self.body = body
61 self.comment = comment
62 assert '\t' not in body
63
64
65 class ClassExtra:
66 '''
67 Extra methods/features when wrapping a particular MuPDF struct into a C++
68 class.
69 '''
70 def __init__( self,
71 accessors=None,
72 class_bottom='',
73 class_post='',
74 class_pre='',
75 class_top='',
76 constructor_default=True,
77 constructor_excludes=None,
78 constructor_prefixes=None,
79 constructor_raw=True,
80 constructors_extra=None,
81 constructors_wrappers=None,
82 copyable=True,
83 extra_cpp='',
84 iterator_next=None,
85 methods_extra=None,
86 method_wrappers=None,
87 method_wrappers_static=None,
88 opaque=False,
89 pod=False,
90 virtual_fnptrs=False,
91 ):
92 '''
93 accessors:
94 If true, we generate accessors methods for all items in the
95 underlying struct.
96
97 Defaults to True if pod is True, else False.
98
99 class_bottom:
100 Extra text at end of class definition, e.g. for member variables.
101
102 class_post:
103 Extra text after class definition, e.g. complete definition of
104 iterator class.
105
106 class_pre:
107 Extra text before class definition, e.g. forward declaration of
108 iterator class.
109
110 class_top:
111 Extra text at start of class definition, e.g. for enums.
112
113 constructor_default:
114 If None we set to true if `pod` is true, otherwise false. If
115 true, we create a default constructor. If `pod` is true this
116 constructor will default-initialise each member, otherwise it will
117 set `m_internal` to null.
118
119 constructor_excludes:
120 Lists of constructor functions to ignore.
121
122 constructor_prefixes:
123 Extra fz_*() function name prefixes that can be used by class
124 constructors_wrappers. We find all functions whose name starts with one of
125 the specified prefixes and which returns a pointer to the relevant
126 fz struct.
127
128 For each function we find, we make a constructor that takes the
129 required arguments and set m_internal to what this function
130 returns.
131
132 If there is a '-' item, we omit the default 'fz_new_<type>' prefix.
133
134 constructor_raw:
135 If true, create a constructor that takes a pointer to an instance
136 of the wrapped fz_ struct. If 'default', this constructor arg
137 defaults to NULL. If 'declaration_only' we declare the constructor
138 but do not write out the function definition - typically this will
139 be instead specified as custom code in <extra_cpp>.
140
141 constructors_extra:
142 List of ExtraConstructor's, allowing arbitrary constructors_wrappers to be
143 specified.
144
145 constructors_wrappers:
146 List of fns to use as constructors_wrappers.
147
148 copyable:
149 If 'default' we allow default copy constructor to be created by C++
150 compiler. This is useful for plain structs that are not referenced
151 counted but can still be copied, but which we don't want to specify
152 pod=True.
153
154 Otherwise if true, generated wrapper class must be copyable. If
155 pod is false, we generate a copy constructor by looking for a
156 fz_keep_*() function; it's an error if we can't find this function
157 [2024-01-24 fixme: actually we don't appear to raise an
158 error in this case, instead we make class non-copyable.
159 e.g. FzCompressedBuffer.].
160
161 Otherwise if false we create a private copy constructor.
162
163 [todo: need to check docs for interaction of pod/copyable.]
164
165 extra_cpp:
166 Extra text for .cpp file, e.g. implementation of iterator class
167 methods.
168
169 iterator_next:
170 Support for iterating forwards over linked list.
171
172 Should be (first, last).
173
174 first:
175 Name of element within the wrapped class that points to the
176 first item in the linked list. We assume that this element will
177 have 'next' pointers that terminate in NULL.
178
179 If <first> is '', the container is itself the first element in
180 the linked list.
181
182 last:
183 Currently unused, but could be used for reverse iteration in
184 the future.
185
186 We generate begin() and end() methods, plus a separate iterator
187 class, to allow iteration over the linked list starting at
188 <structname>::<first> and iterating to ->next until we reach NULL.
189
190 methods_extra:
191 List of ExtraMethod's, allowing arbitrary methods to be specified.
192
193 method_wrappers:
194 Extra fz_*() function names that should be wrapped in class
195 methods.
196
197 E.g. 'fz_foo_bar' is converted to a method called foo_bar()
198 that takes same parameters as fz_foo_bar() except context and
199 any pointer to struct and fz_context*. The implementation calls
200 fz_foo_bar(), converting exceptions etc.
201
202 The first arg that takes underlying fz_*_s type is omitted and
203 implementation passes <this>.
204
205 method_wrappers_static:
206 Like <method_wrappers>, but generates static methods, where no args
207 are replaced by <this>.
208
209 opaque:
210 If true, we generate a wrapper even if there's no definition
211 available for the struct, i.e. it's only available as a forward
212 declaration.
213
214 pod:
215 If 'inline', there is no m_internal; instead, each member of the
216 underlying class is placed in the wrapper class and special method
217 `internal()` returns a fake pointer to underlying class.
218
219 If 'none', there is no m_internal member at all. Typically
220 <extra_cpp> could be used to add in custom members.
221
222 If True, underlying class is POD and m_internal is an instance of
223 the underlying class instead of a pointer to it.
224
225 virtual_fnptrs:
226 If true, should be a dict with these keys:
227
228 alloc:
229 A string containing C++ code to be embedded in the
230 virtual_fnptrs wrapper class's constructor.
231
232 If the wrapper class is a POD, the MuPDF struct is already
233 available as part of the wrapper class instance (as
234 m_internal, or `internal()` if inline). Otherwise this
235 code should set `m_internal` to point to a newly allocated
236 instance of the MuPDF struct.
237
238 Should typically set up the MuPDF struct so that `self_()`
239 can return the original C++ wrapper class instance.
240 comment:
241 Extra comment for the wrapper class.
242 free:
243 Optional code for freeing the virtual_fnptrs wrapper
244 class. If specified this causes creation of a destructor
245 function.
246
247 This is only needed for non-ref-counted classes that are
248 not marked as POD. In this case the wrapper class has a
249 pointer `m_internal` member that will not be automatically
250 freed by the destructor, and `alloc` will usually have set
251 it to a newly allocated struct.
252 self_:
253 A callable that returns a string containing C++ code for
254 embedding in each low-level callback. It should returns a
255 pointer to the original C++ virtual_fnptrs wrapper class.
256
257 If `self_n` is None, this callable takes no args. Otherwise
258 it takes the name of the `self_n`'th arg.
259 self_n:
260 Index of arg in each low-level callback, for the arg that
261 should be passed to `self_`. We use the same index for all
262 low-level callbacks. If not specified, default is 1 (we
263 generally expect args to be (fz_context* ctx, void*, ...).
264 If None, `self_` is called with no arg; this is for if we
265 use a different mechanism such as a global variable.
266
267 We generate a virtual_fnptrs wrapper class, derived from the main
268 wrapper class, where the main wrapper class's function pointers end
269 up calling the virtual_fnptrs wrapper class's virtual methods. We
270 then use SWIG's 'Director' support to allow these virtual methods
271 to be overridden in Python/C#. Thus one can make MuPDF function
272 pointers call Python/C# code.
273 '''
274 if accessors is None and pod is True:
275 accessors = True
276 if constructor_default is None:
277 constructor_default = pod
278 self.accessors = accessors
279 self.class_bottom = class_bottom
280 self.class_post = class_post
281 self.class_pre = class_pre
282 self.class_top = class_top
283 self.constructor_default = constructor_default
284 self.constructor_excludes = constructor_excludes or []
285 self.constructor_prefixes = constructor_prefixes or []
286 self.constructor_raw = constructor_raw
287 self.constructors_extra = constructors_extra or []
288 self.constructors_wrappers = constructors_wrappers or []
289 self.copyable = copyable
290 self.extra_cpp = extra_cpp
291 self.iterator_next = iterator_next
292 self.methods_extra = methods_extra or []
293 self.method_wrappers = method_wrappers or []
294 self.method_wrappers_static = method_wrappers_static or []
295 self.opaque = opaque
296 self.pod = pod
297 self.virtual_fnptrs = virtual_fnptrs
298
299 assert self.pod in (False, True, 'inline', 'none'), f'{self.pod}'
300
301 def assert_list_of( items, type_):
302 assert isinstance( items, list)
303 for item in items:
304 assert isinstance( item, type_)
305
306 assert_list_of( self.constructor_prefixes, str)
307 assert_list_of( self.method_wrappers, str)
308 assert_list_of( self.method_wrappers_static, str)
309 assert_list_of( self.methods_extra, ExtraMethod)
310 assert_list_of( self.constructors_extra, ExtraConstructor)
311
312 if virtual_fnptrs:
313 assert isinstance(virtual_fnptrs, dict), f'virtual_fnptrs={virtual_fnptrs!r}'
314
315 def __str__( self):
316 ret = ''
317 ret += f' accessors={self.accessors}'
318 ret += f' class_bottom={self.class_bottom}'
319 ret += f' class_post={self.class_post}'
320 ret += f' class_pre={self.class_pre}'
321 ret += f' class_top={self.class_top}'
322 ret += f' constructor_default={self.constructor_default}'
323 ret += f' constructor_excludes={self.constructor_excludes}'
324 ret += f' constructor_prefixes={self.constructor_prefixes}'
325 ret += f' constructor_raw={self.constructor_raw}'
326 ret += f' constructors_extra={self.constructors_extra}'
327 ret += f' constructors_wrappers={self.constructors_wrappers}'
328 ret += f' copyable={self.copyable}'
329 ret += f' extra_cpp={self.extra_cpp}'
330 ret += f' iterator_next={self.iterator_next}'
331 ret += f' methods_extra={self.methods_extra}'
332 ret += f' method_wrappers={self.method_wrappers}'
333 ret += f' method_wrappers_static={self.method_wrappers_static}'
334 ret += f' opaque={self.opaque}'
335 ret += f' pod={self.pod}'
336 ret += f' virtual_fnptrs={self.virtual_fnptrs}'
337 return ret
338
339
340
341 class ClassExtras:
342 '''
343 Extra methods/features for each of our auto-generated C++ wrapper classes.
344 '''
345 def __init__( self, **namevalues):
346 '''
347 namevalues:
348 Named args mapping from struct name (e.g. fz_document) to a
349 ClassExtra.
350 '''
351 self.items = dict()
352 for name, value in namevalues.items():
353 self.items[ name] = value
354
355 def get( self, tu, name):
356 '''
357 Searches for <name> and returns a ClassExtra instance. If <name> is not
358 found, we insert an empty ClassExtra instance and return it. We do this
359 for any name, e.g. name could be 'foo *'.
360
361 We return None if <name> is a known enum.
362 '''
363 verbose = state.state_.show_details( name)
364 if 0 and verbose:
365 jlib.log( 'ClassExtras.get(): {=name}')
366 name = util.clip( name, ('const ', 'struct '))
367 if 0 and verbose:
368 jlib.log( 'ClassExtras.get(): {=name}')
369 if not name.startswith( ('fz_', 'pdf_')):
370 return
371
372 ret = self.items.setdefault( name, ClassExtra())
373
374 if name in state.state_.enums[ tu]:
375 #jlib.log( '*** name is an enum: {name=}')
376 return None
377
378 if ' ' not in name and not ret.pod and ret.copyable and ret.copyable != 'default':
379 # Check whether there is a _keep() fn.
380 keep_name = f'fz_keep_{name[3:]}' if name.startswith( 'fz_') else f'pdf_keep_{name[4:]}'
381 keep_cursor = state.state_.find_function( tu, keep_name, method=True)
382 if not keep_cursor:
383 if ret.copyable:
384 if 0:
385 jlib.log( '*** Changing .copyable to False for {=name keep_name}')
386 ret.copyable = False
387 return ret
388
389 def get_or_none( self, name):
390 return self.items.get( name)
391
392
393 # Customisation information for selected wrapper classes.
394 #
395 # We use MuPDF struct names as keys.
396 #
397 classextras = ClassExtras(
398
399 fz_aa_context = ClassExtra(
400 pod='inline',
401 ),
402
403 fz_band_writer = ClassExtra(
404 class_top = '''
405 /* We use these enums to support construction via all the relevant MuPDF functions. */
406
407 enum Cm
408 {
409 MONO,
410 COLOR,
411 };
412 enum P
413 {
414 PNG,
415 PNM,
416 PAM,
417 PBM,
418 PKM,
419 PS,
420 PSD,
421 };
422 ''',
423 constructors_extra = [
424 ExtraConstructor(
425 f'({rename.class_("fz_output")}& out, Cm cm, const {rename.class_("fz_pcl_options")}& options)',
426 f'''
427 {{
428 ::fz_output* out2 = out.m_internal;
429 const ::fz_pcl_options* options2 = options.m_internal;
430 if (0) {{}}
431 else if (cm == MONO) m_internal = {rename.ll_fn('fz_new_mono_pcl_band_writer' )}( out2, options2);
432 else if (cm == COLOR) m_internal = {rename.ll_fn('fz_new_color_pcl_band_writer')}( out2, options2);
433 else throw std::runtime_error( "Unrecognised fz_band_writer_s Cm type");
434 }}
435 ''',
436 comment = f'/* Constructor using fz_new_mono_pcl_band_writer() or fz_new_color_pcl_band_writer(). */',
437 ),
438 ExtraConstructor(
439 f'({rename.class_("fz_output")}& out, P p)',
440 f'''
441 {{
442 ::fz_output* out2 = out.m_internal;
443 if (0) {{}}
444 else if (p == PNG) m_internal = {rename.ll_fn('fz_new_png_band_writer')}( out2);
445 else if (p == PNM) m_internal = {rename.ll_fn('fz_new_pnm_band_writer')}( out2);
446 else if (p == PAM) m_internal = {rename.ll_fn('fz_new_pam_band_writer')}( out2);
447 else if (p == PBM) m_internal = {rename.ll_fn('fz_new_pbm_band_writer')}( out2);
448 else if (p == PKM) m_internal = {rename.ll_fn('fz_new_pkm_band_writer')}( out2);
449 else if (p == PS) m_internal = {rename.ll_fn('fz_new_ps_band_writer' )}( out2);
450 else if (p == PSD) m_internal = {rename.ll_fn('fz_new_psd_band_writer')}( out2);
451 else throw std::runtime_error( "Unrecognised fz_band_writer_s P type");
452 }}
453 ''',
454 comment = f'/* Constructor using fz_new_p*_band_writer(). */',
455 ),
456 ExtraConstructor(
457 f'({rename.class_("fz_output")}& out, Cm cm, const {rename.class_("fz_pwg_options")}& options)',
458 f'''
459 {{
460 ::fz_output* out2 = out.m_internal;
461 const ::fz_pwg_options* options2 = &options.m_internal;
462 if (0) {{}}
463 else if (cm == MONO) m_internal = {rename.ll_fn('fz_new_mono_pwg_band_writer' )}( out2, options2);
464 else if (cm == COLOR) m_internal = {rename.ll_fn('fz_new_pwg_band_writer')}( out2, options2);
465 else throw std::runtime_error( "Unrecognised fz_band_writer_s Cm type");
466 }}
467 ''',
468 comment = f'/* Constructor using fz_new_mono_pwg_band_writer() or fz_new_pwg_band_writer(). */',
469 ),
470 ],
471 copyable = False,
472 ),
473
474 fz_bitmap = ClassExtra(
475 accessors = True,
476 ),
477
478 fz_buffer = ClassExtra(
479 constructor_raw = 'default',
480 constructors_wrappers = [
481 'fz_read_file',
482 ],
483 ),
484
485 fz_color_params = ClassExtra(
486 pod='inline',
487 constructors_extra = [
488 ExtraConstructor('()',
489 f'''
490 {{
491 this->ri = fz_default_color_params.ri;
492 this->bp = fz_default_color_params.bp;
493 this->op = fz_default_color_params.op;
494 this->opm = fz_default_color_params.opm;
495 }}
496 ''',
497 comment = '/* Equivalent to fz_default_color_params. */',
498 ),
499 ],
500 ),
501
502 fz_colorspace = ClassExtra(
503 constructors_extra = [
504 ExtraConstructor(
505 '(Fixed fixed)',
506 f'''
507 {{
508 if (0) {{}}
509 else if ( fixed == Fixed_GRAY) m_internal = {rename.ll_fn( 'fz_device_gray')}();
510 else if ( fixed == Fixed_RGB) m_internal = {rename.ll_fn( 'fz_device_rgb' )}();
511 else if ( fixed == Fixed_BGR) m_internal = {rename.ll_fn( 'fz_device_bgr' )}();
512 else if ( fixed == Fixed_CMYK) m_internal = {rename.ll_fn( 'fz_device_cmyk')}();
513 else if ( fixed == Fixed_LAB) m_internal = {rename.ll_fn( 'fz_device_lab' )}();
514 else {{
515 std::string message = "Unrecognised fixed colorspace id";
516 throw {rename.error_class("FZ_ERROR_GENERIC")}(message.c_str());
517 }}
518 {rename.ll_fn('fz_keep_colorspace')}(m_internal);
519 }}
520 ''',
521 comment = '/* Construct using one of: fz_device_gray(), fz_device_rgb(), fz_device_bgr(), fz_device_cmyk(), fz_device_lab(). */',
522 ),
523 ],
524 constructor_raw=1,
525 class_top = '''
526 /* We use this enums to support construction via all the relevant MuPDF functions. */
527 enum Fixed
528 {
529 Fixed_GRAY,
530 Fixed_RGB,
531 Fixed_BGR,
532 Fixed_CMYK,
533 Fixed_LAB,
534 };
535 ''',
536 ),
537
538 fz_compressed_buffer = ClassExtra(
539 methods_extra = [
540 ExtraMethod(
541 rename.class_('fz_buffer'),
542 'get_buffer()',
543 textwrap.dedent(f'''
544 {{
545 return {rename.class_('fz_buffer')}(
546 {rename.ll_fn('fz_keep_buffer')}(m_internal->buffer)
547 );
548 }}
549 '''),
550 '/* Returns wrapper class for fz_buffer *m_internal.buffer. */',
551 ),
552 ],
553 ),
554
555 fz_context = ClassExtra(
556 copyable = False,
557 ),
558
559 fz_cookie = ClassExtra(
560 constructors_extra = [
561 ExtraConstructor( '()',
562 '''
563 {
564 this->m_internal.abort = 0;
565 this->m_internal.progress = 0;
566 this->m_internal.progress_max = (size_t) -1;
567 this->m_internal.errors = 0;
568 this->m_internal.incomplete = 0;
569 }
570 ''',
571 comment = '/* Default constructor sets all fields to default values. */',
572 ),
573 ],
574 constructor_raw = False,
575 methods_extra = [
576 ExtraMethod(
577 'void',
578 'set_abort()',
579 '{ m_internal.abort = 1; }\n',
580 '/* Sets m_internal.abort to 1. */',
581 ),
582 ExtraMethod(
583 'void',
584 'increment_errors(int delta)',
585 '{ m_internal.errors += delta; }\n',
586 '/* Increments m_internal.errors by <delta>. */',
587 ),
588 ],
589 pod = True,
590 # Other code asynchronously writes to our fields, so we are not
591 # copyable. todo: maybe tie us to all objects to which we have
592 # been associated?
593 #
594 copyable=False,
595 ),
596
597 fz_device = ClassExtra(
598 virtual_fnptrs = dict(
599 self_ = lambda name: f'(*({rename.class_("fz_device")}2**) ({name} + 1))',
600 alloc = textwrap.dedent( f'''
601 m_internal = {rename.ll_fn("fz_new_device_of_size")}(
602 sizeof(*m_internal) + sizeof({rename.class_("fz_device")}2*)
603 );
604 *(({rename.class_("fz_device")}2**) (m_internal + 1)) = this;
605 '''),
606 ),
607 constructor_raw = True,
608 ),
609
610 fz_document = ClassExtra(
611 constructor_excludes = [
612 'fz_new_xhtml_document_from_document',
613 ],
614 constructor_prefixes = [
615 'fz_open_accelerated_document',
616 'fz_open_document',
617 ],
618 constructors_extra = [
619 ExtraConstructor( f'({rename.class_("pdf_document")}& pdfdocument)',
620 f'''
621 {{
622 m_internal = {rename.ll_fn('fz_keep_document')}(&pdfdocument.m_internal->super);
623 }}
624 ''',
625 f'/* Returns a {rename.class_("fz_document")} for pdfdocument.m_internal.super. */',
626 ),
627 ],
628 constructor_raw = 'default',
629 method_wrappers = [
630 'fz_load_outline',
631 ],
632 method_wrappers_static = [
633 'fz_new_xhtml_document_from_document',
634 ],
635 ),
636
637 # This is a little complicated. Many of the functions that we would
638 # like to wrap to form constructors, have the same set of args. C++
639 # does not support named constructors so we differentiate between
640 # constructors with identical args using enums.
641 #
642 # Also, fz_document_writer is not reference counted so the wrapping
643 # class is not copyable or assignable, so our normal approach of making
644 # static class functions that return a newly constructed instance by
645 # value, does not work.
646 #
647 # So instead we define enums that are passed to our constructors,
648 # allowing the constructor to decide which fz_ function to use to
649 # create the new fz_document_writer.
650 #
651 # There should be no commented-out constructors in the generated code
652 # marked as 'Disabled because same args as ...'.
653 #
654 fz_document_writer = ClassExtra(
655 class_top = '''
656 /* Used for constructor that wraps fz_ functions taking (const char *path, const char *options). */
657 enum PathType
658 {
659 PathType_CBZ,
660 PathType_DOCX,
661 PathType_ODT,
662 PathType_PAM_PIXMAP,
663 PathType_PBM_PIXMAP,
664 PathType_PCL,
665 PathType_PCLM,
666 PathType_PDF,
667 PathType_PDFOCR,
668 PathType_PGM_PIXMAP,
669 PathType_PKM_PIXMAP,
670 PathType_PNG_PIXMAP,
671 PathType_PNM_PIXMAP,
672 PathType_PPM_PIXMAP,
673 PathType_PS,
674 PathType_PWG,
675 PathType_SVG,
676 };
677
678 /* Used for constructor that wraps fz_ functions taking (Output& out, const char *options). */
679 enum OutputType
680 {
681 OutputType_CBZ,
682 OutputType_DOCX,
683 OutputType_ODT,
684 OutputType_PCL,
685 OutputType_PCLM,
686 OutputType_PDF,
687 OutputType_PDFOCR,
688 OutputType_PS,
689 OutputType_PWG,
690 };
691
692 /* Used for constructor that wraps fz_ functions taking (const char *format, const char *path, const char *options). */
693 enum FormatPathType
694 {
695 FormatPathType_DOCUMENT,
696 FormatPathType_TEXT,
697 };
698 ''',
699 # These excludes should match the functions called by the
700 # extra constructors defined below. This ensures that we don't
701 # generate commented-out constructors with a comment saying
702 # 'Disabled because same args as ...'.
703 constructor_excludes = [
704 'fz_new_cbz_writer',
705 'fz_new_docx_writer',
706 'fz_new_odt_writer',
707 'fz_new_pam_pixmap_writer',
708 'fz_new_pbm_pixmap_writer',
709 'fz_new_pcl_writer',
710 'fz_new_pclm_writer',
711 'fz_new_pdfocr_writer',
712 'fz_new_pdf_writer',
713 'fz_new_pgm_pixmap_writer',
714 'fz_new_pkm_pixmap_writer',
715 'fz_new_png_pixmap_writer',
716 'fz_new_pnm_pixmap_writer',
717 'fz_new_ppm_pixmap_writer',
718 'fz_new_ps_writer',
719 'fz_new_pwg_writer',
720 'fz_new_svg_writer',
721
722 'fz_new_cbz_writer_with_output',
723 'fz_new_docx_writer_with_output',
724 'fz_new_odt_writer_with_output',
725 'fz_new_pcl_writer_with_output',
726 'fz_new_pclm_writer_with_output',
727 'fz_new_pdf_writer_with_output',
728 'fz_new_pdfocr_writer_with_output',
729 'fz_new_ps_writer_with_output',
730 'fz_new_pwg_writer_with_output',
731
732 'fz_new_document_writer',
733 'fz_new_text_writer',
734
735 'fz_new_document_writer_with_output',
736 'fz_new_text_writer_with_output',
737 ],
738
739 copyable=False,
740 methods_extra = [
741 # 2022-08-26: we used to provide a custom wrapper of
742 # fz_begin_page(), but this is not longer necessary
743 # because function_wrapper_class_aware_body() knows
744 # that fz_begin_page() returns a borrowed reference.
745 #
746 ],
747 constructors_extra = [
748 ExtraConstructor(
749 '(const char *path, const char *options, PathType path_type)',
750 f'''
751 {{
752 if (0) {{}}
753 else if (path_type == PathType_CBZ) m_internal = {rename.ll_fn( 'fz_new_cbz_writer')}(path, options);
754 else if (path_type == PathType_DOCX) m_internal = {rename.ll_fn( 'fz_new_docx_writer')}(path, options);
755 else if (path_type == PathType_ODT) m_internal = {rename.ll_fn( 'fz_new_odt_writer')}(path, options);
756 else if (path_type == PathType_PAM_PIXMAP) m_internal = {rename.ll_fn( 'fz_new_pam_pixmap_writer')}(path, options);
757 else if (path_type == PathType_PBM_PIXMAP) m_internal = {rename.ll_fn( 'fz_new_pbm_pixmap_writer')}(path, options);
758 else if (path_type == PathType_PCL) m_internal = {rename.ll_fn( 'fz_new_pcl_writer')}(path, options);
759 else if (path_type == PathType_PCLM) m_internal = {rename.ll_fn( 'fz_new_pclm_writer')}(path, options);
760 else if (path_type == PathType_PDF) m_internal = {rename.ll_fn( 'fz_new_pdf_writer')}(path, options);
761 else if (path_type == PathType_PDFOCR) m_internal = {rename.ll_fn( 'fz_new_pdfocr_writer')}(path, options);
762 else if (path_type == PathType_PGM_PIXMAP) m_internal = {rename.ll_fn( 'fz_new_pgm_pixmap_writer')}(path, options);
763 else if (path_type == PathType_PKM_PIXMAP) m_internal = {rename.ll_fn( 'fz_new_pkm_pixmap_writer')}(path, options);
764 else if (path_type == PathType_PNG_PIXMAP) m_internal = {rename.ll_fn( 'fz_new_png_pixmap_writer')}(path, options);
765 else if (path_type == PathType_PNM_PIXMAP) m_internal = {rename.ll_fn( 'fz_new_pnm_pixmap_writer')}(path, options);
766 else if (path_type == PathType_PPM_PIXMAP) m_internal = {rename.ll_fn( 'fz_new_ppm_pixmap_writer')}(path, options);
767 else if (path_type == PathType_PS) m_internal = {rename.ll_fn( 'fz_new_ps_writer')}(path, options);
768 else if (path_type == PathType_PWG) m_internal = {rename.ll_fn( 'fz_new_pwg_writer')}(path, options);
769 else if (path_type == PathType_SVG) m_internal = {rename.ll_fn( 'fz_new_svg_writer')}(path, options);
770 else throw {rename.error_class('FZ_ERROR_ABORT')}( "Unrecognised Type value");
771 }}
772 ''',
773 comment = textwrap.dedent('''
774 /* Constructor using one of:
775 fz_new_cbz_writer()
776 fz_new_docx_writer()
777 fz_new_odt_writer()
778 fz_new_pam_pixmap_writer()
779 fz_new_pbm_pixmap_writer()
780 fz_new_pcl_writer()
781 fz_new_pclm_writer()
782 fz_new_pdf_writer()
783 fz_new_pdfocr_writer()
784 fz_new_pgm_pixmap_writer()
785 fz_new_pkm_pixmap_writer()
786 fz_new_png_pixmap_writer()
787 fz_new_pnm_pixmap_writer()
788 fz_new_ppm_pixmap_writer()
789 fz_new_ps_writer()
790 fz_new_pwg_writer()
791 fz_new_svg_writer()
792 */'''),
793 ),
794 ExtraConstructor(
795 f'({rename.class_("fz_output")}& out, const char *options, OutputType output_type)',
796 f'''
797 {{
798 /* All fz_new_*_writer_with_output() functions take
799 ownership of the fz_output, even if they throw an
800 exception. So we need to set out.m_internal to null
801 here so its destructor does nothing. */
802 ::fz_output* out2 = out.m_internal;
803 out.m_internal = NULL;
804 if (0) {{}}
805 else if (output_type == OutputType_CBZ) m_internal = {rename.ll_fn( 'fz_new_cbz_writer_with_output')}(out2, options);
806 else if (output_type == OutputType_DOCX) m_internal = {rename.ll_fn( 'fz_new_docx_writer_with_output')}(out2, options);
807 else if (output_type == OutputType_ODT) m_internal = {rename.ll_fn( 'fz_new_odt_writer_with_output')}(out2, options);
808 else if (output_type == OutputType_PCL) m_internal = {rename.ll_fn( 'fz_new_pcl_writer_with_output')}(out2, options);
809 else if (output_type == OutputType_PCLM) m_internal = {rename.ll_fn( 'fz_new_pclm_writer_with_output')}(out2, options);
810 else if (output_type == OutputType_PDF) m_internal = {rename.ll_fn( 'fz_new_pdf_writer_with_output')}(out2, options);
811 else if (output_type == OutputType_PDFOCR) m_internal = {rename.ll_fn( 'fz_new_pdfocr_writer_with_output')}(out2, options);
812 else if (output_type == OutputType_PS) m_internal = {rename.ll_fn( 'fz_new_ps_writer_with_output')}(out2, options);
813 else if (output_type == OutputType_PWG) m_internal = {rename.ll_fn( 'fz_new_pwg_writer_with_output')}(out2, options);
814 else
815 {{
816 /* Ensure that out2 is dropped before we return. */
817 {rename.ll_fn( 'fz_drop_output')}(out2);
818 throw {rename.error_class('FZ_ERROR_ABORT')}( "Unrecognised OutputType value");
819 }}
820 }}
821 ''',
822 comment = textwrap.dedent('''
823 /* Constructor using one of:
824 fz_new_cbz_writer_with_output()
825 fz_new_docx_writer_with_output()
826 fz_new_odt_writer_with_output()
827 fz_new_pcl_writer_with_output()
828 fz_new_pclm_writer_with_output()
829 fz_new_pdf_writer_with_output()
830 fz_new_pdfocr_writer_with_output()
831 fz_new_ps_writer_with_output()
832 fz_new_pwg_writer_with_output()
833
834 This constructor takes ownership of <out> -
835 out.m_internal is set to NULL after this constructor
836 returns so <out> must not be used again.
837 */
838 '''),
839 ),
840 ExtraConstructor(
841 '(const char *format, const char *path, const char *options, FormatPathType format_path_type)',
842 f'''
843 {{
844 if (0) {{}}
845 else if (format_path_type == FormatPathType_DOCUMENT) m_internal = {rename.ll_fn( 'fz_new_document_writer')}(format, path, options);
846 else if (format_path_type == FormatPathType_TEXT) m_internal = {rename.ll_fn( 'fz_new_text_writer')}(format, path, options);
847 else throw {rename.error_class('FZ_ERROR_ABORT')}( "Unrecognised OutputType value");
848 }}
849 ''',
850 comment = textwrap.dedent('''
851 /* Constructor using one of:
852 fz_new_document_writer()
853 fz_new_text_writer()
854 */'''),
855 ),
856 ExtraConstructor(
857 f'({rename.class_("fz_output")}& out, const char *format, const char *options)',
858 f'''
859 {{
860 /* Need to transfer ownership of <out>. */
861 ::fz_output* out2 = out.m_internal;
862 out.m_internal = NULL;
863 m_internal = {rename.ll_fn( 'fz_new_document_writer_with_output')}(out2, format, options);
864 }}
865 ''',
866 comment = textwrap.dedent('''
867 /* Constructor using fz_new_document_writer_with_output().
868
869 This constructor takes ownership of <out> -
870 out.m_internal is set to NULL after this constructor
871 returns so <out> must not be used again.
872 */'''),
873 ),
874 ExtraConstructor(
875 f'(const char *format, {rename.class_("fz_output")}& out, const char *options)',
876 f'''
877 {{
878 /* Need to transfer ownership of <out>. */
879 ::fz_output* out2 = out.m_internal;
880 out.m_internal = NULL;
881 m_internal = {rename.ll_fn( 'fz_new_text_writer_with_output')}(format, out2, options);
882 }}
883 ''',
884 comment = textwrap.dedent('''
885 /* Constructor using fz_new_text_writer_with_output().
886
887 This constructor takes ownership of <out> -
888 out.m_internal is set to NULL after this constructor
889 returns so <out> must not be used again.
890 */'''),
891 ),
892 ],
893
894 ),
895
896 fz_draw_options = ClassExtra(
897 constructors_wrappers = [
898 'fz_parse_draw_options',
899 ],
900 copyable=False,
901 pod='inline',
902 ),
903
904 fz_halftone = ClassExtra(
905 constructor_raw = 'default',
906 ),
907
908 fz_image = ClassExtra(
909 accessors=True,
910 ),
911
912 fz_install_load_system_font_funcs_args = ClassExtra(
913 pod = True,
914 virtual_fnptrs = dict(
915 alloc = textwrap.dedent( f'''
916 /*
917 There can only be one active instance of the wrapper
918 class so we simply keep a pointer to it in a global
919 variable.
920 */
921 fz_install_load_system_font_funcs2_state = this;
922 '''),
923 self_ = lambda: f'({rename.class_("fz_install_load_system_font_funcs_args")}2*) fz_install_load_system_font_funcs2_state',
924 self_n = None,
925 ),
926 ),
927
928 fz_irect = ClassExtra(
929 constructor_prefixes = [
930 'fz_irect_from_rect',
931 'fz_make_irect',
932 ],
933 pod='inline',
934 constructor_raw = True,
935 ),
936
937 fz_link = ClassExtra(
938 constructors_extra = [
939 ExtraConstructor( f'({rename.class_("fz_rect")}& rect, const char *uri)',
940 f'''
941 {{
942 m_internal = {rename.ll_fn('fz_new_link_of_size')}( sizeof(fz_link), *rect.internal(), uri);
943 }}
944 ''',
945 '/* Construct by calling fz_new_link_of_size() with size=sizeof(fz_link). */',
946 )
947 ],
948 accessors = True,
949 iterator_next = ('', ''),
950 constructor_raw = 'default',
951 copyable = True,
952 ),
953
954 fz_location = ClassExtra(
955 constructor_prefixes = [
956 'fz_make_location',
957 ],
958 pod='inline',
959 constructor_raw = True,
960 ),
961
962 fz_matrix = ClassExtra(
963 constructor_prefixes = [
964 'fz_make_matrix',
965 ],
966 method_wrappers_static = [
967 'fz_concat',
968 'fz_scale',
969 'fz_shear',
970 'fz_rotate',
971 'fz_translate',
972 'fz_transform_page',
973 ],
974 constructors_extra = [
975 ExtraConstructor( '()',
976 '''
977 : a(1), b(0), c(0), d(1), e(0), f(0)
978 {
979 }
980 ''',
981 comment = '/* Constructs identity matrix (like fz_identity). */'),
982 ],
983 pod='inline',
984 constructor_raw = True,
985 ),
986
987 fz_md5 = ClassExtra(
988 pod = True,
989 constructors_extra = [
990 ExtraConstructor(
991 '()',
992 f'''
993 {{
994 {rename.ll_fn( 'fz_md5_init')}( &m_internal);
995 }}
996 ''',
997 '/* Default constructor calls md5_init(). */',
998 )
999 ],
1000 ),
1001
1002 fz_outline = ClassExtra(
1003 # We add various methods to give depth-first iteration of outlines.
1004 #
1005 constructor_prefixes = [
1006 'fz_load_outline',
1007 ],
1008 accessors=True,
1009 ),
1010
1011 fz_outline_item = ClassExtra(
1012 class_top = f'''
1013 FZ_FUNCTION bool valid() const;
1014 FZ_FUNCTION const std::string& title() const; /* Will throw if valid() is not true. */
1015 FZ_FUNCTION const std::string& uri() const; /* Will throw if valid() is not true. */
1016 FZ_FUNCTION int is_open() const; /* Will throw if valid() is not true. */
1017 ''',
1018 class_bottom = f'''
1019 private:
1020 bool m_valid;
1021 std::string m_title;
1022 std::string m_uri;
1023 int m_is_open;
1024 ''',
1025 constructors_extra = [
1026 ],
1027 constructor_raw = 'declaration_only',
1028 copyable = 'default',
1029 pod = 'none',
1030 extra_cpp = f'''
1031 FZ_FUNCTION {rename.class_("fz_outline_item")}::{rename.class_("fz_outline_item")}(const ::fz_outline_item* item)
1032 {{
1033 if (item)
1034 {{
1035 m_valid = true;
1036 m_title = item->title;
1037 m_uri = item->uri;
1038 m_is_open = item->is_open;
1039 }}
1040 else
1041 {{
1042 m_valid = false;
1043 }}
1044 }}
1045 FZ_FUNCTION bool {rename.class_("fz_outline_item")}::valid() const
1046 {{
1047 return m_valid;
1048 }}
1049 FZ_FUNCTION const std::string& {rename.class_("fz_outline_item")}::title() const
1050 {{
1051 if (!m_valid) throw {rename.error_class("FZ_ERROR_GENERIC")}("fz_outline_item is invalid");
1052 return m_title;
1053 }}
1054 FZ_FUNCTION const std::string& {rename.class_("fz_outline_item")}::uri() const
1055 {{
1056 if (!m_valid) throw {rename.error_class("FZ_ERROR_GENERIC")}("fz_outline_item is invalid");
1057 return m_uri;
1058 }}
1059 FZ_FUNCTION int {rename.class_("fz_outline_item")}::is_open() const
1060 {{
1061 if (!m_valid) throw {rename.error_class("FZ_ERROR_GENERIC")}("fz_outline_item is invalid");
1062 return m_is_open;
1063 }}
1064 ''',
1065 ),
1066
1067 fz_outline_iterator = ClassExtra(
1068 copyable = False,
1069 methods_extra = [
1070 ExtraMethod(
1071 'int',
1072 f'{rename.method("fz_outline_iterator", "fz_outline_iterator_insert")}({rename.class_("fz_outline_item")}& item)',
1073 f'''
1074 {{
1075 /* Create a temporary fz_outline_item. */
1076 ::fz_outline_item item2;
1077 item2.title = (char*) item.title().c_str();
1078 item2.uri = (char*) item.uri().c_str();
1079 item2.is_open = item.is_open();
1080 return {rename.ll_fn("fz_outline_iterator_insert")}(m_internal, &item2);
1081 }}
1082 ''',
1083 comment = '/* Custom wrapper for fz_outline_iterator_insert(). */',
1084 ),
1085 ExtraMethod(
1086 'void',
1087 f'{rename.method("fz_outline_iterator", "fz_outline_iterator_update")}({rename.class_("fz_outline_item")}& item)',
1088 f'''
1089 {{
1090 /* Create a temporary fz_outline_item. */
1091 ::fz_outline_item item2;
1092 item2.title = (char*) item.title().c_str();
1093 item2.uri = (char*) item.uri().c_str();
1094 item2.is_open = item.is_open();
1095 return {rename.ll_fn("fz_outline_iterator_update")}(m_internal, &item2);
1096 }}
1097 ''',
1098 comment = '/* Custom wrapper for fz_outline_iterator_update(). */',
1099 ),
1100 ],
1101 ),
1102
1103 fz_output = ClassExtra(
1104 virtual_fnptrs = dict(
1105 self_ = lambda name: f'({rename.class_("fz_output")}2*) {name}',
1106 alloc = f'm_internal = {rename.ll_fn("fz_new_output")}(0 /*bufsize*/, this /*state*/, nullptr /*write*/, nullptr /*close*/, nullptr /*drop*/);\n',
1107 ),
1108 constructor_raw = 'default',
1109 constructor_excludes = [
1110 # These all have the same prototype, so are used by
1111 # constructors_extra below.
1112 'fz_new_asciihex_output',
1113 'fz_new_ascii85_output',
1114 'fz_new_rle_output',
1115 ],
1116 constructors_extra = [
1117 ExtraConstructor( '(Fixed out)',
1118 f'''
1119 {{
1120 if (0) {{}}
1121 else if (out == Fixed_STDOUT) {{
1122 m_internal = {rename.ll_fn('fz_stdout')}();
1123 }}
1124 else if (out == Fixed_STDERR) {{
1125 m_internal = {rename.ll_fn('fz_stderr')}();
1126 }}
1127 else {{
1128 throw {rename.error_class('FZ_ERROR_ABORT')}("Unrecognised Fixed value");
1129 }}
1130 }}
1131 ''',
1132 '/* Uses fz_stdout() or fz_stderr(). */',
1133 # Note that it's ok to call fz_drop_output() on fz_stdout and fz_stderr.
1134 ),
1135 ExtraConstructor(
1136 f'(const {rename.class_("fz_output")}& chain, Filter filter)',
1137 f'''
1138 {{
1139 if (0) {{}}
1140 else if (filter == Filter_HEX) {{
1141 m_internal = {rename.ll_fn('fz_new_asciihex_output')}(chain.m_internal);
1142 }}
1143 else if (filter == Filter_85) {{
1144 m_internal = {rename.ll_fn('fz_new_ascii85_output')}(chain.m_internal);
1145 }}
1146 else if (filter == Filter_RLE) {{
1147 m_internal = {rename.ll_fn('fz_new_rle_output')}(chain.m_internal);
1148 }}
1149 else {{
1150 throw {rename.error_class('FZ_ERROR_ABORT')}("Unrecognised Filter value");
1151 }}
1152 }}
1153 ''',
1154 comment = '/* Calls one of: fz_new_asciihex_output(), fz_new_ascii85_output(), fz_new_rle_output(). */',
1155 ),
1156 ],
1157 class_top = '''
1158 enum Fixed
1159 {
1160 Fixed_STDOUT=1,
1161 Fixed_STDERR=2,
1162 };
1163 enum Filter
1164 {
1165 Filter_HEX,
1166 Filter_85,
1167 Filter_RLE,
1168 };
1169 '''
1170 ,
1171 copyable=False, # No fz_keep_output() fn?
1172 ),
1173
1174 fz_page = ClassExtra(
1175 constructor_prefixes = [
1176 'fz_load_page',
1177 'fz_load_chapter_page',
1178 ],
1179 constructors_extra = [
1180 ExtraConstructor( f'({rename.class_("pdf_page")}& pdfpage)',
1181 f'''
1182 {{
1183 m_internal = {rename.ll_fn('fz_keep_page')}(&pdfpage.m_internal->super);
1184 }}
1185 ''',
1186 f'/* Return {rename.class_("fz_page")} for pdfpage.m_internal.super. */',
1187 ),
1188 ],
1189 methods_extra = [
1190 ExtraMethod(
1191 f'{rename.class_("fz_document")}',
1192 'doc()',
1193 f'''
1194 {{
1195 return {rename.class_("fz_document")}( {rename.ll_fn('fz_keep_document')}( m_internal->doc));
1196 }}
1197 ''',
1198 f'/* Returns wrapper for .doc member. */',
1199 ),
1200 ],
1201 constructor_raw = True,
1202 ),
1203
1204 fz_path_walker = ClassExtra(
1205 constructor_raw = 'default',
1206 virtual_fnptrs = dict(
1207 self_ = lambda name: f'*({rename.class_("fz_path_walker")}2**) ((fz_path_walker*) {name} + 1)',
1208 alloc = textwrap.dedent( f'''
1209 m_internal = (::fz_path_walker*) {rename.ll_fn("fz_calloc")}(
1210 1,
1211 sizeof(*m_internal) + sizeof({rename.class_("fz_path_walker")}2*)
1212 );
1213 *({rename.class_("fz_path_walker")}2**) (m_internal + 1) = this;
1214 '''),
1215 free = f'{rename.ll_fn("fz_free")}(m_internal);\n',
1216 comment = textwrap.dedent(f'''
1217 /*
1218 We require that the `void* arg` passed to callbacks
1219 is the original `fz_path_walker*`. So, for example,
1220 class-aware wrapper mupdf::fz_walk_path() should be
1221 called like:
1222
1223 mupdf.FzPath path = ...;
1224 struct Walker : mupdf.FzPathWalker2 {...};
1225 Walker walker(...);
1226 mupdf::fz_walk_path(path, walker, walker.m_internal);
1227 */
1228 ''')
1229 ),
1230 ),
1231
1232 fz_pcl_options = ClassExtra(
1233 constructors_wrappers = [
1234 'fz_parse_pcl_options',
1235 ],
1236 copyable=False,
1237 ),
1238
1239 fz_pclm_options = ClassExtra(
1240 constructor_prefixes = [
1241 'fz_parse_pclm_options',
1242 ],
1243 copyable=False,
1244 constructors_extra = [
1245 ExtraConstructor( '(const char *args)',
1246 f'''
1247 {{
1248 {rename.ll_fn('fz_parse_pclm_options')}(m_internal, args);
1249 }}
1250 ''',
1251 '/* Construct using fz_parse_pclm_options(). */',
1252 )
1253 ],
1254 ),
1255
1256 fz_pdfocr_options = ClassExtra(
1257 pod = 'inline',
1258 methods_extra = [
1259 ExtraMethod(
1260 'void',
1261 'language_set2(const char* language)',
1262 f'''
1263 {{
1264 fz_strlcpy(this->language, language, sizeof(this->language));
1265 }}
1266 ''',
1267 '/* Copies <language> into this->language, truncating if necessary. */',
1268 ),
1269 ExtraMethod(
1270 'void',
1271 'datadir_set2(const char* datadir)',
1272 f'''
1273 {{
1274 fz_strlcpy(this->datadir, datadir, sizeof(this->datadir));
1275 }}
1276 ''',
1277 '/* Copies <datadir> into this->datadir, truncating if necessary. */',
1278 ),
1279 ],
1280 ),
1281
1282 fz_pixmap = ClassExtra(
1283 constructor_raw = True,
1284 accessors = True,
1285 ),
1286
1287 fz_point = ClassExtra(
1288 method_wrappers_static = [
1289 'fz_transform_point',
1290 'fz_transform_point_xy',
1291 'fz_transform_vector',
1292
1293 ],
1294 constructors_extra = [
1295 ExtraConstructor( '(float x, float y)',
1296 '''
1297 : x(x), y(y)
1298 {
1299 }
1300 ''',
1301 comment = '/* Construct using specified values. */',
1302 ),
1303 ],
1304 methods_extra = [
1305 ExtraMethod(
1306 f'{rename.class_("fz_point")}&',
1307 f'transform(const {rename.class_("fz_matrix")}& m)',
1308 '''
1309 {
1310 double old_x = x;
1311 x = old_x * m.a + y * m.c + m.e;
1312 y = old_x * m.b + y * m.d + m.f;
1313 return *this;
1314 }
1315 ''',
1316 comment = '/* Post-multiply *this by <m> and return *this. */',
1317 ),
1318 ],
1319 pod='inline',
1320 constructor_raw = True,
1321 ),
1322
1323 fz_pwg_options = ClassExtra(
1324 pod=True,
1325 ),
1326
1327 fz_quad = ClassExtra(
1328 constructor_prefixes = [
1329 'fz_transform_quad',
1330 'fz_quad_from_rect'
1331 ],
1332 pod='inline',
1333 constructor_raw = True,
1334 ),
1335
1336 fz_rect = ClassExtra(
1337 constructor_prefixes = [
1338 'fz_transform_rect',
1339 'fz_bound_display_list',
1340 'fz_rect_from_irect',
1341 'fz_rect_from_quad',
1342 ],
1343 method_wrappers_static = [
1344 'fz_intersect_rect',
1345 'fz_union_rect',
1346 ],
1347 constructors_extra = [
1348 ExtraConstructor(
1349 '(double x0, double y0, double x1, double y1)',
1350 '''
1351 :
1352 x0(x0),
1353 x1(x1),
1354 y0(y0),
1355 y1(y1)
1356 {
1357 }
1358 ''',
1359 comment = '/* Construct from specified values. */',
1360 ),
1361 ExtraConstructor(
1362 f'(const {rename.class_("fz_rect")}& rhs)',
1363 '''
1364 :
1365 x0(rhs.x0),
1366 y0(rhs.y0),
1367 x1(rhs.x1),
1368 y1(rhs.y1)
1369 {
1370 }
1371 ''',
1372 comment = '/* Copy constructor using plain copy. */',
1373 ),
1374 ExtraConstructor( '(Fixed fixed)',
1375 f'''
1376 {{
1377 if (0) {{}}
1378 else if (fixed == Fixed_UNIT) *this->internal() = {rename.c_fn('fz_unit_rect')};
1379 else if (fixed == Fixed_EMPTY) *this->internal() = {rename.c_fn('fz_empty_rect')};
1380 else if (fixed == Fixed_INFINITE) *this->internal() = {rename.c_fn('fz_infinite_rect')};
1381 else throw {rename.error_class('FZ_ERROR_ABORT')}( "Unrecognised From value");
1382 }}
1383 ''',
1384 comment = '/* Construct from fz_unit_rect, fz_empty_rect or fz_infinite_rect. */',
1385 ),
1386 ],
1387 methods_extra = [
1388 ExtraMethod(
1389 'void',
1390 f'transform(const {rename.class_("fz_matrix")}& m)',
1391 f'''
1392 {{
1393 *(::fz_rect*) &this->x0 = {rename.c_fn('fz_transform_rect')}(*(::fz_rect*) &this->x0, *(::fz_matrix*) &m.a);
1394 }}
1395 ''',
1396 comment = '/* Transforms *this using fz_transform_rect() with <m>. */',
1397 ),
1398 ExtraMethod( 'bool', 'contains(double x, double y)',
1399 '''
1400 {
1401 if (is_empty()) {
1402 return false;
1403 }
1404 return true
1405 && x >= x0
1406 && x < x1
1407 && y >= y0
1408 && y < y1
1409 ;
1410 }
1411 ''',
1412 comment = '/* Convenience method using fz_contains_rect(). */',
1413 ),
1414 ExtraMethod( 'bool', f'contains({rename.class_("fz_rect")}& rhs)',
1415 f'''
1416 {{
1417 return {rename.c_fn('fz_contains_rect')}(*(::fz_rect*) &x0, *(::fz_rect*) &rhs.x0);
1418 }}
1419 ''',
1420 comment = '/* Uses fz_contains_rect(*this, rhs). */',
1421 ),
1422 ExtraMethod( 'bool', 'is_empty()',
1423 f'''
1424 {{
1425 return {rename.c_fn('fz_is_empty_rect')}(*(::fz_rect*) &x0);
1426 }}
1427 ''',
1428 comment = '/* Uses fz_is_empty_rect(). */',
1429 ),
1430 ExtraMethod( 'void', f'union_({rename.class_("fz_rect")}& rhs)',
1431 f'''
1432 {{
1433 *(::fz_rect*) &x0 = {rename.c_fn('fz_union_rect')}(*(::fz_rect*) &x0, *(::fz_rect*) &rhs.x0);
1434 }}
1435 ''',
1436 comment = '/* Updates *this using fz_union_rect(). */',
1437 ),
1438 ],
1439 pod='inline',
1440 constructor_raw = True,
1441 copyable = True,
1442 class_top = '''
1443 enum Fixed
1444 {
1445 Fixed_UNIT,
1446 Fixed_EMPTY,
1447 Fixed_INFINITE,
1448 };
1449 ''',
1450 ),
1451
1452 fz_separations = ClassExtra(
1453 constructor_raw = 'default',
1454 opaque = True,
1455 ),
1456
1457 fz_shade = ClassExtra(
1458 methods_extra = [
1459 ExtraMethod( 'void',
1460 f'{rename.method( "fz_shade", "fz_paint_shade_no_cache")}('
1461 + f' const {rename.class_("fz_colorspace")}& override_cs'
1462 + f', {rename.class_("fz_matrix")}& ctm'
1463 + f', const {rename.class_("fz_pixmap")}& dest'
1464 + f', {rename.class_("fz_color_params")}& color_params'
1465 + f', {rename.class_("fz_irect")}& bbox'
1466 + f', const {rename.class_("fz_overprint")}& eop'
1467 + f')'
1468 ,
1469 f'''
1470 {{
1471 return {rename.ll_fn('fz_paint_shade')}(
1472 this->m_internal,
1473 override_cs.m_internal,
1474 *(::fz_matrix*) &ctm.a,
1475 dest.m_internal,
1476 *(::fz_color_params*) &color_params.ri,
1477 *(::fz_irect*) &bbox.x0,
1478 eop.m_internal,
1479 NULL /*cache*/
1480 );
1481 }}
1482 ''',
1483 comment = f'/* Extra wrapper for fz_paint_shade(), passing cache=NULL. */',
1484 ),
1485 ],
1486 ),
1487
1488 fz_shade_color_cache = ClassExtra(
1489 ),
1490
1491 # Our wrappers of the fz_stext_* structs all have a default copy
1492 # constructor - there are no fz_keep_stext_*() functions.
1493 #
1494 # We define explicit accessors for fz_stext_block::u.i.* because SWIG
1495 # does not handle nested unions.
1496 #
1497 fz_stext_block = ClassExtra(
1498 iterator_next = ('u.t.first_line', 'u.t.last_line'),
1499 copyable='default',
1500 methods_extra = [
1501 ExtraMethod( f'{rename.class_("fz_matrix")}', 'i_transform()',
1502 f'''
1503 {{
1504 if (m_internal->type != FZ_STEXT_BLOCK_IMAGE) {{
1505 throw std::runtime_error("Not an image");
1506 }}
1507 return m_internal->u.i.transform;
1508 }}
1509 ''',
1510 comment=f'/* Returns m_internal.u.i.transform if m_internal->type is FZ_STEXT_BLOCK_IMAGE, else throws. */',
1511 ),
1512 ExtraMethod( f'{rename.class_("fz_image")}', 'i_image()',
1513 f'''
1514 {{
1515 if (m_internal->type != FZ_STEXT_BLOCK_IMAGE) {{
1516 throw std::runtime_error("Not an image");
1517 }}
1518 return {rename.class_("fz_image")}({rename.ll_fn('fz_keep_image')}(m_internal->u.i.image));
1519 }}
1520 ''',
1521 comment=f'/* Returns m_internal.u.i.image if m_internal->type is FZ_STEXT_BLOCK_IMAGE, else throws. */',
1522 ),
1523 ],
1524 ),
1525
1526 fz_stext_char = ClassExtra(
1527 copyable='default',
1528 ),
1529
1530 fz_stext_line = ClassExtra(
1531 iterator_next = ('first_char', 'last_char'),
1532 copyable='default',
1533 constructor_raw=True,
1534 ),
1535
1536 fz_stext_options = ClassExtra(
1537 constructors_extra = [
1538 ExtraConstructor( '(int flags, float scale=1.0)',
1539 '''
1540 :
1541 flags(flags),
1542 scale(scale)
1543 {
1544 assert(!(flags & FZ_STEXT_CLIP_RECT));
1545 }
1546 ''',
1547 comment = '/* Construct with .flags, .scale but no clip. */',
1548 ),
1549 ExtraConstructor( '(int flags, fz_rect clip, float scale=1.0)',
1550 '''
1551 :
1552 flags(flags | FZ_STEXT_CLIP_RECT),
1553 scale(scale),
1554 clip(clip)
1555 {
1556 }
1557 ''',
1558 comment =
1559 '/* Construct with .flags, .scale and .clip; FZ_STEXT_CLIP_RECT\n'
1560 'is automatically set in .flags. */'
1561 ,
1562 ),
1563 ],
1564 pod='inline',
1565 ),
1566
1567 fz_stext_page = ClassExtra(
1568 methods_extra = [
1569 ExtraMethod(
1570 'std::string',
1571 f'{rename.method( "fz_stext_page", "fz_copy_selection")}('
1572 + f'{rename.class_("fz_point")}& a'
1573 + f', {rename.class_("fz_point")}& b'
1574 + f', int crlf'
1575 + f')',
1576 f'''
1577 {{
1578 char* text = {rename.ll_fn('fz_copy_selection')}(m_internal, *(::fz_point *) &a.x, *(::fz_point *) &b.x, crlf);
1579 std::string ret(text);
1580 {rename.ll_fn('fz_free')}(text);
1581 return ret;
1582 }}
1583 ''',
1584 comment = f'/* Wrapper for fz_copy_selection() that returns std::string. */',
1585 ),
1586 ExtraMethod(
1587 'std::string',
1588 f'{rename.method( "fz_stext_page", "fz_copy_rectangle")}({rename.class_("fz_rect")}& area, int crlf)',
1589 f'''
1590 {{
1591 char* text = {rename.ll_fn('fz_copy_rectangle')}(m_internal, *(::fz_rect*) &area.x0, crlf);
1592 std::string ret(text);
1593 {rename.ll_fn('fz_free')}(text);
1594 return ret;
1595 }}
1596 ''',
1597 comment = f'/* Wrapper for fz_copy_rectangle() that returns a std::string. */',
1598 ),
1599 ExtraMethod(
1600 f'std::vector<{rename.class_("fz_quad")}>',
1601 f'{rename.method( "fz_stext_page", "search_stext_page")}(const char* needle, int *hit_mark, int max_quads)',
1602 f'''
1603 {{
1604 std::vector<{rename.class_("fz_quad")}> ret(max_quads);
1605 int n = {rename.ll_fn('fz_search_stext_page')}(m_internal, needle, hit_mark, ret[0].internal(), max_quads);
1606 ret.resize(n);
1607 return ret;
1608 }}
1609 ''',
1610 '/* Wrapper for fz_search_stext_page() that returns std::vector of Quads. */',
1611 )
1612 ],
1613 iterator_next = ('first_block', 'last_block'),
1614 copyable=False,
1615 constructor_raw = True,
1616 ),
1617
1618 fz_text_span = ClassExtra(
1619 copyable=False,
1620 methods_extra = [
1621 # We provide class-aware accessors where possible. (Some
1622 # types' wrapper classes are not copyable so we can't do
1623 # this for all data).
1624 ExtraMethod(
1625 f'{rename.class_("fz_font")}',
1626 f'font()',
1627 f'''
1628 {{
1629 return {rename.class_("fz_font")}( ll_fz_keep_font( m_internal->font));
1630 }}
1631 ''',
1632 f'/* Gives class-aware access to m_internal->font. */',
1633 ),
1634 ExtraMethod(
1635 f'{rename.class_("fz_matrix")}',
1636 f'trm()',
1637 f'''
1638 {{
1639 return {rename.class_("fz_matrix")}( m_internal->trm);
1640 }}
1641 ''',
1642 f'/* Gives class-aware access to m_internal->trm. */',
1643 ),
1644 ExtraMethod(
1645 f'fz_text_item&',
1646 f'items( int i)',
1647 f'''
1648 {{
1649 assert( i < m_internal->len);
1650 return m_internal->items[i];
1651 }}
1652 ''',
1653 '''
1654 /* Gives access to m_internal->items[i].
1655 Returned reference is only valid as long as `this`.
1656 Provided mainly for use by SWIG bindings.
1657 */
1658 ''',
1659 ),
1660 ],
1661 ),
1662
1663 fz_stream = ClassExtra(
1664 constructor_prefixes = [
1665 'fz_open_file',
1666 'fz_open_memory',
1667 ],
1668 constructors_extra = [
1669 ExtraConstructor( '(const std::string& filename)',
1670 f'''
1671 : m_internal({rename.ll_fn('fz_open_file')}(filename.c_str()))
1672 {{
1673 }}
1674 ''',
1675 comment = '/* Construct using fz_open_file(). */',
1676 )
1677 ],
1678 ),
1679
1680 fz_story_element_position = ClassExtra(
1681 pod='inline',
1682 ),
1683
1684 fz_transition = ClassExtra(
1685 pod='inline',
1686 constructor_raw = True,
1687 ),
1688
1689 pdf_annot = ClassExtra(
1690 constructor_raw = 'default',
1691 ),
1692
1693 pdf_clean_options = ClassExtra(
1694 constructors_extra = [
1695 ExtraConstructor( '()',
1696 f'''
1697 {{
1698 /* Use memcpy() otherwise we get 'invalid array assignment' errors. */
1699 memcpy(&this->internal()->write, &pdf_default_write_options, sizeof(this->internal()->write));
1700 memset(&this->internal()->image, 0, sizeof(this->internal()->image));
1701 }}
1702 ''',
1703 comment = '/* Default constructor, makes copy of pdf_default_write_options. */'
1704 ),
1705 ExtraConstructor(
1706 f'(const {rename.class_("pdf_clean_options")}& rhs)',
1707 f'''
1708 {{
1709 *this = rhs;
1710 }}
1711 ''',
1712 comment = '/* Copy constructor using raw memcopy(). */'
1713 ),
1714 ],
1715 methods_extra = [
1716 ExtraMethod(
1717 f'{rename.class_("pdf_clean_options")}&',
1718 f'operator=(const {rename.class_("pdf_clean_options")}& rhs)',
1719 f'''
1720 {{
1721 memcpy(this->internal(), rhs.internal(), sizeof(*this->internal()));
1722 return *this;
1723 }}
1724 ''',
1725 comment = '/* Assignment using plain memcpy(). */',
1726 ),
1727 ExtraMethod(
1728 f'void',
1729 f'write_opwd_utf8_set(const std::string& text)',
1730 f'''
1731 {{
1732 size_t len = std::min(text.size(), sizeof(write.opwd_utf8) - 1);
1733 memcpy(write.opwd_utf8, text.c_str(), len);
1734 write.opwd_utf8[len] = 0;
1735 }}
1736 ''',
1737 '/* Copies <text> into write.opwd_utf8[]. */',
1738 ),
1739 ExtraMethod(
1740 f'void',
1741 f'write_upwd_utf8_set(const std::string& text)',
1742 f'''
1743 {{
1744 size_t len = std::min(text.size(), sizeof(write.upwd_utf8) - 1);
1745 memcpy(write.upwd_utf8, text.c_str(), len);
1746 write.upwd_utf8[len] = 0;
1747 }}
1748 ''',
1749 '/* Copies <text> into upwd_utf8[]. */',
1750 ),
1751 ],
1752 pod = 'inline',
1753 copyable = 'default',
1754 ),
1755
1756 pdf_document = ClassExtra(
1757 constructor_prefixes = [
1758 'pdf_open_document',
1759 'pdf_create_document',
1760 'pdf_document_from_fz_document',
1761 ],
1762 methods_extra = [
1763 ExtraMethod(
1764 f'{rename.class_("fz_document")}',
1765 'super()',
1766 f'''
1767 {{
1768 return {rename.class_("fz_document")}( {rename.ll_fn('fz_keep_document')}( &m_internal->super));
1769 }}
1770 ''',
1771 f'/* Returns wrapper for .super member. */',
1772 ),
1773 ],
1774 ),
1775
1776 pdf_filter_factory = ClassExtra(
1777 pod = 'inline',
1778 virtual_fnptrs = dict(
1779 self_ = lambda name: f'({rename.class_("pdf_filter_factory")}2*) {name}',
1780 self_n = 6,
1781 alloc = f'this->options = this;\n',
1782 ),
1783 ),
1784
1785 pdf_filter_options = ClassExtra(
1786 pod = 'inline',
1787 # We don't need to allocate extra space, and because we are a
1788 # POD class, we can simply let our default constructor run.
1789 #
1790 # this->opaque is passed as arg[2].
1791 #
1792 virtual_fnptrs = dict(
1793 self_ = lambda name: f'({rename.class_("pdf_filter_options")}2*) {name}',
1794 self_n = 2,
1795 alloc = f'this->opaque = this;\n',
1796 ),
1797 constructors_extra = [
1798 ExtraConstructor( '()',
1799 f'''
1800 {{
1801 this->recurse = 0;
1802 this->instance_forms = 0;
1803 this->ascii = 0;
1804 this->opaque = nullptr;
1805 this->complete = nullptr;
1806 this->filters = nullptr;
1807 pdf_filter_factory eof = {{ nullptr, nullptr}};
1808 m_filters.push_back( eof);
1809 this->newlines = 0;
1810 }}
1811 ''',
1812 comment = '/* Default constructor initialises all fields to null/zero. */',
1813 )
1814 ],
1815 methods_extra = [
1816 ExtraMethod(
1817 'void',
1818 f'add_factory( const pdf_filter_factory& factory)',
1819 textwrap.dedent( f'''
1820 {{
1821 this->m_filters.back() = factory;
1822 pdf_filter_factory eof = {{ nullptr, nullptr}};
1823 this->m_filters.push_back( eof);
1824 this->filters = &this->m_filters[0];
1825 }}
1826 '''),
1827 comment = f'/* Appends `factory` to internal vector and updates this->filters. */',
1828 ),
1829 ],
1830 class_bottom = textwrap.dedent( f'''
1831 std::vector< pdf_filter_factory> m_filters;
1832 '''),
1833 ),
1834
1835 pdf_lexbuf = ClassExtra(
1836 constructors_extra = [
1837 ExtraConstructor( '(int size)',
1838 f'''
1839 {{
1840 m_internal = new ::pdf_lexbuf;
1841 {rename.ll_fn('pdf_lexbuf_init')}(m_internal, size);
1842 }}
1843 ''',
1844 comment = '/* Constructor that calls pdf_lexbuf_init(size). */',
1845 ),
1846 ],
1847 methods_extra = [
1848 ExtraMethod(
1849 '',
1850 '~()',
1851 f'''
1852 {{
1853 {rename.ll_fn('pdf_lexbuf_fin')}(m_internal);
1854 delete m_internal;
1855 }}
1856 ''',
1857 comment = '/* Destructor that calls pdf_lexbuf_fin(). */',
1858 ),
1859 ],
1860 ),
1861
1862 pdf_layer_config = ClassExtra(
1863 pod = 'inline',
1864 ),
1865
1866 pdf_layer_config_ui = ClassExtra(
1867 pod = 'inline',
1868 constructors_extra = [
1869 ExtraConstructor( '()',
1870 f'''
1871 {{
1872 this->text = nullptr;
1873 this->depth = 0;
1874 this->type = PDF_LAYER_UI_LABEL;
1875 this->selected = 0;
1876 this->locked = 0;
1877 }}
1878 ''',
1879 comment = '/* Default constructor sets .text to null, .type to PDF_LAYER_UI_LABEL, and other fields to zero. */',
1880 ),
1881 ],
1882 ),
1883
1884 pdf_obj = ClassExtra(
1885 constructor_raw = 'default',
1886 methods_extra = [
1887 ExtraMethod(
1888 f'{rename.class_("pdf_obj")}',
1889 f'{rename.method( "pdf_obj", "pdf_dict_get")}(int key)',
1890 f'''
1891 {{
1892 ::pdf_obj* temp = {rename.ll_fn('pdf_dict_get')}(this->m_internal, (::pdf_obj*)(uintptr_t) key);
1893 {rename.ll_fn('pdf_keep_obj')}(temp);
1894 auto ret = {rename.class_('pdf_obj')}(temp);
1895 return ret;
1896 }}
1897 ''',
1898 comment = '/* Typesafe wrapper for looking up things such as PDF_ENUM_NAME_Annots. */',
1899 overload=True,
1900 ),
1901 ExtraMethod(
1902 f'std::string',
1903 f'{rename.method( "pdf_obj", "pdf_load_field_name2")}()',
1904 f'''
1905 {{
1906 return {rename.namespace_fn('pdf_load_field_name2')}( *this);
1907 }}
1908 ''',
1909 comment = f'/* Alternative to `{rename.fn("pdf_load_field_name")}()` that returns a std::string. */',
1910 ),
1911 ]
1912 ),
1913
1914 pdf_page = ClassExtra(
1915 methods_extra = [
1916 ExtraMethod(
1917 f'{rename.class_("fz_page")}',
1918 'super()',
1919 f'''
1920 {{
1921 return {rename.class_("fz_page")}( {rename.ll_fn('fz_keep_page')}( &m_internal->super));
1922 }}
1923 ''',
1924 f'/* Returns wrapper for .super member. */',
1925 ),
1926 ExtraMethod(
1927 f'{rename.class_("pdf_document")}',
1928 'doc()',
1929 f'''
1930 {{
1931 return {rename.class_("pdf_document")}( {rename.ll_fn('pdf_keep_document')}( m_internal->doc));
1932 }}
1933 ''',
1934 f'/* Returns wrapper for .doc member. */',
1935 ),
1936 ExtraMethod(
1937 f'{rename.class_("pdf_obj")}',
1938 'obj()',
1939 f'''
1940 {{
1941 return {rename.class_("pdf_obj")}( {rename.ll_fn('pdf_keep_obj')}( m_internal->obj));
1942 }}
1943 ''',
1944 f'/* Returns wrapper for .obj member. */',
1945 ),
1946 ],
1947 ),
1948
1949 pdf_image_rewriter_options = ClassExtra(
1950 pod = 'inline',
1951 copyable = 'default',
1952 ),
1953
1954 pdf_processor = ClassExtra(
1955 virtual_fnptrs = dict(
1956 self_ = lambda name: f'(*({rename.class_("pdf_processor")}2**) ({name} + 1))',
1957 alloc = textwrap.dedent( f'''
1958 m_internal = (::pdf_processor*) {rename.ll_fn("pdf_new_processor")}(
1959 sizeof(*m_internal)
1960 + sizeof({rename.class_("pdf_processor")}2*)
1961 );
1962 *(({rename.class_("pdf_processor")}2**) (m_internal + 1)) = this;
1963 '''),
1964 ),
1965 ),
1966
1967 pdf_recolor_options = ClassExtra(
1968 pod = 'inline',
1969 ),
1970
1971 pdf_redact_options = ClassExtra(
1972 pod = 'inline',
1973 ),
1974
1975 pdf_sanitize_filter_options = ClassExtra(
1976 pod = 'inline',
1977 # this->opaque is passed as arg[1].
1978 virtual_fnptrs = dict(
1979 self_ = lambda name: f'({rename.class_("pdf_sanitize_filter_options")}2*) {name}',
1980 alloc = f'this->opaque = this;\n',
1981 ),
1982 ),
1983
1984 pdf_write_options = ClassExtra(
1985 constructors_extra = [
1986 ExtraConstructor( '()',
1987 f'''
1988 {{
1989 /* Use memcpy() otherwise we get 'invalid array assignment' errors. */
1990 memcpy(this->internal(), &pdf_default_write_options, sizeof(*this->internal()));
1991 }}
1992 ''',
1993 comment = '/* Default constructor, makes copy of pdf_default_write_options. */'
1994 ),
1995 ExtraConstructor(
1996 f'(const {rename.class_("pdf_write_options")}& rhs)',
1997 f'''
1998 {{
1999 *this = rhs;
2000 }}
2001 ''',
2002 comment = '/* Copy constructor using raw memcopy(). */'
2003 ),
2004 ],
2005 methods_extra = [
2006 ExtraMethod(
2007 f'{rename.class_("pdf_write_options")}&',
2008 f'operator=(const {rename.class_("pdf_write_options")}& rhs)',
2009 f'''
2010 {{
2011 memcpy(this->internal(), rhs.internal(), sizeof(*this->internal()));
2012 return *this;
2013 }}
2014 ''',
2015 comment = '/* Assignment using plain memcpy(). */',
2016 ),
2017 ExtraMethod(
2018 # Would prefer to call this opwd_utf8_set() but
2019 # this conflicts with SWIG-generated accessor for
2020 # opwd_utf8.
2021 f'void',
2022 f'opwd_utf8_set_value(const std::string& text)',
2023 f'''
2024 {{
2025 size_t len = std::min(text.size(), sizeof(opwd_utf8) - 1);
2026 memcpy(opwd_utf8, text.c_str(), len);
2027 opwd_utf8[len] = 0;
2028 }}
2029 ''',
2030 '/* Copies <text> into opwd_utf8[]. */',
2031 ),
2032 ExtraMethod(
2033 f'void',
2034 f'upwd_utf8_set_value(const std::string& text)',
2035 f'''
2036 {{
2037 size_t len = std::min(text.size(), sizeof(upwd_utf8) - 1);
2038 memcpy(upwd_utf8, text.c_str(), len);
2039 upwd_utf8[len] = 0;
2040 }}
2041 ''',
2042 '/* Copies <text> into upwd_utf8[]. */',
2043 ),
2044 ],
2045 pod = 'inline',
2046 copyable = 'default',
2047 )
2048 )