/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef MOZILLA_GFX_PRINTTARGET_H #define MOZILLA_GFX_PRINTTARGET_H #include "mozilla/RefPtr.h" #include "mozilla/gfx/2D.h" #include "nsISupportsImpl.h" #include "nsStringFwd.h" namespace mozilla { namespace gfx { class DrawEventRecorder; /** * A class that is used to draw output that is to be sent to a printer or print * preview. * * This class wraps a cairo_surface_t* and provides access to it via a * DrawTarget. The various checkpointing methods manage the state of the * platform specific cairo_surface_t*. */ class PrintTarget { public: NS_INLINE_DECL_REFCOUNTING(PrintTarget); /// Must be matched 1:1 by an EndPrinting/AbortPrinting call. virtual nsresult BeginPrinting(const nsAString& aTitle, const nsAString& aPrintToFileName, int32_t aStartPage, int32_t aEndPage) { return NS_OK; } virtual nsresult EndPrinting() { return NS_OK; } virtual nsresult AbortPrinting() { #ifdef DEBUG mHasActivePage = false; #endif return NS_OK; } virtual nsresult BeginPage() { #ifdef DEBUG MOZ_ASSERT(!mHasActivePage, "Missing EndPage() call"); mHasActivePage = true; #endif return NS_OK; } virtual nsresult EndPage() { #ifdef DEBUG mHasActivePage = false; #endif return NS_OK; } /** * Releases the resources used by this PrintTarget. Typically this should be * called after calling EndPrinting(). Calling this more than once is * allowed, but subsequent calls are a no-op. * * Note that any DrawTarget obtained from this PrintTarget will no longer be * useful after this method has been called. */ virtual void Finish(); /** * Returns true if to print landscape our consumers must apply a 90 degrees * rotation to our DrawTarget. */ virtual bool RotateNeededForLandscape() const { return false; } const IntSize& GetSize() const { return mSize; } /** * Makes a DrawTarget to draw the printer output to, or returns null on * failure. * * If aRecorder is passed a recording DrawTarget will be created instead of * the type of DrawTarget that would normally be returned for a particular * subclass of this class. This argument is only intended to be used in * the e10s content process if printing output can't otherwise be transfered * over to the parent process using the normal DrawTarget type. * * NOTE: this should only be called between BeginPage()/EndPage() calls, and * the returned DrawTarget should not be drawn to after EndPage() has been * called. * * XXX For consistency with the old code this takes a size parameter even * though we already have the size passed to our subclass's CreateOrNull * factory methods. The size passed to the factory method comes from * nsIDeviceContextSpec::MakePrintTarget overrides, whereas the size * passed to us comes from nsDeviceContext::CreateRenderingContext. In at * least one case (nsDeviceContextSpecAndroid::MakePrintTarget) these are * different. At some point we should align the two sources and get rid of * this method's size parameter. * * XXX For consistency with the old code this returns a new DrawTarget for * each call. Perhaps we can create and cache a DrawTarget in our subclass's * CreateOrNull factory methods and return that on each call? Currently that * seems to cause Mochitest failures on Windows though, which coincidentally * is the only platform where we get passed an aRecorder. Probably the * issue is that we get called more than once with a different aRecorder, so * storing one recording DrawTarget for our lifetime doesn't currently work. * * XXX Could we pass aRecorder to our subclass's CreateOrNull factory methods? * We'd need to check that our consumers always pass the same aRecorder for * our entire lifetime. * * XXX Once PrintTargetThebes is removed this can become non-virtual. * * XXX In the long run, this class and its sub-classes should be converted to * use STL classes and mozilla::RefCounted<> so the can be moved to Moz2D. * * TODO: Consider adding a SetDPI method that calls * cairo_surface_set_fallback_resolution. */ virtual already_AddRefed MakeDrawTarget(const IntSize& aSize, DrawEventRecorder* aRecorder = nullptr); /** * Returns a reference DrawTarget. Unlike MakeDrawTarget, this method is not * restricted to being called between BeginPage()/EndPage() calls, and the * returned DrawTarget it is still valid to use after EndPage() has been * called. */ virtual already_AddRefed GetReferenceDrawTarget(DrawEventRecorder* aRecorder); protected: // Only created via subclass's constructors explicit PrintTarget(cairo_surface_t* aCairoSurface, const IntSize& aSize); // Protected because we're refcounted virtual ~PrintTarget(); static already_AddRefed CreateWrapAndRecordDrawTarget(DrawEventRecorder* aRecorder, DrawTarget* aDrawTarget); cairo_surface_t* mCairoSurface; RefPtr mRefDT; // reference DT // Early on during printing we expect to be called without a recorder in // order to gather metrics for reflow. However, in a content process, once // we go on to paint we then expect to be called with a recorder. Hence why // we have this separate recording reference DrawTarget (which wraps mRefDT). RefPtr mRecordingRefDT; IntSize mSize; bool mIsFinished; #ifdef DEBUG bool mHasActivePage; // owned by mRecordingRefDT, so kept alive for our entire lifetime if set: DrawEventRecorder* mRecorder; #endif }; } // namespace gfx } // namespace mozilla #endif /* MOZILLA_GFX_PRINTTARGET_H */