1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2  * This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #ifndef MOZILLA_GFX_PRINTTARGET_H
7 #define MOZILLA_GFX_PRINTTARGET_H
8 
9 #include <functional>
10 
11 #include "mozilla/RefPtr.h"
12 #include "mozilla/gfx/2D.h"
13 #include "nsISupportsImpl.h"
14 #include "nsStringFwd.h"
15 
16 namespace mozilla {
17 namespace gfx {
18 
19 class DrawEventRecorder;
20 
21 /**
22  * A class that is used to draw output that is to be sent to a printer or print
23  * preview.
24  *
25  * This class wraps a cairo_surface_t* and provides access to it via a
26  * DrawTarget.  The various checkpointing methods manage the state of the
27  * platform specific cairo_surface_t*.
28  */
29 class PrintTarget {
30  public:
31   NS_INLINE_DECL_REFCOUNTING(PrintTarget);
32 
33   /// Must be matched 1:1 by an EndPrinting/AbortPrinting call.
BeginPrinting(const nsAString & aTitle,const nsAString & aPrintToFileName,int32_t aStartPage,int32_t aEndPage)34   virtual nsresult BeginPrinting(const nsAString& aTitle,
35                                  const nsAString& aPrintToFileName,
36                                  int32_t aStartPage, int32_t aEndPage) {
37     return NS_OK;
38   }
EndPrinting()39   virtual nsresult EndPrinting() { return NS_OK; }
AbortPrinting()40   virtual nsresult AbortPrinting() {
41 #ifdef DEBUG
42     mHasActivePage = false;
43 #endif
44     return NS_OK;
45   }
BeginPage()46   virtual nsresult BeginPage() {
47 #ifdef DEBUG
48     MOZ_ASSERT(!mHasActivePage, "Missing EndPage() call");
49     mHasActivePage = true;
50 #endif
51     return NS_OK;
52   }
EndPage()53   virtual nsresult EndPage() {
54 #ifdef DEBUG
55     mHasActivePage = false;
56 #endif
57     return NS_OK;
58   }
59 
60   /**
61    * Releases the resources used by this PrintTarget.  Typically this should be
62    * called after calling EndPrinting().  Calling this more than once is
63    * allowed, but subsequent calls are a no-op.
64    *
65    * Note that any DrawTarget obtained from this PrintTarget will no longer be
66    * useful after this method has been called.
67    */
68   virtual void Finish();
69 
70   /**
71    * Returns true if to print landscape our consumers must apply a 90 degrees
72    * rotation to our DrawTarget.
73    */
RotateNeededForLandscape()74   virtual bool RotateNeededForLandscape() const { return false; }
75 
GetSize()76   const IntSize& GetSize() const { return mSize; }
77 
78   /**
79    * Makes a DrawTarget to draw the printer output to, or returns null on
80    * failure.
81    *
82    * If aRecorder is passed a recording DrawTarget will be created instead of
83    * the type of DrawTarget that would normally be returned for a particular
84    * subclass of this class.  This argument is only intended to be used in
85    * the e10s content process if printing output can't otherwise be transfered
86    * over to the parent process using the normal DrawTarget type.
87    *
88    * NOTE: this should only be called between BeginPage()/EndPage() calls, and
89    * the returned DrawTarget should not be drawn to after EndPage() has been
90    * called.
91    *
92    * XXX For consistency with the old code this takes a size parameter even
93    * though we already have the size passed to our subclass's CreateOrNull
94    * factory methods.  The size passed to the factory method comes from
95    * nsIDeviceContextSpec::MakePrintTarget overrides, whereas the size
96    * passed to us comes from nsDeviceContext::CreateRenderingContext.  In at
97    * least one case (nsDeviceContextSpecAndroid::MakePrintTarget) these are
98    * different.  At some point we should align the two sources and get rid of
99    * this method's size parameter.
100    *
101    * XXX For consistency with the old code this returns a new DrawTarget for
102    * each call.  Perhaps we can create and cache a DrawTarget in our subclass's
103    * CreateOrNull factory methods and return that on each call?  Currently that
104    * seems to cause Mochitest failures on Windows though, which coincidentally
105    * is the only platform where we get passed an aRecorder.  Probably the
106    * issue is that we get called more than once with a different aRecorder, so
107    * storing one recording DrawTarget for our lifetime doesn't currently work.
108    *
109    * XXX Could we pass aRecorder to our subclass's CreateOrNull factory methods?
110    * We'd need to check that our consumers always pass the same aRecorder for
111    * our entire lifetime.
112    *
113    * XXX Once PrintTargetThebes is removed this can become non-virtual.
114    *
115    * XXX In the long run, this class and its sub-classes should be converted to
116    * use STL classes and mozilla::RefCounted<> so the can be moved to Moz2D.
117    *
118    * TODO: Consider adding a SetDPI method that calls
119    * cairo_surface_set_fallback_resolution.
120    */
121   virtual already_AddRefed<DrawTarget> MakeDrawTarget(
122       const IntSize& aSize, DrawEventRecorder* aRecorder = nullptr);
123 
124   /**
125    * Returns a reference DrawTarget. Unlike MakeDrawTarget, this method is not
126    * restricted to being called between BeginPage()/EndPage() calls, and the
127    * returned DrawTarget is still valid to use after EndPage() has been called.
128    */
129   virtual already_AddRefed<DrawTarget> GetReferenceDrawTarget();
130 
131   static void AdjustPrintJobNameForIPP(const nsAString& aJobName,
132                                        nsCString& aAdjustedJobName);
133   static void AdjustPrintJobNameForIPP(const nsAString& aJobName,
134                                        nsString& aAdjustedJobName);
135 
136  protected:
137   // Only created via subclass's constructors
138   explicit PrintTarget(cairo_surface_t* aCairoSurface, const IntSize& aSize);
139 
140   // Protected because we're refcounted
141   virtual ~PrintTarget();
142 
143   static already_AddRefed<DrawTarget> CreateRecordingDrawTarget(
144       DrawEventRecorder* aRecorder, DrawTarget* aDrawTarget);
145 
146   cairo_surface_t* mCairoSurface;
147   RefPtr<DrawTarget> mRefDT;  // reference DT
148 
149   IntSize mSize;
150   bool mIsFinished;
151 #ifdef DEBUG
152   bool mHasActivePage;
153 #endif
154 };
155 
156 }  // namespace gfx
157 }  // namespace mozilla
158 
159 #endif /* MOZILLA_GFX_PRINTTARGET_H */
160