From 99efffd5fc95c9d6006a9e7823e8eda0c3ed6682 Mon Sep 17 00:00:00 2001 From: "vladimir%pobox.com" Date: Sat, 7 May 2005 03:45:06 +0000 Subject: [PATCH] b=291216, canvas should not be an empty element, default width/height, fallback content should not be rendered, r+sr=bzbarsky, a=brendan/shaver git-svn-id: svn://10.0.0.236/trunk@173165 18797224-902f-48f8-a5cc-f745e15eee43 --- .../html/content/src/nsHTMLCanvasElement.cpp | 107 ++++++---------- mozilla/layout/base/nsCSSFrameConstructor.cpp | 13 +- mozilla/layout/generic/nsHTMLCanvasFrame.cpp | 120 +++++++++++------- mozilla/layout/generic/nsHTMLCanvasFrame.h | 9 +- mozilla/layout/style/html.css | 8 +- .../parser/htmlparser/src/nsElementTable.cpp | 4 +- 6 files changed, 133 insertions(+), 128 deletions(-) diff --git a/mozilla/content/html/content/src/nsHTMLCanvasElement.cpp b/mozilla/content/html/content/src/nsHTMLCanvasElement.cpp index f8b988d6065..2d0470e1e80 100644 --- a/mozilla/content/html/content/src/nsHTMLCanvasElement.cpp +++ b/mozilla/content/html/content/src/nsHTMLCanvasElement.cpp @@ -53,6 +53,9 @@ #include "nsICanvasRenderingContextInternal.h" +#define DEFAULT_CANVAS_WIDTH 300 +#define DEFAULT_CANVAS_HEIGHT 200 + class nsHTMLCanvasElement : public nsGenericHTMLElement, public nsIDOMHTMLCanvasElement, public nsICanvasElement @@ -83,6 +86,7 @@ public: NS_IMETHOD_(PRBool) IsAttributeMapped(const nsIAtom* aAttribute) const; nsMapRuleToAttributesFunc GetAttributeMappingFunction() const; PRBool ParseAttribute(nsIAtom* aAttribute, const nsAString& aValue, nsAttrValue& aResult); + nsChangeHint GetAttributeChangeHint(const nsIAtom* aAttribute, PRInt32 aModType) const; // SetAttr override. C++ is stupid, so have to override both // overloaded methods. @@ -94,11 +98,8 @@ public: virtual nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, nsIAtom* aPrefix, const nsAString& aValue, PRBool aNotify); - - nsChangeHint GetAttributeChangeHint(const nsIAtom* aAttribute, - PRInt32 aModType) const; protected: - nsSize GetWidthHeight(); + nsIntSize GetWidthHeight(); nsresult UpdateImageContainer(); nsresult UpdateContext(); @@ -135,63 +136,35 @@ NS_HTML_CONTENT_INTERFACE_MAP_END NS_IMPL_DOM_CLONENODE(nsHTMLCanvasElement) -nsSize +nsIntSize nsHTMLCanvasElement::GetWidthHeight() { - nsSize size(0,0); + nsIntSize size(0,0); const nsAttrValue* value; PRInt32 k, rv; - if ((value = GetParsedAttr(nsHTMLAtoms::width))) { - if (value->Type() == nsAttrValue::eInteger) { + if ((value = GetParsedAttr(nsHTMLAtoms::width)) && + value->Type() == nsAttrValue::eInteger) + { size.width = value->GetIntegerValue(); - } else if (value->Type() == nsAttrValue::eString) { - k = value->GetStringValue().ToInteger(&rv); - if (NS_SUCCEEDED(rv)) - size.width = k; - } } - if ((value = GetParsedAttr(nsHTMLAtoms::height))) { - if (value->Type() == nsAttrValue::eInteger) { + if ((value = GetParsedAttr(nsHTMLAtoms::height)) && + value->Type() == nsAttrValue::eInteger) + { size.height = value->GetIntegerValue(); - } else if (value->Type() == nsAttrValue::eString) { - k = value->GetStringValue().ToInteger(&rv); - if (NS_SUCCEEDED(rv)) - size.height = k; - } } + if (size.width <= 0) + size.width = DEFAULT_CANVAS_WIDTH; + if (size.height <= 0) + size.height = DEFAULT_CANVAS_HEIGHT; + return size; } -NS_IMETHODIMP -nsHTMLCanvasElement::GetHeight(PRInt32* aHeight) -{ - *aHeight = GetWidthHeight().height; - - return NS_OK; -} - -NS_IMETHODIMP -nsHTMLCanvasElement::SetHeight(PRInt32 aHeight) -{ - return nsGenericHTMLElement::SetIntAttr(nsHTMLAtoms::height, aHeight); -} - -NS_IMETHODIMP -nsHTMLCanvasElement::GetWidth(PRInt32* aWidth) -{ - *aWidth = GetWidthHeight().width; - - return NS_OK; -} - -NS_IMETHODIMP -nsHTMLCanvasElement::SetWidth(PRInt32 aWidth) -{ - return nsGenericHTMLElement::SetIntAttr(nsHTMLAtoms::width, aWidth); -} +NS_IMPL_INT_ATTR_DEFAULT_VALUE(nsHTMLCanvasElement, Width, width, DEFAULT_CANVAS_WIDTH) +NS_IMPL_INT_ATTR_DEFAULT_VALUE(nsHTMLCanvasElement, Height, height, DEFAULT_CANVAS_HEIGHT) nsresult nsHTMLCanvasElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, @@ -205,9 +178,6 @@ nsHTMLCanvasElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, { rv = UpdateImageContainer(); NS_ENSURE_SUCCESS(rv, rv); - - rv = UpdateContext(); - NS_ENSURE_SUCCESS(rv, rv); } return rv; @@ -222,7 +192,7 @@ nsHTMLCanvasElement::GetAttributeChangeHint(const nsIAtom* aAttribute, if (aAttribute == nsHTMLAtoms::width || aAttribute == nsHTMLAtoms::height) { - NS_UpdateHint(retval, NS_STYLE_HINT_FRAMECHANGE); + NS_UpdateHint(retval, NS_STYLE_HINT_REFLOW); } return retval; } @@ -231,8 +201,6 @@ static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes, nsRuleData* aData) { - nsGenericHTMLElement::MapImageAlignAttributeInto(aAttributes, aData); - nsGenericHTMLElement::MapImageBorderAttributeInto(aAttributes, aData); nsGenericHTMLElement::MapImageMarginAttributeInto(aAttributes, aData); nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData); } @@ -255,9 +223,7 @@ nsHTMLCanvasElement::IsAttributeMapped(const nsIAtom* aAttribute) const { static const MappedAttributeEntry* const map[] = { sCommonAttributeMap, - sImageMarginAttributeMap, - sImageBorderAttributeMap, - sImageAlignAttributeMap + sImageMarginAttributeMap }; return FindAttributeDependence(aAttribute, map, NS_ARRAY_LENGTH(map)); @@ -284,6 +250,8 @@ NS_IMETHODIMP nsHTMLCanvasElement::GetContext(const nsAString& aContextId, nsISupports **aContext) { + nsresult rv; + if (mCurrentContextId.IsEmpty()) { nsCString ctxId; ctxId.Assign(NS_LossyConvertUTF16toASCII(aContextId)); @@ -303,8 +271,10 @@ nsHTMLCanvasElement::GetContext(const nsAString& aContextId, nsCString ctxString("@mozilla.org/content/canvas-rendering-context;1?id="); ctxString.Append(ctxId); - mCurrentContext = do_CreateInstance(nsPromiseFlatCString(ctxString).get()); - if (!mCurrentContext) + mCurrentContext = do_CreateInstance(nsPromiseFlatCString(ctxString).get(), &rv); + if (rv == NS_ERROR_OUT_OF_MEMORY) + return NS_ERROR_OUT_OF_MEMORY; + if (NS_FAILED(rv)) return NS_ERROR_INVALID_ARG; nsCOMPtr internalctx(do_QueryInterface(mCurrentContext)); @@ -313,17 +283,15 @@ nsHTMLCanvasElement::GetContext(const nsAString& aContextId, return NS_ERROR_FAILURE; } - nsresult rv = internalctx->Init(this); + rv = internalctx->Init(this); NS_ENSURE_SUCCESS(rv, rv); rv = UpdateImageContainer(); NS_ENSURE_SUCCESS(rv, rv); - rv = UpdateContext(); - NS_ENSURE_SUCCESS(rv, rv); - mCurrentContextId.Assign(aContextId); } else if (!mCurrentContextId.Equals(aContextId)) { + //XXX eventually allow for more than one active context on a given canvas return NS_ERROR_INVALID_ARG; } @@ -336,10 +304,7 @@ nsHTMLCanvasElement::UpdateImageContainer() { nsresult rv = NS_OK; - nsSize sz = GetWidthHeight(); - if (sz.width == 0 || sz.height == 0) - return NS_OK; - + nsIntSize sz = GetWidthHeight(); PRInt32 w = 0, h = 0; if (mImageFrame) { @@ -365,7 +330,7 @@ nsHTMLCanvasElement::UpdateImageContainer() mImageContainer->AppendFrame(mImageFrame); } - return rv; + return UpdateContext(); } nsresult @@ -386,8 +351,12 @@ nsHTMLCanvasElement::UpdateContext() NS_IMETHODIMP nsHTMLCanvasElement::GetCanvasImageContainer (imgIContainer **aImageContainer) { - if (!mImageContainer) - UpdateImageContainer(); + nsresult rv; + + if (!mImageContainer) { + rv = UpdateImageContainer(); + NS_ENSURE_SUCCESS(rv, rv); + } NS_IF_ADDREF(*aImageContainer = mImageContainer); return NS_OK; diff --git a/mozilla/layout/base/nsCSSFrameConstructor.cpp b/mozilla/layout/base/nsCSSFrameConstructor.cpp index db1eb936297..5abea86e072 100644 --- a/mozilla/layout/base/nsCSSFrameConstructor.cpp +++ b/mozilla/layout/base/nsCSSFrameConstructor.cpp @@ -5394,6 +5394,9 @@ nsCSSFrameConstructor::ConstructHTMLFrame(nsFrameConstructorState& aState, rv = NS_NewIsIndexFrame(mPresShell, &newFrame); } else if (nsHTMLAtoms::canvas == aTag) { + if (!aHasPseudoParent && !aState.mPseudoFrames.IsEmpty()) { + ProcessPseudoFrames(aState, aFrameItems); + } isReplaced = PR_TRUE; rv = NS_NewHTMLCanvasFrame(mPresShell, &newFrame); } @@ -8484,8 +8487,9 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer, // then don't do any processing now nsIAtom* frameType = parentFrame->GetType(); if (frameType == nsLayoutAtoms::objectFrame || - frameType == nsLayoutAtoms::tableColFrame) { - // This handles APPLET, EMBED, OBJECT and COL + frameType == nsLayoutAtoms::tableColFrame || + frameType == nsLayoutAtoms::canvasFrame) { + // This handles APPLET, EMBED, OBJECT, COL, and CANVAS return NS_OK; } // Deal with inner/outer tables, fieldsets @@ -9071,8 +9075,9 @@ nsCSSFrameConstructor::ContentInserted(nsIContent* aContainer, // then don't do any processing now nsIAtom* frameType = parentFrame->GetType(); if (frameType == nsLayoutAtoms::objectFrame || - frameType == nsLayoutAtoms::tableColFrame) { - // This handles APPLET, EMBED, OBJECT and COL + frameType == nsLayoutAtoms::tableColFrame || + frameType == nsLayoutAtoms::canvasFrame) { + // This handles APPLET, EMBED, OBJECT, COL, and CANVAS return NS_OK; } // Deal with inner/outer tables, fieldsets diff --git a/mozilla/layout/generic/nsHTMLCanvasFrame.cpp b/mozilla/layout/generic/nsHTMLCanvasFrame.cpp index eac6dfbe7ab..9de265f0e0f 100644 --- a/mozilla/layout/generic/nsHTMLCanvasFrame.cpp +++ b/mozilla/layout/generic/nsHTMLCanvasFrame.cpp @@ -63,32 +63,13 @@ nsHTMLCanvasFrame::~nsHTMLCanvasFrame() { } -NS_IMETHODIMP -nsHTMLCanvasFrame::Init(nsPresContext* aPresContext, - nsIContent* aContent, - nsIFrame* aParent, - nsStyleContext* aContext, - nsIFrame* aPrevInFlow) -{ - nsCOMPtr canvas (do_QueryInterface(aContent)); - NS_ENSURE_TRUE(canvas, NS_ERROR_FAILURE); - - nsresult rv = canvas->GetCanvasImageContainer(getter_AddRefs(mImageContainer)); - NS_ENSURE_SUCCESS(rv, rv); - - if (mImageContainer) { - PRInt32 w, h; - mImageContainer->GetWidth(&w); - mImageContainer->GetHeight(&h); - - mCanvasSize.SizeTo(w, h); - } - - rv = nsSplittableFrame::Init(aPresContext, aContent, aParent, - aContext, aPrevInFlow); - - return rv; -} +// We really want a PR_MINMAX to go along with PR_MIN/PR_MAX +#define MINMAX(_value,_min,_max) \ + ((_value) < (_min) \ + ? (_min) \ + : ((_value) > (_max) \ + ? (_max) \ + : (_value))) NS_IMETHODIMP nsHTMLCanvasFrame::Reflow(nsPresContext* aPresContext, @@ -106,13 +87,43 @@ nsHTMLCanvasFrame::Reflow(nsPresContext* aPresContext, aStatus = NS_FRAME_COMPLETE; + nsCOMPtr canvas(do_QueryInterface(GetContent())); + NS_ENSURE_TRUE(canvas, NS_ERROR_FAILURE); + + nsresult rv = canvas->GetCanvasImageContainer(getter_AddRefs(mImageContainer)); + NS_ENSURE_SUCCESS(rv, rv); + float p2t = GetPresContext()->PixelsToTwips(); - aMetrics.width = NSIntPixelsToTwips(mCanvasSize.width, p2t); - aMetrics.height = NSIntPixelsToTwips(mCanvasSize.height, p2t); + if (mImageContainer) { + PRInt32 w, h; + mImageContainer->GetWidth(&w); + mImageContainer->GetHeight(&h); - aMetrics.width += aReflowState.mComputedBorderPadding.left + aReflowState.mComputedBorderPadding.right; - aMetrics.height += aReflowState.mComputedBorderPadding.top + aReflowState.mComputedBorderPadding.bottom; + mCanvasSize.SizeTo(NSIntPixelsToTwips(w, p2t), NSIntPixelsToTwips(h, p2t)); + } else { + mCanvasSize.SizeTo(0, 0); + } + + if (aReflowState.mComputedWidth == NS_INTRINSICSIZE) + aMetrics.width = mCanvasSize.width; + else + aMetrics.width = aReflowState.mComputedWidth; + + if (aReflowState.mComputedHeight == NS_INTRINSICSIZE) + aMetrics.height = mCanvasSize.height; + else + aMetrics.height = aReflowState.mComputedHeight; + + // clamp + aMetrics.height = MINMAX(aMetrics.height, aReflowState.mComputedMinHeight, aReflowState.mComputedMaxHeight); + aMetrics.width = MINMAX(aMetrics.width, aReflowState.mComputedMinWidth, aReflowState.mComputedMaxWidth); + + // stash this away so we can compute our inner area later + mBorderPadding = aReflowState.mComputedBorderPadding; + + aMetrics.width += mBorderPadding.left + mBorderPadding.right; + aMetrics.height += mBorderPadding.top + mBorderPadding.bottom; if (mPrevInFlow) { nscoord y = GetContinuationOffset(&aMetrics.width); @@ -144,6 +155,19 @@ nsHTMLCanvasFrame::Reflow(nsPresContext* aPresContext, return NS_OK; } +// FIXME taken from nsImageFrame, but then had splittable frame stuff +// removed. That needs to be fixed. +nsRect +nsHTMLCanvasFrame::GetInnerArea() const +{ + nsRect r; + r.x = mBorderPadding.left; + r.y = mBorderPadding.top; + r.width = mRect.width - mBorderPadding.left - mBorderPadding.right; + r.height = mRect.height - mBorderPadding.top - mBorderPadding.bottom; + return r; +} + NS_IMETHODIMP nsHTMLCanvasFrame::Paint(nsPresContext* aPresContext, nsIRenderingContext& aRenderingContext, @@ -162,21 +186,25 @@ nsHTMLCanvasFrame::Paint(nsPresContext* aPresContext, return NS_OK; } - if (aWhichLayer == NS_FRAME_PAINT_LAYER_FOREGROUND) { - nsPoint dstpt = GetPosition(); - float p2t = aPresContext->PixelsToTwips(); - nsRect src(0, - 0, - NSIntPixelsToTwips(mCanvasSize.width, p2t), - NSIntPixelsToTwips(mCanvasSize.height, p2t)); + // from nsImageFrame + // First paint background and borders, which should be in the + // FOREGROUND or BACKGROUND paint layer if the element is + // inline-level or block-level, respectively (bug 36710). (See + // CSS2 9.5, which is the rationale for paint layers.) + const nsStyleDisplay* display = GetStyleDisplay(); + nsFramePaintLayer backgroundLayer = display->IsBlockLevel() + ? NS_FRAME_PAINT_LAYER_BACKGROUND + : NS_FRAME_PAINT_LAYER_FOREGROUND; - nsRect dst(0, 0, src.width, src.height); + if (aWhichLayer == backgroundLayer) { + PaintSelf(aPresContext, aRenderingContext, aDirtyRect); + } - if (mImageContainer) { - aRenderingContext.DrawImage(mImageContainer, src, dst); - } else { - aRenderingContext.FillRect(dst); - } + if ((aWhichLayer == NS_FRAME_PAINT_LAYER_FOREGROUND) && mImageContainer) { + nsRect inner = GetInnerArea(); + nsRect src(0, 0, mCanvasSize.width, mCanvasSize.height); + + aRenderingContext.DrawImage(mImageContainer, src, inner); } } @@ -247,6 +275,12 @@ nsHTMLCanvasFrame::GetAccessible(nsIAccessible** aAccessible) #endif #ifdef DEBUG +NS_IMETHODIMP +nsHTMLCanvasFrame::GetFrameName(nsAString& aResult) const +{ + return MakeFrameName(NS_LITERAL_STRING("HTMLCanvas"), aResult); +} + NS_IMETHODIMP nsHTMLCanvasFrame::List(nsPresContext* aPresContext, FILE* out, PRInt32 aIndent) const { diff --git a/mozilla/layout/generic/nsHTMLCanvasFrame.h b/mozilla/layout/generic/nsHTMLCanvasFrame.h index 6140392f939..865b85fd183 100644 --- a/mozilla/layout/generic/nsHTMLCanvasFrame.h +++ b/mozilla/layout/generic/nsHTMLCanvasFrame.h @@ -53,12 +53,6 @@ class nsHTMLCanvasFrame : public nsSplittableFrame public: nsHTMLCanvasFrame(); - // nsISupports - NS_IMETHOD Init(nsPresContext* aPresContext, - nsIContent* aContent, - nsIFrame* aParent, - nsStyleContext* aContext, - nsIFrame* aPrevInFlow); NS_IMETHOD Paint(nsPresContext* aPresContext, nsIRenderingContext& aRenderingContext, const nsRect& aDirtyRect, @@ -76,12 +70,15 @@ public: nsEvent* aEvent, nsIContent** aContent); + nsRect GetInnerArea() const; + #ifdef ACCESSIBILITY NS_IMETHOD GetAccessible(nsIAccessible** aAccessible); #endif virtual nsIAtom* GetType() const; #ifdef DEBUG + NS_IMETHOD GetFrameName(nsAString& aResult) const; NS_IMETHOD List(nsPresContext* aPresContext, FILE* out, PRInt32 aIndent) const; #endif diff --git a/mozilla/layout/style/html.css b/mozilla/layout/style/html.css index 355b0d1553d..dacb9f4d630 100644 --- a/mozilla/layout/style/html.css +++ b/mozilla/layout/style/html.css @@ -424,10 +424,10 @@ spacer { /* focusable content: anything w/ tabindex >=0 is focusable */ abbr:focus, acronym:focus, address:focus, applet:focus, b:focus, -base:focus, big:focus, blockquote:focus, br:focus, caption:focus, center:focus, -cite:focus, code:focus, col:focus, colgroup:focus, dd:focus, del:focus, -dfn:focus, dir:focus, div:focus, dl:focus, dt:focus, em:focus, fieldset:focus, -font:focus, form:focus, h1:focus, h2:focus, h3:focus, h4:focus, +base:focus, big:focus, blockquote:focus, br:focus, canvas:focus, caption:focus, +center:focus, cite:focus, code:focus, col:focus, colgroup:focus, dd:focus, +del:focus, dfn:focus, dir:focus, div:focus, dl:focus, dt:focus, em:focus, +fieldset:focus, font:focus, form:focus, h1:focus, h2:focus, h3:focus, h4:focus, h5:focus, h6:focus, hr:focus, i:focus, img:focus, ins:focus, kbd:focus, label:focus, legend:focus, li:focus, link:focus, menu:focus, object:focus, ol:focus, p:focus, pre:focus, q:focus, s:focus, samp:focus, diff --git a/mozilla/parser/htmlparser/src/nsElementTable.cpp b/mozilla/parser/htmlparser/src/nsElementTable.cpp index 3fc62f94e95..b084efdf0c4 100644 --- a/mozilla/parser/htmlparser/src/nsElementTable.cpp +++ b/mozilla/parser/htmlparser/src/nsElementTable.cpp @@ -374,8 +374,8 @@ const nsHTMLElement gHTMLElements[] = { /*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown, /*rootnodes,endrootnodes*/ &gRootTags,&gRootTags, /*autoclose starttags and endtags*/ 0,0,0,0, - /*parent,incl,exclgroups*/ kSpecial, kNone, kNone, - /*special props, prop-range*/ kNonContainer,kDefaultPropRange, + /*parent,incl,exclgroups*/ kSpecial, (kFlowEntity|kSelf), kNone, + /*special props, prop-range*/ 0, kDefaultPropRange, /*special parents,kids,skip*/ 0,0,eHTMLTag_unknown, /*contain-func*/ 0 },