Bug 502715 - Enable the canvas 2d context to function without an actual canvas element r=vladimir

This commit is contained in:
Rob Arnold 2009-08-04 14:36:02 -07:00
parent 5fdabd8af3
commit 1c601ecdaa
2 changed files with 78 additions and 51 deletions

View File

@ -62,6 +62,8 @@ public:
// whenever the size of the element changes.
NS_IMETHOD SetDimensions(PRInt32 width, PRInt32 height) = 0;
NS_IMETHOD InitializeWithSurface(nsIDocShell *docShell, gfxASurface *surface, PRInt32 width, PRInt32 height) = 0;
// Render the canvas at the origin of the given gfxContext
NS_IMETHOD Render(gfxContext *ctx, gfxPattern::GraphicsFilter aFilter) = 0;

View File

@ -20,6 +20,7 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Rob Arnold <tellrob@gmail.com>
* Eric Butler <zantifon@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
@ -316,6 +317,7 @@ public:
// nsICanvasRenderingContextInternal
NS_IMETHOD SetCanvasElement(nsICanvasElement* aParentCanvas);
NS_IMETHOD SetDimensions(PRInt32 width, PRInt32 height);
NS_IMETHOD InitializeWithSurface(nsIDocShell *shell, gfxASurface *surface, PRInt32 width, PRInt32 height);
NS_IMETHOD Render(gfxContext *ctx, gfxPattern::GraphicsFilter aFilter);
NS_IMETHOD GetInputStream(const char* aMimeType,
const PRUnichar* aEncoderOptions,
@ -361,6 +363,9 @@ protected:
// so these are not nsCOMPtrs
nsICanvasElement* mCanvasElement;
// If mCanvasElement is not provided, then a docshell is
nsCOMPtr<nsIDocShell> mDocShell;
// our CSS parser, for colors and whatnot
nsCOMPtr<nsICSSParser> mCSSParser;
@ -479,6 +484,20 @@ protected:
*/
nsresult DrawRect(const gfxRect& rect, Style style);
/**
* Gets the pres shell from either the canvas element or the doc shell
*/
nsIPresShell *GetPresShell() {
nsIPresShell *presShell = nsnull;
nsCOMPtr<nsIContent> content = do_QueryInterface(mCanvasElement);
if (content) {
presShell = content->GetOwnerDoc()->GetPrimaryShell();
} else if (mDocShell) {
mDocShell->GetPresShell(&presShell);
}
return presShell;
}
// text
enum TextAlign {
TEXT_ALIGN_START,
@ -613,17 +632,14 @@ protected:
PRUint32 devPixel = 60;
PRUint32 cssPixel = 60;
nsCOMPtr<nsINode> elem = do_QueryInterface(mCanvasElement);
if (elem) {
nsIDocument *doc = elem->GetOwnerDoc();
if (!doc) goto FINISH;
nsIPresShell *ps = doc->GetPrimaryShell();
if (!ps) goto FINISH;
nsPresContext *pc = ps->GetPresContext();
if (!pc) goto FINISH;
devPixel = pc->AppUnitsPerDevPixel();
cssPixel = pc->AppUnitsPerCSSPixel();
}
nsIPresShell *ps = GetPresShell();
nsPresContext *pc;
if (!ps) goto FINISH;
pc = ps->GetPresContext();
if (!pc) goto FINISH;
devPixel = pc->AppUnitsPerDevPixel();
cssPixel = pc->AppUnitsPerCSSPixel();
FINISH:
if (perDevPixel)
@ -795,12 +811,10 @@ nsCanvasRenderingContext2D::ApplyStyle(Style aWhichStyle,
nsCanvasPattern* pattern = CurrentState().patternStyles[aWhichStyle];
if (pattern) {
if (!mCanvasElement)
return;
CanvasUtils::DoDrawImageSecurityCheck(mCanvasElement,
pattern->Principal(),
pattern->GetForceWriteOnly());
if (mCanvasElement)
CanvasUtils::DoDrawImageSecurityCheck(mCanvasElement,
pattern->Principal(),
pattern->GetForceWriteOnly());
gfxPattern* gpat = pattern->GetPattern();
@ -859,8 +873,7 @@ nsCanvasRenderingContext2D::SetDimensions(PRInt32 width, PRInt32 height)
{
Destroy();
mWidth = width;
mHeight = height;
nsRefPtr<gfxASurface> surface;
// Check that the dimensions are sane
if (gfxASurface::CheckSurfaceSize(gfxIntSize(width, height), 0xffff)) {
@ -868,13 +881,28 @@ nsCanvasRenderingContext2D::SetDimensions(PRInt32 width, PRInt32 height)
if (mOpaque)
format = gfxASurface::ImageFormatRGB24;
mSurface = gfxPlatform::GetPlatform()->CreateOffscreenSurface
surface = gfxPlatform::GetPlatform()->CreateOffscreenSurface
(gfxIntSize(width, height), format);
if (mSurface->CairoStatus() == 0) {
mThebes = new gfxContext(mSurface);
if (surface->CairoStatus() != 0) {
surface = NULL;
}
}
return InitializeWithSurface(NULL, surface, width, height);
}
NS_IMETHODIMP
nsCanvasRenderingContext2D::InitializeWithSurface(nsIDocShell *docShell, gfxASurface *surface, PRInt32 width, PRInt32 height) {
Destroy();
NS_ASSERTION(!docShell ^ !mCanvasElement, "Cannot set both docshell and canvas element");
mDocShell = docShell;
mWidth = width;
mHeight = height;
mSurface = surface;
mThebes = new gfxContext(mSurface);
/* Create dummy surfaces here */
if (mSurface == nsnull || mSurface->CairoStatus() != 0 ||
@ -886,6 +914,11 @@ nsCanvasRenderingContext2D::SetDimensions(PRInt32 width, PRInt32 height)
mValid = PR_TRUE;
}
// set up our css parser, if necessary
if (!mCSSParser) {
mCSSParser = do_CreateInstance("@mozilla.org/content/css-parser;1");
}
// set up the initial canvas defaults
mStyleStack.Clear();
mSaveCount = 0;
@ -1032,11 +1065,6 @@ nsCanvasRenderingContext2D::SetCanvasElement(nsICanvasElement* aCanvasElement)
// don't hold a ref to this!
mCanvasElement = aCanvasElement;
// set up our css parser, if necessary
if (!mCSSParser) {
mCSSParser = do_CreateInstance("@mozilla.org/content/css-parser;1");
}
return NS_OK;
}
@ -1870,16 +1898,15 @@ nsCanvasRenderingContext2D::SetFont(const nsAString& font)
*/
nsCOMPtr<nsIContent> content = do_QueryInterface(mCanvasElement);
if (!content) {
NS_WARNING("Canvas element must be an nsIContent and non-null");
if (!content && !mDocShell) {
NS_WARNING("Canvas element must be an nsIContent and non-null or a docshell must be provided");
return NS_ERROR_FAILURE;
}
nsIDocument* document = content->GetOwnerDoc();
nsIPresShell* presShell = document->GetPrimaryShell();
nsIPresShell* presShell = GetPresShell();
if (!presShell)
return NS_ERROR_FAILURE;
return NS_ERROR_FAILURE;
nsIDocument* document = presShell->GetDocument();
nsCString langGroup;
presShell->GetPresContext()->GetLangGroup()->ToUTF8String(langGroup);
@ -1887,7 +1914,7 @@ nsCanvasRenderingContext2D::SetFont(const nsAString& font)
nsCOMArray<nsIStyleRule> rules;
nsCOMPtr<nsICSSStyleRule> rule;
rv = CreateFontStyleRule(font, mCSSParser.get(), content.get(), getter_AddRefs(rule));
rv = CreateFontStyleRule(font, mCSSParser.get(), document, getter_AddRefs(rule));
if (NS_FAILED(rv))
return rv;
@ -1899,7 +1926,7 @@ nsCanvasRenderingContext2D::SetFont(const nsAString& font)
// values (2em, bolder, etc.)
nsRefPtr<nsStyleContext> parentContext;
if (content->IsInDoc()) {
if (content && content->IsInDoc()) {
// inherit from the canvas element
parentContext = nsInspectorCSSUtils::GetStyleContextForContent(
content,
@ -1910,7 +1937,7 @@ nsCanvasRenderingContext2D::SetFont(const nsAString& font)
nsCOMPtr<nsICSSStyleRule> parentRule;
rv = CreateFontStyleRule(NS_LITERAL_STRING("10px sans-serif"),
mCSSParser.get(),
content.get(),
document,
getter_AddRefs(parentRule));
if (NS_FAILED(rv))
return rv;
@ -2219,17 +2246,17 @@ nsCanvasRenderingContext2D::DrawOrMeasureText(const nsAString& aRawText,
return NS_ERROR_INVALID_ARG;
nsCOMPtr<nsIContent> content = do_QueryInterface(mCanvasElement);
if (!content) {
NS_WARNING("Canvas element must be an nsIContent and non-null");
if (!content && !mDocShell) {
NS_WARNING("Canvas element must be an nsIContent and non-null or a docshell must be provided");
return NS_ERROR_FAILURE;
}
nsIDocument* document = content->GetOwnerDoc();
nsIPresShell* presShell = document->GetPrimaryShell();
nsIPresShell* presShell = GetPresShell();
if (!presShell)
return NS_ERROR_FAILURE;
nsIDocument* document = presShell->GetDocument();
nsBidiPresUtils* bidiUtils = presShell->GetPresContext()->GetBidiUtils();
if (!bidiUtils)
return NS_ERROR_FAILURE;
@ -2241,7 +2268,7 @@ nsCanvasRenderingContext2D::DrawOrMeasureText(const nsAString& aRawText,
// for now, default to ltr if not in doc
PRBool isRTL = PR_FALSE;
if (content->IsInDoc()) {
if (content && content->IsInDoc()) {
// try to find the closest context
nsRefPtr<nsStyleContext> canvasStyle =
nsInspectorCSSUtils::GetStyleContextForContent(content,
@ -2251,6 +2278,8 @@ nsCanvasRenderingContext2D::DrawOrMeasureText(const nsAString& aRawText,
return NS_ERROR_FAILURE;
isRTL = canvasStyle->GetStyleVisibility()->mDirection ==
NS_STYLE_DIRECTION_RTL;
} else {
isRTL = GET_BIDI_OPTION_DIRECTION(document->GetBidiOptions()) == IBMBIDI_TEXTDIRECTION_RTL;
}
// don't need to take care of these with stroke since Stroke() does that
@ -2896,11 +2925,6 @@ nsCanvasRenderingContext2D::DrawImage()
nsresult rv;
gfxRect dirty;
// we can't do a security check without a canvas element, so
// just skip this entirely
if (!mCanvasElement)
return NS_ERROR_FAILURE;
nsAXPCNativeCallContext *ncc = nsnull;
rv = nsContentUtils::XPConnect()->
GetCurrentNativeCallContext(&ncc);
@ -2959,7 +2983,8 @@ nsCanvasRenderingContext2D::DrawImage()
gfxIntSize imgSize = res.mSize;
PRBool forceWriteOnly = res.mIsWriteOnly;
CanvasUtils::DoDrawImageSecurityCheck(mCanvasElement, principal, forceWriteOnly);
if (mCanvasElement)
CanvasUtils::DoDrawImageSecurityCheck(mCanvasElement, principal, forceWriteOnly);
gfxContextPathAutoSaveRestore pathSR(mThebes, PR_FALSE);
@ -3369,10 +3394,10 @@ nsCanvasRenderingContext2D::DrawWindow(nsIDOMWindow* aWindow, float aX, float aY
NS_IMETHODIMP
nsCanvasRenderingContext2D::GetImageData()
{
if (!mValid || !mCanvasElement)
if (!mValid)
return NS_ERROR_FAILURE;
if (mCanvasElement->IsWriteOnly() && !nsContentUtils::IsCallerTrustedForRead()) {
if (mCanvasElement && mCanvasElement->IsWriteOnly() && !nsContentUtils::IsCallerTrustedForRead()) {
// XXX ERRMSG we need to report an error to developers here! (bug 329026)
return NS_ERROR_DOM_SECURITY_ERR;
}
@ -3727,7 +3752,7 @@ nsCanvasRenderingContext2D::GetThebesSurface(gfxASurface **surface)
NS_IMETHODIMP
nsCanvasRenderingContext2D::CreateImageData()
{
if (!mValid || !mCanvasElement)
if (!mValid)
return NS_ERROR_FAILURE;
nsAXPCNativeCallContext *ncc = nsnull;