Bug 745025 - Part 1 - Adds mozPrintCallback for canvas. r=smaug

This commit is contained in:
Brendan Dahl 2012-08-31 10:45:45 -07:00
parent 1bc80d0294
commit 3f688bb97f
8 changed files with 237 additions and 6 deletions

View File

@ -1413,7 +1413,9 @@ nsCanvasRenderingContext2D::GetImageFormat() const
NS_IMETHODIMP
nsCanvasRenderingContext2D::GetCanvas(nsIDOMHTMLCanvasElement **canvas)
{
NS_IF_ADDREF(*canvas = mCanvasElement);
if (mCanvasElement) {
NS_IF_ADDREF(*canvas = mCanvasElement->GetOriginalCanvas());
}
return NS_OK;
}

View File

@ -1124,7 +1124,9 @@ nsCanvasRenderingContext2DAzure::GetSurfaceFormat() const
NS_IMETHODIMP
nsCanvasRenderingContext2DAzure::GetCanvas(nsIDOMHTMLCanvasElement **canvas)
{
NS_IF_ADDREF(*canvas = GetCanvas());
if (mCanvasElement) {
NS_IF_ADDREF(*canvas = mCanvasElement->GetOriginalCanvas());
}
return NS_OK;
}

View File

@ -18,6 +18,8 @@
class nsICanvasRenderingContextInternal;
class nsIDOMFile;
class nsHTMLCanvasPrintState;
class nsITimerCallback;
class nsIPropertyBag;
namespace mozilla {
@ -168,9 +170,13 @@ protected:
nsresult GetContextHelper(const nsAString& aContextId,
bool aForceThebes,
nsICanvasRenderingContextInternal **aContext);
void CallPrintCallback();
nsString mCurrentContextId;
nsCOMPtr<nsIDOMHTMLCanvasElement> mOriginalCanvas;
nsCOMPtr<nsIPrintCallback> mPrintCallback;
nsCOMPtr<nsICanvasRenderingContextInternal> mCurrentContext;
nsCOMPtr<nsHTMLCanvasPrintState> mPrintState;
public:
// Record whether this canvas should be write-only or not.
@ -178,6 +184,16 @@ public:
// We also transitively set it when script paints a canvas which
// is itself write-only.
bool mWriteOnly;
bool IsPrintCallbackDone();
void HandlePrintCallback(nsPresContext::nsPresContextType aType);
nsresult DispatchPrintCallback(nsITimerCallback* aCallback);
void ResetPrintCallback();
nsIDOMHTMLCanvasElement* GetOriginalCanvas();
};
inline nsISupports*

View File

