1 ///////////////////////////////////////////////////////////////////////////////
2 // Name:        pdfdocument.cpp
3 // Purpose:     Implementation of wxPdfDocument (public methods)
4 // Author:      Ulrich Telle
5 // Created:     2005-08-04
6 // Copyright:   (c) Ulrich Telle
7 // Licence:     wxWindows licence
8 ///////////////////////////////////////////////////////////////////////////////
9 
10 /// \file pdfdocument.cpp Implementation of the wxPdfDocument class
11 
12 // For compilers that support precompilation, includes <wx/wx.h>.
13 #include <wx/wxprec.h>
14 
15 #ifdef __BORLANDC__
16 #pragma hdrstop
17 #endif
18 
19 #ifndef WX_PRECOMP
20 #include <wx/wx.h>
21 #endif
22 
23 #include <wx/image.h>
24 #include <wx/paper.h>
25 #include <wx/wfstream.h>
26 
27 #include "wx/pdfbookmark.h"
28 #include "wx/pdfdocument.h"
29 #include "wx/pdffont.h"
30 #include "wx/pdffontdetails.h"
31 #include "wx/pdffontmanager.h"
32 #include "wx/pdfform.h"
33 #include "wx/pdfgradient.h"
34 #include "wx/pdfgraphics.h"
35 #include "wx/pdflayer.h"
36 #include "wx/pdfparser.h"
37 #include "wx/pdfpattern.h"
38 #include "wx/pdfspotcolour.h"
39 #include "wx/pdftemplate.h"
40 #include "wx/pdffontparser.h"
41 #include "wx/pdfutility.h"
42 
43 #if WXPDFDOC_INHERIT_WXOBJECT
IMPLEMENT_DYNAMIC_CLASS(wxPdfDocument,wxObject)44 IMPLEMENT_DYNAMIC_CLASS(wxPdfDocument, wxObject)
45 #endif
46 
47 // ----------------------------------------------------------------------------
48 // wxPdfDocument: class representing a PDF document
49 // ----------------------------------------------------------------------------
50 
51 wxPdfDocument::wxPdfDocument(int orientation, const wxString& unit, wxPaperSize format)
52 #if WXPDFDOC_INHERIT_WXOBJECT
53   : wxObject()
54 #endif
55 {
56   m_creationDateSet = false;
57   m_yAxisOriginTop = true;
58   SetScaleFactor(unit);
59 
60   // Page format
61   m_defPageSize = CalculatePageSize(format);
62   Initialize(orientation);
63 }
64 
wxPdfDocument(int orientation,double pageWidth,double pageHeight,const wxString & unit)65 wxPdfDocument::wxPdfDocument(int orientation, double pageWidth, double pageHeight, const wxString& unit)
66 #if WXPDFDOC_INHERIT_WXOBJECT
67   : wxObject()
68 #endif
69 {
70   m_creationDateSet = false;
71   m_yAxisOriginTop = true;
72   SetScaleFactor(unit);
73   m_defPageSize = CalculatePageSize(pageWidth, pageHeight);
74   Initialize(orientation);
75 }
76 
77 void
SetScaleFactor(const wxString & unit)78 wxPdfDocument::SetScaleFactor(const wxString& unit)
79 {
80   // Scale factor
81   if (unit == wxS("pt"))
82   {
83     m_k = 1.;
84   }
85   else if (unit == wxS("in"))
86   {
87     m_k = 72.;
88   }
89   else if (unit == wxS("cm"))
90   {
91     m_k = 72. / 2.54;
92   }
93   else // if (unit == "mm") or unknown
94   {
95     m_k = 72. / 25.4;
96   }
97 }
98 
99 wxSize
CalculatePageSize(wxPaperSize format)100 wxPdfDocument::CalculatePageSize(wxPaperSize format)
101 {
102   bool deletePaperDatabase = false;
103   wxPrintPaperDatabase* printPaperDatabase = wxThePrintPaperDatabase;
104   if (printPaperDatabase == NULL)
105   {
106     printPaperDatabase = new wxPrintPaperDatabase;
107     printPaperDatabase->CreateDatabase();
108     deletePaperDatabase = true;
109   }
110   wxPrintPaperType* paperType = printPaperDatabase->FindPaperType(format);
111   if (paperType == NULL)
112   {
113     paperType = printPaperDatabase->FindPaperType(wxPAPER_A4);
114   }
115   wxSize paperSize = paperType->GetSize();
116   if (deletePaperDatabase)
117   {
118     delete printPaperDatabase;
119   }
120   return paperSize;
121 }
122 
123 wxSize
CalculatePageSize(double pageWidth,double pageHeight)124 wxPdfDocument::CalculatePageSize(double pageWidth, double pageHeight)
125 {
126   int width  = (int) (pageWidth  * (m_k * 254. / 72.));
127   int height = (int) (pageHeight * (m_k * 254. / 72.));
128   return wxSize(width,height);
129 }
130 
131 void
Initialize(int orientation)132 wxPdfDocument::Initialize(int orientation)
133 {
134   // Allocate arrays
135   m_currentFont = NULL;
136   m_buffer = new wxMemoryOutputStream();
137 
138   m_page       = 0;
139   m_n          = 2;
140   m_offsets = new wxPdfOffsetHashMap();
141 
142   m_pages = new wxPdfPageHashMap();
143   m_pageSizes = new wxPdfPageSizeMap();
144   m_orientationChanges = new wxPdfBoolHashMap();
145 
146   m_state            = 0;
147   m_fonts            = new wxPdfFontHashMap();
148   m_images           = new wxPdfImageHashMap();
149   m_pageLinks        = new wxPdfPageLinksMap();
150   m_links            = new wxPdfLinkHashMap();
151   m_namedLinks       = new wxPdfNamedLinksMap();
152   m_diffs            = new wxPdfStringHashMap();
153   m_winansi          = new wxPdfBoolHashMap();
154   m_extGStates       = new wxPdfExtGStateMap();
155   m_extGSLookup      = new wxPdfExtGSLookupMap();
156   m_currentExtGState = 0;
157   m_gradients        = new wxPdfGradientMap();
158   m_annotations      = new wxPdfAnnotationsMap();
159   m_formAnnotations  = new wxPdfFormAnnotsMap();
160   m_formFields       = new wxPdfFormFieldsMap();
161   m_radioGroups      = new wxPdfRadioGroupMap();
162   m_templates        = new wxPdfTemplatesMap();
163   m_parsers          = new wxPdfParserMap();
164   m_spotColours      = new wxPdfSpotColourMap();
165   m_patterns         = new wxPdfPatternMap();
166   m_ocgs             = new wxPdfOcgMap();
167   m_rgLayers         = new wxPdfLayerRGMap();
168   m_lockedLayers     = NULL;
169   m_attachments      = new wxPdfAttachmentMap();
170 
171   m_outlineRoot      = -1;
172   m_maxOutlineLevel  = 0;
173 
174   m_inFooter   = false;
175   m_lasth      = 0;
176   m_fontFamily = wxEmptyString;
177   m_fontStyle  = wxPDF_FONTSTYLE_REGULAR;
178   m_fontSizePt = 12;
179   m_decoration = wxPDF_FONTSTYLE_REGULAR;
180   m_fontSubsetting = true;
181 
182   m_drawColour  = wxPdfColour();
183   m_fillColour  = wxPdfColour();
184   m_textColour  = wxPdfColour();
185   m_colourFlag  = false;
186   m_wsApply = false;
187   m_ws = 0;
188   m_textRenderMode = wxPDF_TEXT_RENDER_FILL;
189 
190   // Initialize image scale factor
191   m_imgscale = 1.;
192 
193   // Page format
194   m_curPageSize = m_defPageSize;
195   m_fwPt = m_defPageSize.GetWidth() / 254. * 72.;
196   m_fhPt = m_defPageSize.GetHeight() / 254. * 72.;
197   m_fw = m_fwPt / m_k;
198   m_fh = m_fhPt / m_k;
199 
200   // Page orientation
201   if (orientation == wxLANDSCAPE)
202   {
203     m_defOrientation = wxLANDSCAPE;
204     m_wPt = m_fhPt;
205     m_hPt = m_fwPt;
206   }
207   else // orientation == wxPORTRAIT or unknown
208   {
209     m_defOrientation = wxPORTRAIT;
210     m_wPt = m_fwPt;
211     m_hPt = m_fhPt;
212   }
213 
214   m_curOrientation = m_defOrientation;
215   m_w = m_wPt / m_k;
216   m_h = m_hPt / m_k;
217   m_angle = 0;
218   m_fillRule = wxWINDING_RULE;
219   m_inTransform = 0;
220 
221   // Page margins (1 cm)
222   double margin = (72.0 / 25.4 * 10.0) / m_k;
223   SetMargins(margin, margin);
224 
225   // Interior cell margin (1 mm)
226   m_cMargin = margin / 10;
227 
228   // Line width (0.2 mm)
229   m_lineWidth = (72.0 / 25.4 * 0.2) / m_k;
230 
231   // Automatic page break
232   SetAutoPageBreak(true, 2*margin);
233 
234   // Full width display mode
235   SetDisplayMode(wxPDF_ZOOM_FULLWIDTH);
236   m_zoomFactor = 100.;
237 
238   // Default viewer preferences
239   m_viewerPrefs = 0;
240 
241   // Disable kerning
242   SetKerning(false);
243 
244   // Enable compression
245   SetCompression(true);
246 
247   // Set default PDF version number
248   m_PDFVersion = wxS("1.3");
249   m_importVersion = m_PDFVersion;
250 
251   m_encrypted = false;
252   m_encryptor = NULL;
253 
254   m_javascript = wxEmptyString;
255 
256   m_inTemplate = false;
257   m_templateId = 0;
258   m_templatePrefix = wxS("/TPL");
259 
260   m_currentParser = NULL;
261   m_currentSource = wxEmptyString;
262 
263   m_translate = false;
264 
265   m_zapfdingbats = 0;
266 }
267 
~wxPdfDocument()268 wxPdfDocument::~wxPdfDocument()
269 {
270   wxPdfFontHashMap::iterator font = m_fonts->begin();
271   for (font = m_fonts->begin(); font != m_fonts->end(); font++)
272   {
273     if (font->second != NULL)
274     {
275       delete font->second;
276     }
277   }
278   delete m_fonts;
279 
280   wxPdfImageHashMap::iterator image = m_images->begin();
281   for (image = m_images->begin(); image != m_images->end(); image++)
282   {
283     if (image->second != NULL)
284     {
285       delete image->second;
286     }
287   }
288   delete m_images;
289 
290   wxPdfPageHashMap::iterator page = m_pages->begin();
291   for (page = m_pages->begin(); page != m_pages->end(); page++)
292   {
293     if (page->second != NULL)
294     {
295       delete page->second;
296     }
297   }
298   delete m_pages;
299 
300   wxPdfPageLinksMap::iterator pageLinks = m_pageLinks->begin();
301   for (pageLinks = m_pageLinks->begin(); pageLinks != m_pageLinks->end(); pageLinks++)
302   {
303     if (pageLinks->second != NULL)
304     {
305       delete pageLinks->second;
306     }
307   }
308   delete m_pageLinks;
309 
310   wxPdfLinkHashMap::iterator link = m_links->begin();
311   for (link = m_links->begin(); link != m_links->end(); link++)
312   {
313     if (link->second != NULL)
314     {
315       delete link->second;
316     }
317   }
318   delete m_links;
319 
320   delete m_namedLinks;
321 
322   size_t j;
323   for (j = 0; j < m_outlines.GetCount(); j++)
324   {
325     wxPdfBookmark* bookmark = (wxPdfBookmark*) m_outlines[j];
326     delete bookmark;
327   }
328 
329   wxPdfStringHashMap::iterator diff = m_diffs->begin();
330   for (diff = m_diffs->begin(); diff != m_diffs->end(); diff++)
331   {
332     if (diff->second != NULL)
333     {
334       delete diff->second;
335     }
336   }
337   delete m_diffs;
338 
339   delete m_winansi;
340 
341   wxPdfExtGStateMap::iterator extGState = m_extGStates->begin();
342   for (extGState = m_extGStates->begin(); extGState != m_extGStates->end(); extGState++)
343   {
344     if (extGState->second != NULL)
345     {
346       delete extGState->second;
347     }
348   }
349   delete m_extGStates;
350 
351   delete m_extGSLookup;
352 
353   wxPdfGradientMap::iterator gradient = m_gradients->begin();
354   for (gradient = m_gradients->begin(); gradient != m_gradients->end(); gradient++)
355   {
356     if (gradient->second != NULL)
357     {
358       delete gradient->second;
359     }
360   }
361   delete m_gradients;
362 
363   wxPdfAnnotationsMap::iterator annotation = m_annotations->begin();
364   for (annotation = m_annotations->begin(); annotation != m_annotations->end(); annotation++)
365   {
366     if (annotation->second != NULL)
367     {
368       delete annotation->second;
369     }
370   }
371   delete m_annotations;
372 
373   wxPdfFormAnnotsMap::iterator formAnnotation = m_formAnnotations->begin();
374   for (formAnnotation = m_formAnnotations->begin(); formAnnotation != m_formAnnotations->end(); formAnnotation++)
375   {
376     if (formAnnotation->second != NULL)
377     {
378       delete formAnnotation->second;
379     }
380   }
381   delete m_formAnnotations;
382 
383   wxPdfFormFieldsMap::iterator formField = m_formFields->begin();
384   for (formField = m_formFields->begin(); formField != m_formFields->end(); formField++)
385   {
386     if (formField->second != NULL)
387     {
388       delete formField->second;
389     }
390   }
391   delete m_formFields;
392 
393   wxPdfRadioGroupMap::iterator radioGroup = m_radioGroups->begin();
394   for (radioGroup = m_radioGroups->begin(); radioGroup != m_radioGroups->end(); radioGroup++)
395   {
396     if (radioGroup->second != NULL)
397     {
398       delete radioGroup->second;
399     }
400   }
401   delete m_radioGroups;
402 
403   wxPdfTemplatesMap::iterator templateIter = m_templates->begin();
404   for (templateIter = m_templates->begin(); templateIter != m_templates->end(); templateIter++)
405   {
406     if (templateIter->second != NULL)
407     {
408       delete templateIter->second;
409     }
410   }
411   delete m_templates;
412 
413   wxPdfParserMap::iterator parser = m_parsers->begin();
414   for (parser = m_parsers->begin(); parser != m_parsers->end(); parser++)
415   {
416     if (parser->second != NULL)
417     {
418       delete parser->second;
419     }
420   }
421   delete m_parsers;
422 
423   wxPdfSpotColourMap::iterator spotColour = m_spotColours->begin();
424   for (spotColour = m_spotColours->begin(); spotColour != m_spotColours->end(); spotColour++)
425   {
426     if (spotColour->second != NULL)
427     {
428       delete spotColour->second;
429     }
430   }
431   delete m_spotColours;
432 
433   wxPdfPatternMap::iterator pattern = m_patterns->begin();
434   for (pattern = m_patterns->begin(); pattern != m_patterns->end(); pattern++)
435   {
436     if (pattern->second != NULL)
437     {
438       delete pattern->second;
439     }
440   }
441   delete m_patterns;
442 
443   wxPdfOcgMap::iterator ocg = m_ocgs->begin();
444   for (ocg = m_ocgs->begin(); ocg != m_ocgs->end(); ++ocg)
445   {
446     if (ocg->second != NULL)
447     {
448       delete ocg->second;
449     }
450   }
451   delete m_ocgs;
452 
453   wxPdfLayerRGMap::iterator rg;
454   for (rg = m_rgLayers->begin(); rg != m_rgLayers->end(); ++rg)
455   {
456     if (rg->second != NULL)
457     {
458       delete rg->second;
459     }
460   }
461   delete m_rgLayers;
462 
463   if (m_lockedLayers != NULL)
464   {
465     delete m_lockedLayers;
466   }
467 
468   wxPdfAttachmentMap::iterator attach;
469   for (attach = m_attachments->begin(); attach != m_attachments->end(); ++attach)
470   {
471     if (attach->second != NULL)
472     {
473       delete attach->second;
474     }
475   }
476   delete m_attachments;
477 
478   delete m_orientationChanges;
479   delete m_pageSizes;
480 
481   delete m_offsets;
482 
483   if (m_encryptor != NULL)
484   {
485     delete m_encryptor;
486   }
487 
488   if (m_buffer != NULL)
489   {
490     delete m_buffer;
491   }
492 }
493 
494 // --- Public methods
495 
496 void
SetProtection(int permissions,const wxString & userPassword,const wxString & ownerPassword,wxPdfEncryptionMethod encryptionMethod,int keyLength)497 wxPdfDocument::SetProtection(int permissions,
498                              const wxString& userPassword,
499                              const wxString& ownerPassword,
500                              wxPdfEncryptionMethod encryptionMethod,
501                              int keyLength)
502 {
503   if (m_encryptor == NULL)
504   {
505     int revision = (keyLength > 0) ? 3 : 2;
506     switch (encryptionMethod)
507     {
508       case wxPDF_ENCRYPTION_AESV2:
509         revision = 4;
510         if (m_PDFVersion < wxS("1.6"))
511         {
512           m_PDFVersion = wxS("1.6");
513         }
514         break;
515       case wxPDF_ENCRYPTION_RC4V2:
516         revision = 3;
517         break;
518       case wxPDF_ENCRYPTION_RC4V1:
519       default:
520         revision = 2;
521         break;
522     }
523     m_encryptor = new wxPdfEncrypt(revision, keyLength);
524     m_encrypted = true;
525     int allowedFlags = wxPDF_PERMISSION_PRINT | wxPDF_PERMISSION_MODIFY |
526                        wxPDF_PERMISSION_COPY  | wxPDF_PERMISSION_ANNOT;
527     int protection = 192;
528     protection += (permissions & allowedFlags);
529     wxString ownerPswd = ownerPassword;
530     if (ownerPswd.Length() == 0)
531     {
532       ownerPswd = wxPdfUtility::GetUniqueId(wxS("wxPdfDoc"));
533     }
534     m_encryptor->GenerateEncryptionKey(userPassword, ownerPswd, protection);
535   }
536 }
537 
538 void
SetImageScale(double scale)539 wxPdfDocument::SetImageScale(double scale)
540 {
541   m_imgscale = scale;
542 }
543 
544 double
GetImageScale()545 wxPdfDocument::GetImageScale()
546 {
547   return m_imgscale;
548 }
549 
550 double
GetPageWidth()551 wxPdfDocument::GetPageWidth()
552 {
553   return m_w;
554 }
555 
556 double
GetPageHeight()557 wxPdfDocument::GetPageHeight()
558 {
559   return m_h;
560 }
561 
562 double
GetBreakMargin()563 wxPdfDocument::GetBreakMargin()
564 {
565   return m_bMargin;
566 }
567 
568 double
GetScaleFactor()569 wxPdfDocument::GetScaleFactor()
570 {
571   return m_k;
572 }
573 
574 void
AliasNbPages(const wxString & alias)575 wxPdfDocument::AliasNbPages(const wxString& alias)
576 {
577   // Define an alias for total number of pages
578   m_aliasNbPages = alias;
579 }
580 
581 void
Open()582 wxPdfDocument::Open()
583 {
584   // Begin document
585   m_state = 1;
586 }
587 
588 void
AddPage(int orientation)589 wxPdfDocument::AddPage(int orientation)
590 {
591   AddPage(orientation, m_defPageSize);
592 }
593 
594 void
AddPage(int orientation,wxPaperSize format)595 wxPdfDocument::AddPage(int orientation, wxPaperSize format)
596 {
597   wxSize pageSize = CalculatePageSize(format);
598   AddPage(orientation, pageSize);
599 }
600 
601 void
AddPage(int orientation,double pageWidth,double pageHeight)602 wxPdfDocument::AddPage(int orientation, double pageWidth, double pageHeight)
603 {
604   if (pageWidth > 0 && pageHeight > 0)
605   {
606     wxSize pageSize = CalculatePageSize(pageWidth, pageHeight);
607     AddPage(orientation, pageSize);
608   }
609   else
610   {
611     wxLogError(wxString(wxS("wxPdfDocument::AddPage: ")) +
612                wxString::Format(_("Invalid page size (%.1f,%.1f)."), pageWidth, pageHeight));
613   }
614 }
615 
616 void
AddPage(int orientation,wxSize pageSize)617 wxPdfDocument::AddPage(int orientation, wxSize pageSize)
618 {
619   if (m_inTemplate)
620   {
621     wxLogError(wxString(wxS("wxPdfDocument::AddPage: ")) +
622                wxString::Format(_("Adding pages in templates is impossible. Current template ID is %d."), m_templateId));
623     return;
624   }
625 
626   // Start a new page
627   if (m_state == 0)
628   {
629     Open();
630   }
631   wxPdfFontDetails* currentFont = m_currentFont;
632   wxString family = m_fontFamily;
633   int style = m_fontStyle;
634   if (m_decoration & wxPDF_FONTSTYLE_UNDERLINE)
635   {
636     style |= wxPDF_FONTSTYLE_UNDERLINE;
637   }
638   if (m_decoration & wxPDF_FONTSTYLE_OVERLINE)
639   {
640     style |= wxPDF_FONTSTYLE_OVERLINE;
641   }
642   if (m_decoration & wxPDF_FONTSTYLE_STRIKEOUT)
643   {
644     style |= wxPDF_FONTSTYLE_STRIKEOUT;
645   }
646   double size = m_fontSizePt;
647   double lw = m_lineWidth;
648   wxPdfColour dc = m_drawColour;
649   wxPdfColour fc = m_fillColour;
650   wxPdfColour tc = m_textColour;
651   bool cf = m_colourFlag;
652 
653   if (m_page > 0)
654   {
655     // Page footer
656     m_inFooter = true;
657     Footer();
658     m_inFooter = false;
659     // Close page
660     EndPage();
661   }
662 
663   // Start new page
664   BeginPage(orientation, pageSize);
665 
666   // Set line cap style to square
667   Out("2 J");
668 
669   // Set line width
670   m_lineWidth = lw;
671   OutAscii(wxPdfUtility::Double2String(lw*m_k,2)+wxString(wxS(" w")));
672 
673   // Set font
674   if (currentFont != NULL)
675   {
676     m_currentFont = currentFont;
677     m_fontStyle = style;
678     m_fontSizePt = size;
679     ForceCurrentFont();
680   }
681 
682   // Set colours
683   m_drawColour = dc;
684   if (dc != wxPdfColour(0))
685   {
686     OutAscii(dc.GetColour(true));
687   }
688   m_fillColour = fc;
689   if (fc != wxPdfColour(0))
690   {
691     OutAscii(fc.GetColour(false));
692   }
693   m_textColour = tc;
694   m_colourFlag = cf;
695 
696   // Page header
697   Header();
698 
699   // Restore line width
700   if (m_lineWidth != lw)
701   {
702     m_lineWidth = lw;
703     OutAscii(wxPdfUtility::Double2String(lw*m_k,2)+wxString(wxS(" w")));
704   }
705 
706   // Restore font
707   if(family.Length() > 0)
708   {
709     SetFont(family, style, size);
710   }
711   if (currentFont != NULL)
712   {
713     SetFont(currentFont->GetUserFont(), style, size);
714   }
715 
716   // Restore colours
717   if (m_drawColour != dc)
718   {
719     m_drawColour = dc;
720     OutAscii(dc.GetColour(true));
721   }
722   if (m_fillColour != fc)
723   {
724     m_fillColour = fc;
725     OutAscii(fc.GetColour(false));
726   }
727   m_textColour = tc;
728   m_colourFlag = cf;
729 }
730 
731 void
SetLineWidth(double width)732 wxPdfDocument::SetLineWidth(double width)
733 {
734   // Set line width
735   m_lineWidth = width;
736   if (m_page > 0)
737   {
738     OutAscii(wxPdfUtility::Double2String(width*m_k,2)+ wxString(wxS(" w")));
739   }
740 }
741 
742 double
GetLineWidth()743 wxPdfDocument::GetLineWidth()
744 {
745   return m_lineWidth;
746 }
747 
748 bool
AddFont(const wxString & family,const wxString & style,const wxString & file)749 wxPdfDocument::AddFont(const wxString& family, const wxString& style, const wxString& file)
750 {
751   bool ok = !family.IsEmpty();
752   if (ok)
753   {
754     wxPdfFont regFont = wxPdfFontManager::GetFontManager()->GetFont(family, style);
755     if (!regFont.IsValid())
756     {
757       wxString fileName = file;
758       if (fileName.IsEmpty())
759       {
760         fileName = family.Lower() + style.Lower() + wxString(wxS(".xml"));
761         fileName.Replace(wxS(" "),wxS(""));
762       }
763       regFont = wxPdfFontManager::GetFontManager()->RegisterFont(fileName, family);
764       ok = regFont.IsValid();
765     }
766   }
767   return ok;
768 }
769 
770 #if wxUSE_UNICODE
771 
772 bool
AddFontCJK(const wxString & family)773 wxPdfDocument::AddFontCJK(const wxString& family)
774 {
775   bool ok = !family.IsEmpty();
776   if (ok)
777   {
778     wxPdfFont regFont = wxPdfFontManager::GetFontManager()->GetFont(family);
779     if (!regFont.IsValid())
780     {
781       ok = wxPdfFontManager::GetFontManager()->RegisterFontCJK(family);
782     }
783   }
784   return ok;
785 }
786 
787 #endif // wxUSE_UNICODE
788 
789 bool
SetFont(const wxString & family,const wxString & style,double size)790 wxPdfDocument::SetFont(const wxString& family, const wxString& style, double size)
791 {
792   return SelectFont(family, style, size);
793 }
794 
795 bool
SetFont(const wxString & family,int style,double size)796 wxPdfDocument::SetFont(const wxString& family, int style, double size)
797 {
798   return SelectFont(family, style, size);
799 }
800 
801 bool
SetFont(const wxPdfFont & font,int style,double size)802 wxPdfDocument::SetFont(const wxPdfFont& font, int style, double size)
803 {
804   return SelectFont(font, style, size);
805 }
806 
807 bool
SetFont(const wxFont & font)808 wxPdfDocument::SetFont(const wxFont& font)
809 {
810   return SelectFont(font);
811 }
812 
813 void
SetFontSize(double size)814 wxPdfDocument::SetFontSize(double size)
815 {
816   SetFontSize(size, true);
817 }
818 
819 void
SetFontSize(double size,bool setSize)820 wxPdfDocument::SetFontSize(double size, bool setSize)
821 {
822   if (m_currentFont == NULL)
823   {
824     wxLogError(wxString(wxS("wxPdfDocument::SetFontSize: ")) +
825       wxString(_("No font selected.")));
826     return;
827   }
828   // Set font size in points
829   if (m_fontSizePt == size)
830   {
831     return;
832   }
833   m_fontSizePt = size;
834   m_fontSize = size / m_k;
835   if (setSize && m_page > 0)
836   {
837     OutAscii(wxString::Format(wxS("BT /F%d "),m_currentFont->GetIndex()) +
838              wxPdfUtility::Double2String(m_fontSizePt,2) + wxString(wxS(" Tf ET")));
839   }
840 }
841 
842 wxPdfFont
GetCurrentFont() const843 wxPdfDocument::GetCurrentFont() const
844 {
845   if (m_currentFont == NULL)
846   {
847     wxLogError(wxString(wxS("wxPdfDocument::GetCurrentFont: ")) +
848                wxString(_("No font selected.")));
849     return wxPdfFont();
850   }
851   return m_currentFont->GetUserFont();
852 }
853 
854 const wxPdfFontDescription&
GetFontDescription() const855 wxPdfDocument::GetFontDescription() const
856 {
857   if (m_currentFont == NULL)
858   {
859     wxLogError(wxString(wxS("wxPdfDocument::GetFontDescription: ")) +
860                wxString(_("No font selected.")));
861     static wxPdfFontDescription dummy;
862     return dummy;
863   }
864   return m_currentFont->GetDescription();
865 }
866 
867 const wxString
GetFontFamily()868 wxPdfDocument::GetFontFamily()
869 {
870   return m_fontFamily;
871 }
872 
873 const wxString
GetFontStyle() const874 wxPdfDocument::GetFontStyle() const
875 {
876   wxString style = wxEmptyString;
877   int styles = GetFontStyles();
878   if (styles & wxPDF_FONTSTYLE_BOLD)
879   {
880     style += wxString(wxS("B"));
881   }
882   if (styles & wxPDF_FONTSTYLE_ITALIC)
883   {
884     style += wxString(wxS("I"));
885   }
886   if (styles & wxPDF_FONTSTYLE_UNDERLINE)
887   {
888     style += wxString(wxS("U"));
889   }
890   if (styles & wxPDF_FONTSTYLE_OVERLINE)
891   {
892     style += wxString(wxS("O"));
893   }
894   if (styles & wxPDF_FONTSTYLE_STRIKEOUT)
895   {
896     style += wxString(wxS("S"));
897   }
898   return style;
899 }
900 
901 int
GetFontStyles() const902 wxPdfDocument::GetFontStyles() const
903 {
904   return m_fontStyle | m_decoration;
905 }
906 
907 double
GetFontSize() const908 wxPdfDocument::GetFontSize() const
909 {
910   return m_fontSizePt;
911 }
912 
913 double
GetStringWidth(const wxString & s)914 wxPdfDocument::GetStringWidth(const wxString& s)
915 {
916   wxString voText = ApplyVisualOrdering(s);
917   return DoGetStringWidth(voText);
918 }
919 
920 double
DoGetStringWidth(const wxString & s)921 wxPdfDocument::DoGetStringWidth(const wxString& s)
922 {
923   double w = 0;
924   if (m_currentFont != 0)
925   {
926     w = m_currentFont->GetStringWidth(s, m_kerning) * m_fontSize;
927   }
928   return w;
929 }
930 
931 void
Text(double x,double y,const wxString & txt)932 wxPdfDocument::Text(double x, double y, const wxString& txt)
933 {
934   // Output a string
935   wxString voText = ApplyVisualOrdering(txt);
936 
937   if (m_colourFlag)
938   {
939     Out("q ", false);
940     OutAscii(m_textColour.GetColour(false), false);
941     Out(" ", false);
942   }
943   if (m_yAxisOriginTop)
944   {
945     OutAscii(wxString(wxS("BT 1 0 0 -1 ")) +
946              wxPdfUtility::Double2String(x*m_k,2) + wxString(wxS(" ")) +
947              wxPdfUtility::Double2String(y*m_k,2) + wxString(wxS(" Tm ")), false);
948   }
949   else
950   {
951     OutAscii(wxString(wxS("BT ")) +
952              wxPdfUtility::Double2String(x*m_k,2) + wxString(wxS(" ")) +
953              wxPdfUtility::Double2String(y*m_k,2) + wxString(wxS(" Td ")), false);
954   }
955   OutAscii(wxString::Format(wxS("%d Tr "), m_textRenderMode), false);
956   ShowText(voText);
957   Out("ET", false);
958 
959   if ((m_decoration & wxPDF_FONTSTYLE_DECORATION_MASK) && voText.Length() > 0)
960   {
961     Out(" ", false);
962     OutAscii(DoDecoration(x, y, voText), false);
963   }
964 
965   if (m_colourFlag)
966   {
967     Out(" Q", false);
968   }
969   Out("\n", false);
970 }
971 
972 void
RotatedText(double x,double y,const wxString & txt,double angle)973 wxPdfDocument::RotatedText(double x, double y, const wxString& txt, double angle)
974 {
975   // Text rotated around its origin
976   if (angle == 0)
977   {
978     Text(x, y, txt);
979   }
980   else
981   {
982     StartTransform();
983     Rotate(angle, x, y);
984     Text(x, y, txt);
985     StopTransform();
986   }
987 }
988 
989 void
RotatedText(double textX,double textY,double rotationX,double rotationY,const wxString & txt,double angle)990 wxPdfDocument::RotatedText(double textX, double textY, double rotationX, double rotationY, const wxString& txt, double angle)
991 {
992   // Text rotated around its origin
993   if (angle == 0)
994   {
995     Text(textX, textY, txt);
996   }
997   else
998   {
999     StartTransform();
1000     Rotate(angle, rotationX, rotationY);
1001     Text(textX, textY, txt);
1002     StopTransform();
1003   }
1004 }
1005 
1006 bool
AcceptPageBreak()1007 wxPdfDocument::AcceptPageBreak()
1008 {
1009   // Accept automatic page break or not
1010   return m_autoPageBreak;
1011 }
1012 
1013 void
Cell(double w,double h,const wxString & txt,int border,int ln,int align,int fill,const wxPdfLink & link)1014 wxPdfDocument::Cell(double w, double h, const wxString& txt, int border, int ln, int align, int fill, const wxPdfLink& link)
1015 {
1016   wxString voText = ApplyVisualOrdering(txt);
1017   DoCell(w, h, voText, border, ln, align, fill, link);
1018 }
1019 
1020 void
DoCell(double w,double h,const wxString & txt,int border,int ln,int align,int fill,const wxPdfLink & link)1021 wxPdfDocument::DoCell(double w, double h, const wxString& txt, int border, int ln, int align, int fill, const wxPdfLink& link)
1022 {
1023   // Output a cell
1024   double x, y;
1025   double k = m_k;
1026   bool doPageBreak = (m_yAxisOriginTop) ? (m_y+h > m_pageBreakTrigger) : (m_y-h < m_pageBreakTrigger);
1027   if (doPageBreak && !m_inFooter && AcceptPageBreak())
1028   {
1029     // Automatic page break
1030     x = m_x;
1031     double ws = m_ws;
1032     if (ws > 0)
1033     {
1034       m_ws = 0;
1035       Out("0 Tw");
1036     }
1037     AddPage(m_curOrientation);
1038     m_x = x;
1039     if (ws > 0)
1040     {
1041       m_ws = ws;
1042       if (!m_wsApply)
1043       {
1044         OutAscii(wxPdfUtility::Double2String(ws*k, 3) + wxString(wxS(" Tw")));
1045       }
1046     }
1047   }
1048   if ( w == 0)
1049   {
1050     w = m_w - m_rMargin - m_x;
1051   }
1052   wxString s = wxEmptyString;
1053   if (fill == 1 || border == wxPDF_BORDER_FRAME)
1054   {
1055     s = wxPdfUtility::Double2String(m_x*k,2) + wxString(wxS(" ")) +
1056         wxPdfUtility::Double2String(m_y*k,2) + wxString(wxS(" ")) +
1057         wxPdfUtility::Double2String(w*k,2) + wxString(wxS(" ")) +
1058         wxPdfUtility::Double2String(h*k,2);
1059     if (fill == 1)
1060     {
1061       if (border == wxPDF_BORDER_FRAME)
1062       {
1063         s += wxString(wxS(" re B "));
1064       }
1065       else
1066       {
1067         s += wxString(wxS(" re f "));
1068       }
1069     }
1070     else
1071     {
1072       s += wxString(wxS(" re S "));
1073     }
1074   }
1075   if (border != wxPDF_BORDER_NONE && border != wxPDF_BORDER_FRAME)
1076   {
1077     x = m_x;
1078     y = m_y;
1079     if (border & wxPDF_BORDER_LEFT)
1080     {
1081       s += wxPdfUtility::Double2String(x*k,2) + wxString(wxS(" ")) +
1082            wxPdfUtility::Double2String(y*k,2) + wxString(wxS(" m ")) +
1083            wxPdfUtility::Double2String(x*k,2) + wxString(wxS(" ")) +
1084            wxPdfUtility::Double2String((y+h)*k,2) + wxString(wxS(" l S "));
1085     }
1086     if (border & wxPDF_BORDER_TOP)
1087     {
1088       s += wxPdfUtility::Double2String(x*k,2) + wxString(wxS(" ")) +
1089            wxPdfUtility::Double2String(y*k,2) + wxString(wxS(" m ")) +
1090            wxPdfUtility::Double2String((x+w)*k,2) + wxString(wxS(" ")) +
1091            wxPdfUtility::Double2String(y*k,2) + wxString(wxS(" l S "));
1092     }
1093     if (border & wxPDF_BORDER_RIGHT)
1094     {
1095       s += wxPdfUtility::Double2String((x+w)*k,2) + wxString(wxS(" ")) +
1096            wxPdfUtility::Double2String(y*k,2) + wxString(wxS(" m ")) +
1097            wxPdfUtility::Double2String((x+w)*k,2) + wxString(wxS(" ")) +
1098            wxPdfUtility::Double2String((y+h)*k,2) + wxString(wxS(" l S "));
1099     }
1100     if (border & wxPDF_BORDER_BOTTOM)
1101     {
1102       s += wxPdfUtility::Double2String(x*k,2) + wxString(wxS(" ")) +
1103            wxPdfUtility::Double2String((y+h)*k,2) + wxString(wxS(" m ")) +
1104            wxPdfUtility::Double2String((x+w)*k,2) + wxString(wxS(" ")) +
1105            wxPdfUtility::Double2String((y+h)*k,2) + wxString(wxS(" l S "));
1106     }
1107   }
1108   if (s.Length() > 0)
1109   {
1110     bool newline = txt.Length() == 0;
1111     OutAscii(s, newline);
1112     s = wxS("");
1113   }
1114 
1115   if (txt.Length() > 0)
1116   {
1117     double width = DoGetStringWidth(txt);
1118     double dx;
1119     if (align == wxPDF_ALIGN_RIGHT)
1120     {
1121       dx = w - m_cMargin - width;
1122     }
1123     else if (align == wxPDF_ALIGN_CENTER)
1124     {
1125       dx = (w - width) / 2;
1126     }
1127     else
1128     {
1129       dx = m_cMargin;
1130     }
1131     if (m_colourFlag)
1132     {
1133       s += wxString(wxS("q ")) + m_textColour.GetColour(false) + wxString(wxS(" "));
1134     }
1135     if (m_yAxisOriginTop)
1136     {
1137       s += wxString(wxS("BT 1 0 0 -1 ")) +
1138            wxPdfUtility::Double2String((m_x+dx)*k,2) + wxString(wxS(" ")) +
1139            wxPdfUtility::Double2String((m_y+.5*h+.3*m_fontSize)*k,2) + wxString(wxS(" Tm "));
1140     }
1141     else
1142     {
1143       s += wxString(wxS("BT ")) +
1144            wxPdfUtility::Double2String((m_x+dx)*k,2) + wxString(wxS(" ")) +
1145            wxPdfUtility::Double2String((m_y+.5*h+.3*m_fontSize)*k,2) + wxString(wxS(" Td "));
1146     }
1147     OutAscii(s,false);
1148     OutAscii(wxString::Format(wxS("%d Tr "), m_textRenderMode), false);
1149     ShowText(txt);
1150     s = wxS(" ET");
1151 
1152     if (m_decoration & wxPDF_FONTSTYLE_DECORATION_MASK)
1153     {
1154       s += wxString(wxS(" ")) + DoDecoration(m_x+dx,m_y+.5*h+.3*m_fontSize,txt);
1155     }
1156     if (m_colourFlag)
1157     {
1158       s += wxString(wxS(" Q"));
1159     }
1160     if (link.IsValid())
1161     {
1162       Link(m_x+dx,m_y+.5*h-.5*m_fontSize,width,m_fontSize,link);
1163     }
1164     OutAscii(s);
1165   }
1166   m_lasth = h;
1167   if (ln > 0)
1168   {
1169     // Go to next line
1170     if (m_yAxisOriginTop)
1171     {
1172       m_y += h;
1173     }
1174     else
1175     {
1176       m_y -= h;
1177     }
1178     if ( ln == 1)
1179     {
1180       m_x = m_lMargin;
1181     }
1182   }
1183   else
1184   {
1185     m_x += w;
1186   }
1187 }
1188 
1189 int
MultiCell(double w,double h,const wxString & txt,int border,int align,int fill,int maxline)1190 wxPdfDocument::MultiCell(double w, double h, const wxString& txt, int border, int align, int fill, int maxline)
1191 {
1192   // Output text with automatic or explicit line breaks
1193   if (w == 0)
1194   {
1195     w = m_w - m_rMargin - m_x;
1196   }
1197 
1198   // Determine whether to apply manual word spacing
1199   wxString fontType = m_currentFont->GetType();
1200   m_wsApply = (align == wxPDF_ALIGN_JUSTIFY) && ((fontType == wxS("TrueTypeUnicode")) || (fontType == wxS("OpenTypeUnicode")));
1201 
1202   double wmax = (w - 2 * m_cMargin);
1203   wxString s = ApplyVisualOrdering(txt);
1204   s.Replace(wxS("\r"),wxS("")); // remove carriage returns
1205   int nb = (int) s.Length();
1206   if (nb > 0 && s[nb-1] == wxS('\n'))
1207   {
1208     nb--;
1209   }
1210 
1211   int b = wxPDF_BORDER_NONE;
1212   int b2 = wxPDF_BORDER_NONE;
1213   if (border != wxPDF_BORDER_NONE)
1214   {
1215     if (border == wxPDF_BORDER_FRAME)
1216     {
1217       b = wxPDF_BORDER_LEFT | wxPDF_BORDER_RIGHT | wxPDF_BORDER_TOP;
1218       b2 = wxPDF_BORDER_LEFT | wxPDF_BORDER_RIGHT;
1219     }
1220     else
1221     {
1222       b2 = wxPDF_BORDER_NONE;
1223       if (border & wxPDF_BORDER_LEFT)
1224       {
1225         b2 = b2 | wxPDF_BORDER_LEFT;
1226       }
1227       if (border & wxPDF_BORDER_RIGHT)
1228       {
1229         b2 = b2 | wxPDF_BORDER_RIGHT;
1230       }
1231       b = (border & wxPDF_BORDER_TOP) ? b2 | wxPDF_BORDER_TOP : b2;
1232     }
1233   }
1234   int sep = -1;
1235   int i = 0;
1236   int j = 0;
1237   double len = 0;
1238   double ls = 0;
1239   int ns = 0;
1240   int nl = 1;
1241   wxChar c;
1242   while (i < nb)
1243   {
1244     // Get next character
1245     c = s[i];
1246     if (c == wxS('\n'))
1247     {
1248       // Explicit line break
1249       if (m_ws > 0)
1250       {
1251         m_ws = 0;
1252         Out("0 Tw");
1253       }
1254       DoCell(w,h,s.SubString(j,i-1),b,2,align,fill);
1255       i++;
1256       sep = -1;
1257       j = i;
1258       len = 0;
1259       ns = 0;
1260       nl++;
1261       if (border != wxPDF_BORDER_NONE && nl == 2)
1262       {
1263         b = b2;
1264       }
1265       if (maxline > 0 && nl > maxline)
1266       {
1267         return j;
1268       }
1269       continue;
1270     }
1271     if (c == wxS(' '))
1272     {
1273       sep = i;
1274       ls = len;
1275       ns++;
1276     }
1277     len = DoGetStringWidth(s.SubString(j, i));
1278 
1279     if (len > wmax)
1280     {
1281       // Automatic line break
1282       if (sep == -1)
1283       {
1284         if (i == j)
1285         {
1286           i++;
1287         }
1288         if (m_ws > 0)
1289         {
1290           m_ws = 0;
1291           Out("0 Tw");
1292         }
1293         DoCell(w,h,s.SubString(j,i-1),b,2,align,fill);
1294       }
1295       else
1296       {
1297         if (align == wxPDF_ALIGN_JUSTIFY)
1298         {
1299           m_ws = (ns > 1) ? (wmax - ls)/(ns-1) : 0;
1300           if (!m_wsApply)
1301           {
1302             OutAscii(wxPdfUtility::Double2String(m_ws*m_k, 3) + wxString(wxS(" Tw")));
1303           }
1304         }
1305         DoCell(w,h,s.SubString(j,sep-1),b,2,align,fill);
1306         i = sep + 1;
1307       }
1308       sep = -1;
1309       j = i;
1310       len = 0;
1311       ns = 0;
1312       nl++;
1313       if (border != wxPDF_BORDER_NONE && nl == 2)
1314       {
1315         b = b2;
1316       }
1317       if (maxline > 0 && nl > maxline)
1318       {
1319         return j;
1320       }
1321     }
1322     else
1323     {
1324       i++;
1325     }
1326   }
1327   // Last chunk
1328   if (m_ws > 0)
1329   {
1330     m_ws = 0;
1331     Out("0 Tw");
1332   }
1333   if ((border != wxPDF_BORDER_NONE) && (border & wxPDF_BORDER_BOTTOM))
1334   {
1335     b = b | wxPDF_BORDER_BOTTOM;
1336   }
1337   DoCell(w,h,s.SubString(j,i-1),b,2,align,fill);
1338   m_x = m_lMargin;
1339   m_wsApply = false;
1340   return i;
1341 }
1342 
1343 int
LineCount(double w,const wxString & txt)1344 wxPdfDocument::LineCount(double w, const wxString& txt)
1345 {
1346   // Output text with automatic or explicit line breaks
1347   if (w == 0)
1348   {
1349     w = m_w - m_rMargin - m_x;
1350   }
1351 
1352   double wmax = (w - 2 * m_cMargin);
1353   wxString s = txt;
1354   s.Replace(wxS("\r"),wxS("")); // remove carriage returns
1355   int nb = (int) s.Length();
1356   if (nb > 0 && s[nb-1] == wxS('\n'))
1357   {
1358     nb--;
1359   }
1360 
1361   int sep = -1;
1362   int i = 0;
1363   int j = 0;
1364   double len = 0;
1365   int nl = 1;
1366   wxChar c;
1367   while (i < nb)
1368   {
1369     // Get next character
1370     c = s[i];
1371     if (c == wxS('\n'))
1372     {
1373       // Explicit line break
1374       i++;
1375       sep = -1;
1376       j = i;
1377       len = 0;
1378       nl++;
1379       continue;
1380     }
1381     if (c == wxS(' '))
1382     {
1383       sep = i;
1384     }
1385     len = DoGetStringWidth(s.SubString(j, i));
1386 
1387     if (len > wmax)
1388     {
1389       // Automatic line break
1390       if (sep == -1)
1391       {
1392         if (i == j)
1393         {
1394           i++;
1395         }
1396       }
1397       else
1398       {
1399         i = sep + 1;
1400       }
1401       sep = -1;
1402       j = i;
1403       len = 0;
1404       nl++;
1405     }
1406     else
1407     {
1408       i++;
1409     }
1410   }
1411   return nl;
1412 }
1413 
1414 int
TextBox(double w,double h,const wxString & txt,int halign,int valign,int border,int fill)1415 wxPdfDocument::TextBox(double w, double h, const wxString& txt,
1416                        int halign, int valign, int border, int fill)
1417 {
1418   double xi = m_x;
1419   double yi = m_y;
1420 
1421   double hrow  = m_fontSize;
1422   int textrows = LineCount(w, txt);
1423   int maxrows  = (int) floor(h / hrow);
1424   int rows     = (textrows < maxrows) ? textrows : maxrows;
1425 
1426   double dy = 0;
1427   if (valign == wxPDF_ALIGN_MIDDLE)
1428   {
1429     dy = (h - rows * hrow) / 2;
1430   }
1431   else if (valign == wxPDF_ALIGN_BOTTOM)
1432   {
1433     dy = h - rows * hrow;
1434   }
1435 
1436   SetY(yi+dy);
1437   SetX(xi);
1438   int trail = MultiCell(w, hrow, txt, 0, halign, fill, rows);
1439 
1440   if (border == wxPDF_BORDER_FRAME)
1441   {
1442     Rect(xi, yi, w, h);
1443   }
1444   else
1445   {
1446     if (border & wxPDF_BORDER_LEFT)   Line(xi,yi,xi,yi+h);
1447     if (border & wxPDF_BORDER_RIGHT)  Line(xi+w,yi,xi+w,yi+h);
1448     if (border & wxPDF_BORDER_TOP)    Line(xi,yi,xi+w,yi);
1449     if (border & wxPDF_BORDER_BOTTOM) Line(xi,yi+h,xi+w,yi+h);
1450   }
1451 
1452   return trail;
1453 }
1454 
1455 void
Write(double h,const wxString & txt,const wxPdfLink & link)1456 wxPdfDocument::Write(double h, const wxString& txt, const wxPdfLink& link)
1457 {
1458   WriteCell(h, txt, wxPDF_BORDER_NONE, 0, link);
1459 }
1460 
1461 void
WriteCell(double h,const wxString & txt,int border,int fill,const wxPdfLink & link)1462 wxPdfDocument::WriteCell(double h, const wxString& txt, int border, int fill, const wxPdfLink& link)
1463 {
1464   // Output text in flowing mode
1465   wxString s = ApplyVisualOrdering(txt);
1466 
1467   s.Replace(wxS("\r"),wxS("")); // remove carriage returns
1468   int nb = (int) s.Length();
1469 
1470   // handle single space character
1471   if ((nb == 1) && s[0] == wxS(' '))
1472   {
1473     m_x += DoGetStringWidth(s);
1474     return;
1475   }
1476 
1477   double saveCellMargin = GetCellMargin();
1478   SetCellMargin(0);
1479 
1480   double w = m_w - m_rMargin - m_x;
1481   double wmax = (w - 2 * m_cMargin) + wxPDF_EPSILON;
1482 
1483   int sep = -1;
1484   int i = 0;
1485   int j = 0;
1486   double len=0;
1487   int nl = 1;
1488   wxChar c;
1489   while (i < nb)
1490   {
1491     // Get next character
1492     c = s[i];
1493     if (c == wxS('\n'))
1494     {
1495       // Explicit line break
1496       DoCell(w, h, s.SubString(j,i-1), border, 2, wxPDF_ALIGN_LEFT, fill, link);
1497       i++;
1498       sep = -1;
1499       j = i;
1500       len = 0;
1501       if (nl == 1)
1502       {
1503         m_x = m_lMargin;
1504         w = m_w - m_rMargin - m_x;
1505         wmax = (w - 2 * m_cMargin);
1506       }
1507       nl++;
1508       continue;
1509     }
1510     if (c == wxS(' '))
1511     {
1512       sep = i;
1513     }
1514     len = DoGetStringWidth(s.SubString(j, i));
1515     if (len > wmax)
1516     {
1517       // Automatic line break
1518       if (sep == -1)
1519       {
1520         if (m_x > m_lMargin)
1521         {
1522           // Move to next line
1523           m_x = m_lMargin;
1524           if (m_yAxisOriginTop)
1525           {
1526             m_y += h;
1527           }
1528           else
1529           {
1530             m_y -= h;
1531           }
1532           w = m_w - m_rMargin - m_x;
1533           wmax = (w - 2 * m_cMargin);
1534           i++;
1535           nl++;
1536           continue;
1537         }
1538         if (i == j)
1539         {
1540           i++;
1541         }
1542         DoCell(w, h,s.SubString(j, i-1), border, 2, wxPDF_ALIGN_LEFT, fill, link);
1543       }
1544       else
1545       {
1546         DoCell(w, h, s.SubString(j, sep-1), border, 2, wxPDF_ALIGN_LEFT, fill, link);
1547         i = sep + 1;
1548       }
1549       sep = -1;
1550       j = i;
1551       len = 0;
1552       if (nl == 1)
1553       {
1554         m_x = m_lMargin;
1555         w = m_w - m_rMargin - m_x;
1556         wmax = (w - 2 * m_cMargin);
1557       }
1558       nl++;
1559     }
1560     else
1561     {
1562       i++;
1563     }
1564   }
1565   // Last chunk
1566   if (i != j)
1567   {
1568     DoCell(len, h, s.SubString(j,i-1), border, 0, wxPDF_ALIGN_LEFT, fill, link);
1569   }
1570 
1571   // Following statement was in PHP code, but seems to be in error.
1572   // m_x += GetStringWidth(s.SubString(j, i-1));
1573   SetCellMargin(saveCellMargin);
1574 }
1575 
1576 bool
WriteGlyphArray(wxPdfArrayDouble & x,wxPdfArrayDouble & y,wxPdfArrayUint32 & glyphs)1577 wxPdfDocument::WriteGlyphArray(wxPdfArrayDouble& x, wxPdfArrayDouble& y, wxPdfArrayUint32& glyphs)
1578 {
1579   bool ok = m_currentFont != NULL;
1580 #if wxUSE_UNICODE
1581   if (ok)
1582   {
1583     // Check whether the current font is valid for this method
1584     wxString fontType = m_currentFont->GetType();
1585     if (fontType.IsSameAs(wxS("TrueTypeUnicode")) || fontType.IsSameAs(wxS("OpenTypeUnicode")))
1586     {
1587       // if the arrays have different sizes use only the smallest size
1588       size_t nx = x.GetCount();
1589       size_t ny = y.GetCount();
1590       size_t ng = glyphs.GetCount();
1591       size_t n = (nx > ny) ? ((ny > ng) ? ng : ny) : ((nx > ng) ? ng : nx);
1592       double xp, yp;
1593       size_t j;
1594       for (j = 0; j < n; ++j)
1595       {
1596         xp = m_x + x[j];
1597         yp = m_y + y[j];
1598         if (m_yAxisOriginTop)
1599         {
1600           Out("BT 1 0 0 -1 ", false);
1601         }
1602         else
1603         {
1604           Out("BT ", false);
1605         }
1606         OutAscii(wxPdfUtility::Double2String(xp*m_k,2), false);
1607         Out(" ", false);
1608         OutAscii(wxPdfUtility::Double2String(yp*m_k,2), false);
1609         if (m_yAxisOriginTop)
1610         {
1611           Out(" Tm ", false);
1612         }
1613         else
1614         {
1615           Out(" Td ", false);
1616         }
1617         ShowGlyph(glyphs[j]);
1618         Out(" ET");
1619       }
1620     }
1621     else
1622     {
1623       ok = false;
1624       wxLogError(wxString(wxS("wxPdfDocument::WriteGlyphArray: ")) +
1625                  wxString::Format(_("Font type '%s' not supported."), fontType.c_str()));
1626     }
1627   }
1628   else
1629   {
1630     wxLogError(wxString(wxS("wxPdfDocument::WriteGlyphArray: ")) +
1631                wxString(_("No font selected.")));
1632   }
1633 #else
1634   wxUnusedVar(x);
1635   wxUnusedVar(y);
1636   wxUnusedVar(glyphs);
1637   wxLogError(wxString(wxS("wxPdfDocument::WriteGlyphArray: ")) +
1638              wxString(_("Supported in Unicode build only.")));
1639 #endif // wxUSE_UNICODE
1640   return ok;
1641 }
1642 
1643 wxSize
GetImageSize(const wxString & file,const wxString & mimeType)1644 wxPdfDocument::GetImageSize(const wxString& file, const wxString& mimeType)
1645 {
1646   wxSize imageSize(0, 0);
1647   wxImage image;
1648   if (mimeType.IsEmpty())
1649   {
1650     // Auto detect image type
1651     image.LoadFile(file);
1652   }
1653   else
1654   {
1655     // Use mimetype as specified
1656     image.LoadFile(file, mimeType);
1657   }
1658   if (image.IsOk())
1659   {
1660 #if wxCHECK_VERSION(2,9,0)
1661     imageSize = image.GetSize();
1662 #else
1663     imageSize.Set(image.GetWidth(), image.GetHeight());
1664 #endif
1665   }
1666   return imageSize;
1667 }
1668 
1669 bool
Image(const wxString & file,double x,double y,double w,double h,const wxString & type,const wxPdfLink & link,int maskImage)1670 wxPdfDocument::Image(const wxString& file, double x, double y, double w, double h,
1671                      const wxString& type, const wxPdfLink& link, int maskImage)
1672 {
1673   wxPdfImage* currentImage = NULL;
1674   // Put an image on the page
1675   wxPdfImageHashMap::iterator image = (*m_images).find(file);
1676   if (image == (*m_images).end())
1677   {
1678     // First use of image, get info
1679     int i = (int) (*m_images).size() + 1;
1680     currentImage = new wxPdfImage(this, i, file, type);
1681     if (!currentImage->Parse())
1682     {
1683       bool isValid = false;
1684       delete currentImage;
1685 
1686       if (wxImage::FindHandler(wxBITMAP_TYPE_PNG) == NULL)
1687       {
1688         wxImage::AddHandler(new wxPNGHandler());
1689       }
1690       wxImage tempImage;
1691       tempImage.LoadFile(file);
1692       if (tempImage.Ok())
1693       {
1694         isValid = Image(file, tempImage, x, y, w, h, link, maskImage);
1695       }
1696       return isValid;
1697     }
1698     if (maskImage > 0)
1699     {
1700       currentImage->SetMaskImage(maskImage);
1701     }
1702     (*m_images)[file] = currentImage;
1703   }
1704   else
1705   {
1706     currentImage = image->second;
1707     if (maskImage > 0 && currentImage->GetMaskImage() != maskImage)
1708     {
1709       currentImage->SetMaskImage(maskImage);
1710     }
1711   }
1712   OutImage(currentImage, x, y, w, h, link);
1713   return true;
1714 }
1715 
1716 bool
Image(const wxString & name,const wxImage & img,double x,double y,double w,double h,const wxPdfLink & link,int maskImage,bool jpegFormat,int jpegQuality)1717 wxPdfDocument::Image(const wxString& name, const wxImage& img, double x, double y, double w, double h,
1718                      const wxPdfLink& link, int maskImage, bool jpegFormat, int jpegQuality)
1719 {
1720   bool isValid = false;
1721   if (img.Ok())
1722   {
1723     wxImage tempImage = img.Copy();
1724     wxPdfImage* currentImage = NULL;
1725     // Put an image on the page
1726     wxPdfImageHashMap::iterator image = (*m_images).find(name);
1727     if (image == (*m_images).end())
1728     {
1729       if (tempImage.HasAlpha())
1730       {
1731         if (maskImage <= 0)
1732         {
1733           maskImage = ImageMask(name+wxString(wxS(".mask")), tempImage);
1734         }
1735         if(!tempImage.ConvertAlphaToMask(0))
1736         {
1737           return false;
1738         }
1739       }
1740       else if (tempImage.HasMask() && maskImage <= 0)
1741       {
1742         // Extract the mask
1743         wxImage mask = tempImage.ConvertToMono(tempImage.GetMaskRed(), tempImage.GetMaskGreen(), tempImage.GetMaskBlue());
1744         // Invert the mask
1745         mask = mask.ConvertToMono(0, 0, 0);
1746         maskImage = ImageMask(name+wxString(wxS(".mask")), mask);
1747       }
1748       // First use of image, get info
1749       tempImage.SetMask(false);
1750       if (jpegFormat)
1751       {
1752         tempImage.SetOption(wxIMAGE_OPTION_QUALITY, jpegQuality);
1753       }
1754       int i = (int) (*m_images).size() + 1;
1755       currentImage = new wxPdfImage(this, i, name, tempImage, jpegFormat);
1756       if (!currentImage->Parse())
1757       {
1758         delete currentImage;
1759         return false;
1760       }
1761       if (maskImage > 0)
1762       {
1763         currentImage->SetMaskImage(maskImage);
1764       }
1765       (*m_images)[name] = currentImage;
1766     }
1767     else
1768     {
1769       currentImage = image->second;
1770       if (maskImage > 0 && currentImage->GetMaskImage() != maskImage)
1771       {
1772         currentImage->SetMaskImage(maskImage);
1773       }
1774     }
1775     OutImage(currentImage, x, y, w, h, link);
1776     isValid = true;
1777   }
1778   return isValid;
1779 }
1780 
1781 bool
Image(const wxString & name,wxInputStream & stream,const wxString & mimeType,double x,double y,double w,double h,const wxPdfLink & link,int maskImage)1782 wxPdfDocument::Image(const wxString& name, wxInputStream& stream,
1783                      const wxString& mimeType,
1784                      double x, double y, double w, double h,
1785                      const wxPdfLink& link, int maskImage)
1786 {
1787   bool isValid = false;
1788   wxPdfImage* currentImage = NULL;
1789   // Put an image on the page
1790   wxPdfImageHashMap::iterator image = (*m_images).find(name);
1791   if (image == (*m_images).end())
1792   {
1793     // First use of image, get info
1794     int i = (int) (*m_images).size() + 1;
1795     currentImage = new wxPdfImage(this, i, name, stream, mimeType);
1796     if (!currentImage->Parse())
1797     {
1798       delete currentImage;
1799       if (wxImage::FindHandler(wxBITMAP_TYPE_PNG) == NULL)
1800       {
1801         wxImage::AddHandler(new wxPNGHandler());
1802       }
1803       wxImage tempImage;
1804       tempImage.LoadFile(stream, mimeType);
1805       if (tempImage.Ok())
1806       {
1807         isValid = Image(name, tempImage, x, y, w, h, link, maskImage);
1808       }
1809       return isValid;
1810 
1811     }
1812     if (maskImage > 0)
1813     {
1814       currentImage->SetMaskImage(maskImage);
1815     }
1816     (*m_images)[name] = currentImage;
1817   }
1818   else
1819   {
1820     currentImage = image->second;
1821     if (maskImage > 0 && currentImage->GetMaskImage() != maskImage)
1822     {
1823       currentImage->SetMaskImage(maskImage);
1824     }
1825   }
1826   OutImage(currentImage, x, y, w, h, link);
1827   isValid = true;
1828   return isValid;
1829 }
1830 
1831 int
ImageMask(const wxString & file,const wxString & type)1832 wxPdfDocument::ImageMask(const wxString& file, const wxString& type)
1833 {
1834   int n = 0;
1835   wxPdfImage* currentImage = NULL;
1836   // Put an image on the page
1837   wxPdfImageHashMap::iterator image = (*m_images).find(file);
1838   if (image == (*m_images).end())
1839   {
1840     // First use of image, get info
1841     n = (int) (*m_images).size() + 1;
1842     currentImage = new wxPdfImage(this, n, file, type);
1843     if (!currentImage->Parse())
1844     {
1845       delete currentImage;
1846       return 0;
1847     }
1848     // Check whether this is a gray scale image (must be)
1849     if (currentImage->GetColourSpace() != wxS("DeviceGray"))
1850     {
1851       delete currentImage;
1852       return 0;
1853     }
1854     (*m_images)[file] = currentImage;
1855   }
1856   else
1857   {
1858     currentImage = image->second;
1859     n = currentImage->GetIndex();
1860   }
1861   if (m_PDFVersion < wxS("1.4"))
1862   {
1863     m_PDFVersion = wxS("1.4");
1864   }
1865   return n;
1866 }
1867 
1868 int
ImageMask(const wxString & name,const wxImage & img)1869 wxPdfDocument::ImageMask(const wxString& name, const wxImage& img)
1870 {
1871   int n = 0;
1872   if (img.Ok())
1873   {
1874     wxPdfImage* currentImage = NULL;
1875     // Put an image on the page
1876     wxPdfImageHashMap::iterator image = (*m_images).find(name);
1877     if (image == (*m_images).end())
1878     {
1879       wxImage tempImage;
1880       if (img.HasAlpha())
1881       {
1882         int x, y;
1883         int w = img.GetWidth();
1884         int h = img.GetHeight();
1885         tempImage = wxImage(w, h);
1886         unsigned char alpha;
1887         for (x = 0; x < w; x++)
1888         {
1889           for (y = 0; y < h; y++)
1890           {
1891             alpha = img.GetAlpha(x, y);
1892             tempImage.SetRGB(x, y, alpha, alpha, alpha);
1893           }
1894         }
1895         tempImage.SetOption(wxIMAGE_OPTION_PNG_FORMAT, wxPNG_TYPE_GREY_RED);
1896       }
1897       else
1898       {
1899         tempImage = img.ConvertToGreyscale();
1900         tempImage.SetOption(wxIMAGE_OPTION_PNG_FORMAT, wxPNG_TYPE_GREY_RED);
1901       }
1902       tempImage.SetMask(false);
1903       // First use of image, get info
1904       n = (int) (*m_images).size() + 1;
1905       currentImage = new wxPdfImage(this, n, name, tempImage);
1906       if (!currentImage->Parse())
1907       {
1908         delete currentImage;
1909         return 0;
1910       }
1911       (*m_images)[name] = currentImage;
1912     }
1913     else
1914     {
1915       currentImage = image->second;
1916       n = currentImage->GetIndex();
1917     }
1918     if (m_PDFVersion < wxS("1.4"))
1919     {
1920       m_PDFVersion = wxS("1.4");
1921     }
1922   }
1923   return n;
1924 }
1925 
1926 int
ImageMask(const wxString & name,wxInputStream & stream,const wxString & mimeType)1927 wxPdfDocument::ImageMask(const wxString& name, wxInputStream& stream, const wxString& mimeType)
1928 {
1929   int n = 0;
1930   wxPdfImage* currentImage = NULL;
1931   // Put an image on the page
1932   wxPdfImageHashMap::iterator image = (*m_images).find(name);
1933   if (image == (*m_images).end())
1934   {
1935     // First use of image, get info
1936     n = (int) (*m_images).size() + 1;
1937     currentImage = new wxPdfImage(this, n, name, stream, mimeType);
1938     if (!currentImage->Parse())
1939     {
1940       delete currentImage;
1941       return 0;
1942     }
1943     // Check whether this is a gray scale image (must be)
1944     if (currentImage->GetColourSpace() != wxS("DeviceGray"))
1945     {
1946       delete currentImage;
1947       return 0;
1948     }
1949     (*m_images)[name] = currentImage;
1950   }
1951   else
1952   {
1953     currentImage = image->second;
1954     n = currentImage->GetIndex();
1955   }
1956   if (m_PDFVersion < wxS("1.4"))
1957   {
1958     m_PDFVersion = wxS("1.4");
1959   }
1960   return n;
1961 }
1962 
1963 void
RotatedImage(const wxString & file,double x,double y,double w,double h,double angle,const wxString & type,const wxPdfLink & link,int maskImage)1964 wxPdfDocument::RotatedImage(const wxString& file, double x, double y, double w, double h,
1965                             double angle, const wxString& type, const wxPdfLink& link, int maskImage)
1966 {
1967   // Image rotated around its upper-left corner
1968   StartTransform();
1969   Rotate(angle, x, y);
1970   Image(file, x, y, w, h, type, link, maskImage);
1971   StopTransform();
1972 }
1973 
1974 void
Ln(double h)1975 wxPdfDocument::Ln(double h)
1976 {
1977   // Line feed; default value is last cell height
1978   m_x = m_lMargin;
1979   if (h < 0)
1980   {
1981     if (m_yAxisOriginTop)
1982     {
1983       m_y += m_lasth;
1984     }
1985     else
1986     {
1987       m_y -= m_lasth;
1988     }
1989   }
1990   else
1991   {
1992     if (m_yAxisOriginTop)
1993     {
1994       m_y += h;
1995     }
1996     else
1997     {
1998       m_y -= h;
1999     }
2000   }
2001 }
2002 
2003 bool
SaveAsFile(const wxString & name)2004 wxPdfDocument::SaveAsFile(const wxString& name)
2005 {
2006   wxString fileName = name;
2007   // Normalize parameters
2008   if(fileName.Length() == 0)
2009   {
2010     fileName = wxS("doc.pdf");
2011   }
2012 
2013   wxLogNull logNull;
2014   wxFileOutputStream outfile(fileName);
2015   bool ok = outfile.IsOk();
2016 
2017   if (ok)
2018   {
2019     // Finish document if necessary
2020     if (m_state < 3)
2021     {
2022       if (m_buffer != NULL)
2023       {
2024         delete m_buffer;
2025       }
2026       m_buffer = &outfile;
2027       Close();
2028       m_buffer = NULL;
2029     }
2030     else
2031     {
2032       // Save to local file
2033       wxMemoryInputStream tmp(*((wxMemoryOutputStream*) m_buffer));
2034       outfile.Write(tmp);
2035     }
2036     outfile.Close();
2037   }
2038   return ok;
2039 }
2040 
2041 const wxMemoryOutputStream&
CloseAndGetBuffer()2042 wxPdfDocument::CloseAndGetBuffer()
2043 {
2044   if (m_state < 3)
2045   {
2046     Close();
2047   }
2048 
2049   return *((wxMemoryOutputStream*) m_buffer);
2050 }
2051 
2052 void
SetViewerPreferences(int preferences)2053 wxPdfDocument::SetViewerPreferences(int preferences)
2054 {
2055   m_viewerPrefs = (preferences > 0) ? preferences : 0;
2056   if (((m_viewerPrefs & wxPDF_VIEWER_DISPLAYDOCTITLE) != 0) && (m_PDFVersion < wxS("1.4")))
2057   {
2058     m_PDFVersion = wxS("1.4");
2059   }
2060 }
2061 
2062 void
SetTitle(const wxString & title)2063 wxPdfDocument::SetTitle(const wxString& title)
2064 {
2065   // Title of document
2066   m_title = title;
2067 }
2068 
2069 void
SetSubject(const wxString & subject)2070 wxPdfDocument::SetSubject(const wxString& subject)
2071 {
2072   // Subject of document
2073   m_subject = subject;
2074 }
2075 
2076 void
SetAuthor(const wxString & author)2077 wxPdfDocument::SetAuthor(const wxString& author)
2078 {
2079   // Author of document
2080   m_author = author;
2081 }
2082 
2083 void
SetKeywords(const wxString & keywords)2084 wxPdfDocument::SetKeywords(const wxString& keywords)
2085 {
2086   // Keywords of document
2087   m_keywords = keywords;
2088 }
2089 
2090 void
SetCreator(const wxString & creator)2091 wxPdfDocument::SetCreator(const wxString& creator)
2092 {
2093   // Creator of document
2094   m_creator = creator;
2095 }
2096 
2097 void
SetCreationDate(const wxDateTime & creationDate)2098 wxPdfDocument::SetCreationDate(const wxDateTime& creationDate)
2099 {
2100   if (creationDate.IsValid())
2101   {
2102     m_creationDateSet = true;
2103     m_creationDate = creationDate;
2104   }
2105 }
2106 
2107 void
SetMargins(double left,double top,double right)2108 wxPdfDocument::SetMargins(double left, double top, double right)
2109 {
2110   // Set left, top and right margins
2111   m_lMargin = left;
2112   m_tMargin = top;
2113   if (right == -1)
2114   {
2115     right = left;
2116   }
2117   m_rMargin = right;
2118 }
2119 
2120 void
SetLeftMargin(double margin)2121 wxPdfDocument::SetLeftMargin(double margin)
2122 {
2123   // Set left margin
2124   m_lMargin = margin;
2125   if (m_page > 0 && m_x < margin)
2126   {
2127     m_x = margin;
2128   }
2129 }
2130 
2131 double
GetLeftMargin()2132 wxPdfDocument::GetLeftMargin()
2133 {
2134   return m_lMargin;
2135 }
2136 
2137 void
SetTopMargin(double margin)2138 wxPdfDocument::SetTopMargin(double margin)
2139 {
2140   // Set top margin
2141   m_tMargin = margin;
2142 }
2143 
2144 double
GetTopMargin()2145 wxPdfDocument::GetTopMargin()
2146 {
2147   return m_tMargin;
2148 }
2149 
2150 void
SetRightMargin(double margin)2151 wxPdfDocument::SetRightMargin(double margin)
2152 {
2153   // Set right margin
2154   m_rMargin = margin;
2155 }
2156 
2157 double
GetRightMargin()2158 wxPdfDocument::GetRightMargin()
2159 {
2160   return m_rMargin;
2161 }
2162 
2163 void
SetCellMargin(double margin)2164 wxPdfDocument::SetCellMargin(double margin)
2165 {
2166   // Set cell margin
2167   m_cMargin = margin;
2168 }
2169 
2170 double
GetCellMargin()2171 wxPdfDocument::GetCellMargin()
2172 {
2173   return m_cMargin;
2174 }
2175 
2176 void
SetLineHeight(double height)2177 wxPdfDocument::SetLineHeight(double height)
2178 {
2179   m_lasth = height;
2180 }
2181 
2182 double
GetLineHeight()2183 wxPdfDocument::GetLineHeight()
2184 {
2185   return m_lasth;
2186 }
2187 
2188 void
SetAutoPageBreak(bool autoPageBreak,double margin)2189 wxPdfDocument::SetAutoPageBreak(bool autoPageBreak, double margin)
2190 {
2191   // Set auto page break mode and triggering margin
2192   m_autoPageBreak = autoPageBreak;
2193   m_bMargin = margin;
2194   m_pageBreakTrigger = (m_yAxisOriginTop) ? m_h - margin : margin;
2195 }
2196 
2197 void
SetDisplayMode(wxPdfZoom zoom,wxPdfLayout layout,double zoomFactor)2198 wxPdfDocument::SetDisplayMode(wxPdfZoom zoom, wxPdfLayout layout, double zoomFactor)
2199 {
2200   // Set display mode in viewer
2201   switch (zoom)
2202   {
2203     case wxPDF_ZOOM_FULLPAGE:
2204     case wxPDF_ZOOM_FULLWIDTH:
2205     case wxPDF_ZOOM_REAL:
2206     case wxPDF_ZOOM_DEFAULT:
2207       m_zoomMode = zoom;
2208       break;
2209     case wxPDF_ZOOM_FACTOR:
2210       m_zoomMode = zoom;
2211       m_zoomFactor = (zoomFactor > 0) ? zoomFactor : 100.;
2212       break;
2213     default:
2214       m_zoomMode = wxPDF_ZOOM_FULLWIDTH;
2215       break;
2216   }
2217 
2218   switch (layout)
2219   {
2220     case wxPDF_LAYOUT_SINGLE:
2221     case wxPDF_LAYOUT_TWO:
2222     case wxPDF_LAYOUT_DEFAULT:
2223     case wxPDF_LAYOUT_CONTINUOUS:
2224       m_layoutMode = layout;
2225       break;
2226     default:
2227       m_layoutMode = wxPDF_LAYOUT_CONTINUOUS;
2228       break;
2229   }
2230 }
2231 
2232 void
Close()2233 wxPdfDocument::Close()
2234 {
2235   // Terminate document
2236   if (m_state == 3)
2237   {
2238     return;
2239   }
2240   if (m_page == 0)
2241   {
2242     AddPage();
2243   }
2244 
2245   // Page footer
2246   m_inFooter = true;
2247   Footer();
2248   m_inFooter = false;
2249 
2250   // Close page
2251   EndPage();
2252 
2253   // Close document
2254   EndDoc();
2255 }
2256 
2257 void
Header()2258 wxPdfDocument::Header()
2259 {
2260   // To be implemented in your own inherited class
2261 }
2262 
2263 void
Footer()2264 wxPdfDocument::Footer()
2265 {
2266   // To be implemented in your own inherited class
2267 }
2268 
2269 bool
IsInFooter()2270 wxPdfDocument::IsInFooter()
2271 {
2272   return m_inFooter;
2273 }
2274 
2275 int
PageNo()2276 wxPdfDocument::PageNo()
2277 {
2278   // Get current page number
2279   return m_page;
2280 }
2281 
2282 double
GetX()2283 wxPdfDocument::GetX()
2284 {
2285   // Get x position
2286   return m_x;
2287 }
2288 
2289 void
SetX(double x)2290 wxPdfDocument::SetX(double x)
2291 {
2292   // Set x position
2293   if ( x >= 0.0)
2294   {
2295     m_x = x;
2296   }
2297   else
2298   {
2299     m_x = m_w + x;
2300   }
2301 }
2302 
2303 double
GetY()2304 wxPdfDocument::GetY()
2305 {
2306   // Get y position
2307   return m_y;
2308 }
2309 
2310 void
SetY(double y)2311 wxPdfDocument::SetY(double y)
2312 {
2313   // Set y position and reset x
2314   m_x = m_lMargin;
2315   if ( y >= 0)
2316   {
2317     m_y = y;
2318   }
2319   else
2320   {
2321     m_y = m_h + y;
2322   }
2323 }
2324 
2325 void
SetXY(double x,double y)2326 wxPdfDocument::SetXY(double x, double y)
2327 {
2328   // Set x and y positions
2329   SetY(y);
2330   SetX(x);
2331 }
2332 
2333 void
SetKerning(bool kerning)2334 wxPdfDocument::SetKerning(bool kerning)
2335 {
2336   m_kerning = kerning;
2337 }
2338 
2339 void
SetCompression(bool compress)2340 wxPdfDocument::SetCompression(bool compress)
2341 {
2342   m_compress = compress;
2343 }
2344 
2345 void
AppendJavascript(const wxString & javascript)2346 wxPdfDocument::AppendJavascript(const wxString& javascript)
2347 {
2348   m_javascript += javascript;
2349 }
2350 
2351 bool
AttachFile(const wxString & fileName,const wxString & attachName,const wxString & description)2352 wxPdfDocument::AttachFile(const wxString& fileName, const wxString& attachName, const wxString& description)
2353 {
2354   wxFileName attachFile(fileName);
2355   bool ok = attachFile.FileExists();
2356   if (ok)
2357   {
2358     wxArrayString* attachment = new wxArrayString();
2359     attachment->Add(fileName);
2360     if (!attachName.IsEmpty())
2361     {
2362       attachment->Add(attachName);
2363     }
2364     else
2365     {
2366       attachment->Add(attachFile.GetFullName());
2367     }
2368     attachment->Add(description);
2369 
2370     int index = (int) (m_attachments->size() + 1);
2371     (*m_attachments)[index] = attachment;
2372   }
2373   else
2374   {
2375     wxLogDebug(wxS("*** Attachment file '%s' does not exist."), fileName.c_str());
2376   }
2377   return ok;
2378 }
2379 
2380 // ---
2381 
2382 void
AddSpotColour(const wxString & name,double cyan,double magenta,double yellow,double black)2383 wxPdfDocument::AddSpotColour(const wxString& name, double cyan, double magenta, double yellow, double black)
2384 {
2385   wxPdfSpotColourMap::iterator spotColour = (*m_spotColours).find(name);
2386   if (spotColour == (*m_spotColours).end())
2387   {
2388     int i = (int) (*m_spotColours).size() + 1;
2389     (*m_spotColours)[name] = new wxPdfSpotColour(i, cyan, magenta, yellow, black);
2390   }
2391 }
2392 
2393 bool
AddPattern(const wxString & patternName,const wxImage & image,double width,double height)2394 wxPdfDocument::AddPattern(const wxString& patternName, const wxImage& image, double width, double height)
2395 {
2396   bool isValid = true;
2397   wxPdfPatternMap::iterator patternIter = m_patterns->find(patternName);
2398   if (patternIter == m_patterns->end())
2399   {
2400     if (image.IsOk() && width > 0 && height > 0)
2401     {
2402       wxString imageName = wxString(wxS("pattern:")) + patternName;
2403       wxPdfImage* currentImage = NULL;
2404       wxPdfImageHashMap::iterator imageIter = (*m_images).find(imageName);
2405       if (imageIter == (*m_images).end())
2406       {
2407         // Prepare new image
2408         int maskImage = 0;
2409         wxImage tempImage = image.Copy();
2410         if (tempImage.HasAlpha())
2411         {
2412           maskImage = ImageMask(imageName+wxString(wxS(".mask")), tempImage);
2413           tempImage.ConvertAlphaToMask(0);
2414         }
2415         tempImage.SetMask(false);
2416         int i = (*m_images).size() + 1;
2417         currentImage = new wxPdfImage(this, i, imageName, tempImage);
2418         currentImage->Parse();
2419         if (maskImage > 0)
2420         {
2421           currentImage->SetMaskImage(maskImage);
2422         }
2423         (*m_images)[imageName] = currentImage;
2424       }
2425       else
2426       {
2427         // Use existing image
2428         currentImage = imageIter->second;
2429       }
2430 
2431       // Register new pattern
2432       wxPdfPattern* pattern;
2433       int i = (int) m_patterns->size() + 1;
2434       pattern = new wxPdfPattern(i, width, height);
2435       pattern->SetImage(currentImage);
2436       (*m_patterns)[patternName] = pattern;
2437     }
2438     else
2439     {
2440       isValid = false;
2441       if (!image.IsOk())
2442       {
2443         wxLogError(wxString(wxS("wxPdfDocument::AddPattern: ")) +
2444                    wxString(_("Invalid image.")));
2445       }
2446       else
2447       {
2448         wxLogError(wxString(wxS("wxPdfDocument::AddPattern: ")) +
2449                    wxString::Format(_("Invalid width (%.1f) and/or height (%.1f)."), width, height));
2450       }
2451     }
2452   }
2453   return isValid;
2454 }
2455 
2456 void
SetDrawColour(const wxColour & colour)2457 wxPdfDocument::SetDrawColour(const wxColour& colour)
2458 {
2459   wxPdfColour tempColour(colour);
2460   m_drawColour = tempColour;
2461   if (m_page > 0)
2462   {
2463     OutAscii(m_drawColour.GetColour(true));
2464   }
2465 }
2466 
2467 void
SetDrawColour(const unsigned char grayscale)2468 wxPdfDocument::SetDrawColour(const unsigned char grayscale)
2469 {
2470   wxPdfColour tempColour(grayscale);
2471   m_drawColour = tempColour;
2472   if (m_page > 0)
2473   {
2474     OutAscii(m_drawColour.GetColour(true));
2475   }
2476 }
2477 
2478 void
SetDrawColour(const unsigned char red,const unsigned char green,const unsigned char blue)2479 wxPdfDocument::SetDrawColour(const unsigned char red, const unsigned char green, const unsigned char blue)
2480 {
2481   SetDrawColour(wxColour(red, green, blue));
2482 }
2483 
2484 void
SetDrawColour(double cyan,double magenta,double yellow,double black)2485 wxPdfDocument::SetDrawColour(double cyan, double magenta, double yellow, double black)
2486 {
2487   SetDrawColour(wxPdfColour(cyan, magenta, yellow, black));
2488 }
2489 
2490 void
SetDrawColour(const wxPdfColour & colour)2491 wxPdfDocument::SetDrawColour(const wxPdfColour& colour)
2492 {
2493   m_drawColour = colour;
2494   if (m_page > 0)
2495   {
2496     OutAscii(m_drawColour.GetColour(true));
2497   }
2498 }
2499 
2500 void
SetDrawColour(const wxString & name,double tint)2501 wxPdfDocument::SetDrawColour(const wxString& name, double tint)
2502 {
2503   wxPdfSpotColourMap::iterator spotColour = (*m_spotColours).find(name);
2504   if (spotColour != (*m_spotColours).end())
2505   {
2506     wxPdfColour tempColour(*(spotColour->second), tint);
2507     m_drawColour = tempColour;
2508     if (m_page > 0)
2509     {
2510       OutAscii(m_drawColour.GetColour(true));
2511     }
2512   }
2513   else
2514   {
2515     wxLogError(wxString(wxS("wxPdfDocument::SetDrawColour: ")) +
2516                wxString::Format(_("Undefined spot colour: '%s'."), name.c_str()));
2517   }
2518 }
2519 
2520 void
SetDrawPattern(const wxString & name)2521 wxPdfDocument::SetDrawPattern(const wxString& name)
2522 {
2523   wxPdfPatternMap::iterator pattern = m_patterns->find(name);
2524   if (pattern != m_patterns->end())
2525   {
2526     wxPdfColour tempColour(*(pattern->second));
2527     m_drawColour = tempColour;
2528     if (m_page > 0)
2529     {
2530       OutAscii(m_drawColour.GetColour(true));
2531     }
2532   }
2533   else
2534   {
2535     wxLogError(wxString(wxS("wxPdfDocument::SetDrawPattern: ")) +
2536                wxString::Format(_("Undefined pattern: '%s'."), name.c_str()));
2537   }
2538 }
2539 
2540 const wxPdfColour
GetDrawColour()2541 wxPdfDocument::GetDrawColour()
2542 {
2543   return wxPdfColour(m_drawColour);
2544 }
2545 
2546 void
SetFillColour(const wxColour & colour)2547 wxPdfDocument::SetFillColour(const wxColour& colour)
2548 {
2549   wxPdfColour tempColour(colour);
2550   m_fillColour = tempColour;
2551   m_colourFlag = (m_fillColour != m_textColour);
2552   if (m_page > 0)
2553   {
2554     OutAscii(m_fillColour.GetColour(false));
2555   }
2556 }
2557 
2558 void
SetFillColour(const unsigned char grayscale)2559 wxPdfDocument::SetFillColour(const unsigned char grayscale)
2560 {
2561   wxPdfColour tempColour(grayscale);
2562   m_fillColour = tempColour;
2563   m_colourFlag = (m_fillColour != m_textColour);
2564   if (m_page > 0)
2565   {
2566     OutAscii(m_fillColour.GetColour(false));
2567   }
2568 }
2569 
2570 void
SetFillColour(const wxPdfColour & colour)2571 wxPdfDocument::SetFillColour(const wxPdfColour& colour)
2572 {
2573   m_fillColour = colour;
2574   m_colourFlag = (m_fillColour != m_textColour);
2575   if (m_page > 0)
2576   {
2577     OutAscii(m_fillColour.GetColour(false));
2578   }
2579 }
2580 
2581 void
SetFillColour(const unsigned char red,const unsigned char green,const unsigned char blue)2582 wxPdfDocument::SetFillColour(const unsigned char red, const unsigned char green, const unsigned char blue)
2583 {
2584   SetFillColour(wxColour(red, green, blue));
2585 }
2586 
2587 void
SetFillColour(double cyan,double magenta,double yellow,double black)2588 wxPdfDocument::SetFillColour(double cyan, double magenta, double yellow, double black)
2589 {
2590   SetFillColour(wxPdfColour(cyan, magenta, yellow, black));
2591 }
2592 
2593 void
SetFillColour(const wxString & name,double tint)2594 wxPdfDocument::SetFillColour(const wxString& name, double tint)
2595 {
2596   wxPdfSpotColourMap::iterator spotColour = (*m_spotColours).find(name);
2597   if (spotColour != (*m_spotColours).end())
2598   {
2599     wxPdfColour tempColour(*(spotColour->second), tint);
2600     m_fillColour = tempColour;
2601     m_colourFlag = (m_fillColour != m_textColour);
2602     if (m_page > 0)
2603     {
2604       OutAscii(m_fillColour.GetColour(false));
2605     }
2606   }
2607   else
2608   {
2609     wxLogError(wxString(wxS("wxPdfDocument::SetFillColour: ")) +
2610                wxString::Format(_("Undefined spot colour: '%s'."), name.c_str()));
2611   }
2612 }
2613 
2614 void
SetFillPattern(const wxString & name)2615 wxPdfDocument::SetFillPattern(const wxString& name)
2616 {
2617   wxPdfPatternMap::iterator pattern = m_patterns->find(name);
2618   if (pattern != m_patterns->end())
2619   {
2620     wxPdfColour tempColour(*(pattern->second));
2621     m_fillColour = tempColour;
2622     m_colourFlag = (m_fillColour != m_textColour);
2623     if (m_page > 0)
2624     {
2625       OutAscii(m_fillColour.GetColour(false));
2626     }
2627   }
2628   else
2629   {
2630     wxLogError(wxString(wxS("wxPdfDocument::SetFillPattern: ")) +
2631                wxString::Format(_("Undefined pattern: '%s'."), name.c_str()));
2632   }
2633 }
2634 
2635 const wxPdfColour
GetPatternColour(const wxString & name)2636 wxPdfDocument::GetPatternColour(const wxString& name)
2637 {
2638   wxPdfColour colour(0);
2639   wxPdfPatternMap::iterator pattern = m_patterns->find(name);
2640   if (pattern != m_patterns->end())
2641   {
2642     wxPdfColour tempColour(*(pattern->second));
2643     colour = tempColour;
2644   }
2645   else
2646   {
2647     wxLogError(wxString(wxS("wxPdfDocument::GetPatternColour: ")) +
2648                wxString::Format(_("Undefined pattern: '%s'."), name.c_str()));
2649   }
2650   return colour;
2651 }
2652 
2653 const wxPdfColour
GetFillColour()2654 wxPdfDocument::GetFillColour()
2655 {
2656   return wxPdfColour(m_fillColour);
2657 }
2658 
2659 void
SetTextColour(const wxColour & colour)2660 wxPdfDocument::SetTextColour(const wxColour& colour)
2661 {
2662   wxPdfColour tempColour(colour);
2663   m_textColour = tempColour;
2664   m_colourFlag = (m_fillColour != m_textColour);
2665 }
2666 
2667 void
SetTextColour(const unsigned char grayscale)2668 wxPdfDocument::SetTextColour(const unsigned char grayscale)
2669 {
2670   wxPdfColour tempColour(grayscale);
2671   m_textColour = tempColour;
2672   m_colourFlag = (m_fillColour != m_textColour);
2673 }
2674 
2675 void
SetTextColour(const wxPdfColour & colour)2676 wxPdfDocument::SetTextColour(const wxPdfColour& colour)
2677 {
2678   m_textColour = colour;
2679   m_colourFlag = (m_fillColour != m_textColour);
2680 }
2681 
2682 void
SetTextColour(const unsigned char red,const unsigned char green,const unsigned char blue)2683 wxPdfDocument::SetTextColour(const unsigned char red, const unsigned char green, const unsigned char blue)
2684 {
2685   SetTextColour(wxColour(red, green, blue));
2686 }
2687 
2688 void
SetTextColour(double cyan,double magenta,double yellow,double black)2689 wxPdfDocument::SetTextColour(double cyan, double magenta, double yellow, double black)
2690 {
2691   SetTextColour(wxPdfColour(cyan, magenta, yellow, black));
2692 }
2693 
2694 void
SetTextColour(const wxString & name,double tint)2695 wxPdfDocument::SetTextColour(const wxString& name, double tint)
2696 {
2697   wxPdfSpotColourMap::iterator spotColour = (*m_spotColours).find(name);
2698   if (spotColour != (*m_spotColours).end())
2699   {
2700     wxPdfColour tempColour(*(spotColour->second), tint);
2701     m_textColour = tempColour;
2702     m_colourFlag = (m_fillColour != m_textColour);
2703   }
2704   else
2705   {
2706     wxLogError(wxString(wxS("wxPdfDocument::SetTextColour: ")) +
2707                wxString::Format(_("Undefined spot colour: '%s'."), name.c_str()));
2708   }
2709 }
2710 
2711 void
SetTextPattern(const wxString & name)2712 wxPdfDocument::SetTextPattern(const wxString& name)
2713 {
2714   wxPdfPatternMap::iterator pattern = m_patterns->find(name);
2715   if (pattern != m_patterns->end())
2716   {
2717     wxPdfColour tempColour(*(pattern->second));
2718     m_textColour = tempColour;
2719     m_colourFlag = (m_fillColour != m_textColour);
2720   }
2721   else
2722   {
2723     wxLogError(wxString(wxS("wxPdfDocument::SetFillPattern: ")) +
2724                wxString::Format(_("Undefined pattern: '%s'."), name.c_str()));
2725   }
2726 }
2727 
2728 const wxPdfColour
GetTextColour()2729 wxPdfDocument::GetTextColour()
2730 {
2731   return wxPdfColour(m_textColour);
2732 }
2733 
2734 void
SetTextRenderMode(wxPdfTextRenderMode mode)2735 wxPdfDocument::SetTextRenderMode(wxPdfTextRenderMode mode)
2736 {
2737   m_textRenderMode = mode;
2738 }
2739 
2740 wxPdfTextRenderMode
GetTextRenderMode() const2741 wxPdfDocument::GetTextRenderMode() const
2742 {
2743   return m_textRenderMode;
2744 }
2745