@ -28,6 +28,8 @@
#include "nsDisplayList.h"
#include "BasicLayers.h"
#include "imgIEncoder.h"
#include "nsITimer.h"
#include "nsAsyncDOMEvent.h"
#include "nsIWritablePropertyBag2.h"
@ -38,6 +40,91 @@ using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::layers;
class nsHTMLCanvasPrintState : public nsIDOMMozCanvasPrintState
{
public:
nsHTMLCanvasPrintState(nsHTMLCanvasElement* aCanvas,
nsICanvasRenderingContextInternal* aContext,
nsITimerCallback* aCallback)
: mIsDone(false), mPendingNotify(false), mCanvas(aCanvas),
mContext(aContext), mCallback(aCallback)
{
}
NS_IMETHOD GetContext(nsISupports** aContext)
{
NS_ADDREF(*aContext = mContext);
return NS_OK;
}
NS_IMETHOD Done()
{
if (!mPendingNotify && !mIsDone) {
// The canvas needs to be invalidated for printing reftests on linux to
// work.
if (mCanvas) {
mCanvas->InvalidateCanvas();
}
nsRefPtr<nsRunnableMethod<nsHTMLCanvasPrintState> > doneEvent =
NS_NewRunnableMethod(this, &nsHTMLCanvasPrintState::NotifyDone);
if (NS_SUCCEEDED(NS_DispatchToCurrentThread(doneEvent))) {
mPendingNotify = true;
}
}
return NS_OK;
}
void NotifyDone()
{
mIsDone = true;
mPendingNotify = false;
if (mCallback) {
mCallback->Notify(nullptr);
}
}
bool mIsDone;
// CC
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS(nsHTMLCanvasPrintState)
private:
virtual ~nsHTMLCanvasPrintState()
{
}
bool mPendingNotify;
protected:
nsRefPtr<nsHTMLCanvasElement> mCanvas;
nsCOMPtr<nsICanvasRenderingContextInternal> mContext;
nsCOMPtr<nsITimerCallback> mCallback;
};
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsHTMLCanvasPrintState)
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsHTMLCanvasPrintState)
DOMCI_DATA(MozCanvasPrintState, nsHTMLCanvasPrintState)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsHTMLCanvasPrintState)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_ENTRY(nsIDOMMozCanvasPrintState)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MozCanvasPrintState)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTION_CLASS(nsHTMLCanvasPrintState)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsHTMLCanvasPrintState)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mCanvas, nsIDOMHTMLCanvasElement)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mContext)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mCallback)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsHTMLCanvasPrintState)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mCanvas)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mContext)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mCallback)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
// ---------------------------------------------------------------------------
nsGenericHTMLElement*
NS_NewHTMLCanvasElement(already_AddRefed<nsINodeInfo> aNodeInfo,
FromParser aFromParser)
@ -46,23 +133,31 @@ NS_NewHTMLCanvasElement(already_AddRefed<nsINodeInfo> aNodeInfo,
}
nsHTMLCanvasElement::nsHTMLCanvasElement(already_AddRefed<nsINodeInfo> aNodeInfo)
: nsGenericHTMLElement(aNodeInfo), mWriteOnly(false)
: nsGenericHTMLElement(aNodeInfo),
mWriteOnly(false)
{
}
nsHTMLCanvasElement::~nsHTMLCanvasElement()
{
ResetPrintCallback();
}
NS_IMPL_CYCLE_COLLECTION_CLASS(nsHTMLCanvasElement)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsHTMLCanvasElement,
nsGenericHTMLElement)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mCurrentContext)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mPrintCallback)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mPrintState)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOriginalCanvas)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsHTMLCanvasElement,
nsGenericHTMLElement)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mCurrentContext)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mPrintCallback)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mPrintState)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOriginalCanvas)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_ADDREF_INHERITED(nsHTMLCanvasElement, nsGenericElement)
@ -122,6 +217,74 @@ nsHTMLCanvasElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
return rv;
}
void
nsHTMLCanvasElement::HandlePrintCallback(nsPresContext::nsPresContextType aType)
{
// Only call the print callback here if 1) we're in a print testing mode or
// print preview mode, 2) the canvas has a print callback and 3) the callback
// hasn't already been called. For real printing the callback is handled in
// nsSimplePageSequenceFrame::PrePrintNextPage.
nsCOMPtr<nsIPrintCallback> printCallback;
if ((aType == nsPresContext::eContext_PageLayout ||
aType == nsPresContext::eContext_PrintPreview) &&
!mPrintState &&
NS_SUCCEEDED(GetMozPrintCallback(getter_AddRefs(printCallback))) && printCallback) {
DispatchPrintCallback(nullptr);
}
}
nsresult
nsHTMLCanvasElement::DispatchPrintCallback(nsITimerCallback* aCallback)
{
// For print reftests the context may not be initialized yet, so get a context
// so mCurrentContext is set.
if (!mCurrentContext) {
nsresult rv;
nsCOMPtr<nsISupports> context;
rv = GetContext(NS_LITERAL_STRING("2d"), JSVAL_VOID,
getter_AddRefs(context));
NS_ENSURE_SUCCESS(rv, rv);
}
mPrintState = new nsHTMLCanvasPrintState(this, mCurrentContext, aCallback);
nsRefPtr<nsRunnableMethod<nsHTMLCanvasElement> > renderEvent =
NS_NewRunnableMethod(this, &nsHTMLCanvasElement::CallPrintCallback);
return NS_DispatchToCurrentThread(renderEvent);
}
void
nsHTMLCanvasElement::CallPrintCallback()
{
nsCOMPtr<nsIPrintCallback> printCallback;
GetMozPrintCallback(getter_AddRefs(printCallback));
printCallback->Render(mPrintState);
}
void
nsHTMLCanvasElement::ResetPrintCallback()
{
if (mPrintState) {
mPrintState = nullptr;
}
}
bool
nsHTMLCanvasElement::IsPrintCallbackDone()
{
if (mPrintState == nullptr) {
return true;
}
return mPrintState->mIsDone;
}
nsIDOMHTMLCanvasElement*
nsHTMLCanvasElement::GetOriginalCanvas()
{
return mOriginalCanvas ? mOriginalCanvas.get() : this;
}
nsresult
nsHTMLCanvasElement::CopyInnerTo(nsGenericElement* aDest)
{
@ -129,11 +292,14 @@ nsHTMLCanvasElement::CopyInnerTo(nsGenericElement* aDest)
NS_ENSURE_SUCCESS(rv, rv);
if (aDest->OwnerDoc()->IsStaticDocument()) {
nsHTMLCanvasElement* dest = static_cast<nsHTMLCanvasElement*>(aDest);
nsHTMLCanvasElement* self = const_cast<nsHTMLCanvasElement*>(this);
dest->mOriginalCanvas = self;
nsCOMPtr<nsISupports> cxt;
dest->GetContext(NS_LITERAL_STRING("2d"), JSVAL_VOID, getter_AddRefs(cxt));
nsCOMPtr<nsIDOMCanvasRenderingContext2D> context2d = do_QueryInterface(cxt);
if (context2d) {
context2d->DrawImage(const_cast<nsHTMLCanvasElement*>(this),
if (context2d && !self->mPrintCallback) {
context2d->DrawImage(self,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0);
}
}
@ -217,6 +383,24 @@ nsHTMLCanvasElement::MozFetchAsStream(nsIInputStreamCallback *aCallback,
return asyncCallback->OnInputStreamReady(asyncData);
}
NS_IMETHODIMP
nsHTMLCanvasElement::SetMozPrintCallback(nsIPrintCallback *aCallback)
{
mPrintCallback = aCallback;
return NS_OK;
}
NS_IMETHODIMP
nsHTMLCanvasElement::GetMozPrintCallback(nsIPrintCallback** aCallback)
{
if (mOriginalCanvas) {
mOriginalCanvas->GetMozPrintCallback(aCallback);
return NS_OK;
}
NS_IF_ADDREF(*aCallback = mPrintCallback);
return NS_OK;
}
nsresult
nsHTMLCanvasElement::ExtractData(const nsAString& aType,
const nsAString& aOptions,

View File

@ -1346,6 +1346,8 @@ static nsDOMClassInfoData sClassInfoData[] = {
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(ImageData, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(MozCanvasPrintState, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(SmartCardEvent, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
@ -3926,6 +3928,10 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_ENTRY(nsIDOMImageData)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(MozCanvasPrintState, nsIDOMMozCanvasPrintState)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozCanvasPrintState)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(XSLTProcessor, nsIXSLTProcessor)
DOM_CLASSINFO_MAP_ENTRY(nsIXSLTProcessor)
DOM_CLASSINFO_MAP_ENTRY(nsIXSLTProcessorPrivate)

View File

@ -322,6 +322,7 @@ DOMCI_CLASS(CanvasGradient)
DOMCI_CLASS(CanvasPattern)
DOMCI_CLASS(TextMetrics)
DOMCI_CLASS(ImageData)
DOMCI_CLASS(MozCanvasPrintState)
// SmartCard Events
DOMCI_CLASS(SmartCardEvent)

View File

@ -24,7 +24,23 @@ interface nsIDOMFile;
interface nsIVariant;
interface nsIInputStreamCallback;
[scriptable, uuid(5929542B-C68E-48AB-84F9-D9642DA39720)]
[scriptable, builtinclass, uuid(8d5fb8a0-7782-11e1-b0c4-0800200c9a67)]
interface nsIDOMMozCanvasPrintState : nsISupports
{
// A canvas rendering context.
readonly attribute nsISupports context;
// To be called when rendering to the context is done.
void done();
};
[scriptable, function, uuid(8d5fb8a0-7782-11e1-b0c4-0800200c9a66)]
interface nsIPrintCallback : nsISupports
{
void render(in nsIDOMMozCanvasPrintState ctx);
};
[scriptable, uuid(a7062fca-41c6-4520-b777-3bb30fd77273)]
interface nsIDOMHTMLCanvasElement : nsIDOMHTMLElement
{
attribute unsigned long width;
@ -56,5 +72,8 @@ interface nsIDOMHTMLCanvasElement : nsIDOMHTMLElement
// stream in the desired image format.
void mozFetchAsStream(in nsIInputStreamCallback callback,
[optional] in DOMString type);
// A Mozilla-only callback that is called during the printing process.
attribute nsIPrintCallback mozPrintCallback;
};

View File

@ -530,6 +530,7 @@ var interfaceNamesInGlobalScope =
"CameraManager",
"CSSSupportsRule",
"MozMobileCellInfo",
"MozCanvasPrintState",
"TCPSocket"
]