b=333177, update canvas internal interfaces, optimize canvas, and fix some implementation bugs; r=stuart

This commit is contained in:
vladimir%pobox.com 2006-04-18 21:23:15 +00:00
parent fdb6b63a3a
commit 5d02ec5b40
8 changed files with 667 additions and 429 deletions

View File

@ -40,32 +40,40 @@
#include "nsISupports.h"
#include "nsIFrame.h"
#include "imgIContainer.h"
// {8fd94ec9-d4e0-409b-af8f-828c7d7648f5}
// {C234660C-BD06-493e-8583-939A5A158B37}
#define NS_ICANVASELEMENT_IID \
{ 0x8fd94ec9, 0xd4e0, 0x409b, { 0xaf, 0x8f, 0x82, 0x8c, 0x7d, 0x76, 0x48, 0xf5 } }
{ 0xc234660c, 0xbd06, 0x493e, { 0x85, 0x83, 0x93, 0x9a, 0x5a, 0x15, 0x8b, 0x37 } }
class nsIRenderingContext;
struct _cairo_surface;
class nsICanvasElement : public nsISupports {
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_ICANVASELEMENT_IID)
/**
* Ask the Canvas Element to return the current image container that
* the frame should render.
*/
NS_IMETHOD GetCanvasImageContainer (imgIContainer **aImageContainer) = 0;
/**
* Ask the canvas Element to return the primary frame, if any
*/
NS_IMETHOD GetPrimaryCanvasFrame (nsIFrame **aFrame) = 0;
/**
* Ask the canvas element to notify the rendering context to update
* the image frame, in preparation for rendering
* Get the size in pixels of this canvas element
*/
NS_IMETHOD UpdateImageFrame () = 0;
NS_IMETHOD GetSize (PRUint32 *width, PRUint32 *height) = 0;
/*
* Ask the canvas element to tell the contexts to render themselves
* into the given nsIRenderingContext at the origin.
*/
NS_IMETHOD RenderContexts (nsIRenderingContext *rc) = 0;
/*
* Ask the canvas element to tell the contexts to render themselves
* into to given cairo_surface_t.
*/
NS_IMETHOD RenderContextsToSurface (struct _cairo_surface *surf) = 0;
/**
* Determine whether the canvas is write-only.

View File

@ -39,14 +39,16 @@
#define nsICanvasRenderingContextInternal_h___
#include "nsISupports.h"
#include "nsPresContext.h"
#include "gfxIImageFrame.h"
#include "nsICanvasElement.h"
#include "nsIInputStream.h"
// {0be74436-51a3-4be3-8357-ede741750080}
// {05150761-22A3-4e8d-A03E-EC53CB731C70}
#define NS_ICANVASRENDERINGCONTEXTINTERNAL_IID \
{ 0x0be74436, 0x51a3, 0x4be3, { 0x83, 0x57, 0xed, 0xe7, 0x41, 0x75, 0x00, 0x80 } }
{ 0x5150761, 0x22a3, 0x4e8d, { 0xa0, 0x3e, 0xec, 0x53, 0xcb, 0x73, 0x1c, 0x70 } }
class nsIRenderingContext;
struct _cairo_surface;
class nsICanvasRenderingContextInternal : public nsISupports {
public:
@ -56,8 +58,15 @@ public:
// with nsnull when the element is going away.
NS_IMETHOD SetCanvasElement(nsICanvasElement* aParentCanvas) = 0;
// Will be called whenever the target image frame changes
NS_IMETHOD SetTargetImageFrame(gfxIImageFrame* aImageFrame) = 0;
// Sets the dimensions of the canvas, in pixels. Called
// whenever the size of the element changes.
NS_IMETHOD SetDimensions(PRInt32 width, PRInt32 height) = 0;
// Render the canvas at the origin of the given nsIRenderingContext
NS_IMETHOD Render(nsIRenderingContext *rc) = 0;
// Render the canvas at the origin of the given cairo surface
NS_IMETHOD RenderToSurface(struct _cairo_surface *surf) = 0;
// Gives you a stream containing the image represented by this context.
// The format is given in aMimeTime, for example "image/png".
@ -68,10 +77,6 @@ public:
NS_IMETHOD GetInputStream(const nsACString& aMimeType,
const nsAString& aEncoderOptions,
nsIInputStream **aStream) = 0;
// Will be called whenever the element needs to be redrawn,
// e.g. due to a Redraw on the frame.
NS_IMETHOD UpdateImageFrame() = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsICanvasRenderingContextInternal,

View File

@ -77,6 +77,10 @@ REQUIRES = \
libpixman \
$(NULL)
ifeq ($(MOZ_ENABLE_CAIRO_GFX),1)
REQUIRES += thebes
endif
# XXX some platforms can't handle building
# an empty .a/lib. Remove this dummy.cpp
# whenever w have a rendering context
@ -94,6 +98,6 @@ FORCE_STATIC_LIB = 1
include $(topsrcdir)/config/rules.mk
CXXFLAGS += $(MOZ_CAIRO_CFLAGS)
CXXFLAGS += $(MOZ_CAIRO_CFLAGS) $(TK_CFLAGS)
DEFINES += -D_IMPL_NS_LAYOUT

File diff suppressed because it is too large Load Diff

View File

@ -50,9 +50,7 @@
#include "prmem.h"
#include "nsICanvasElement.h"
#include "gfxIImageFrame.h"
#include "imgIContainer.h"
#include "nsIRenderingContext.h"
#include "nsICanvasRenderingContextInternal.h"
@ -83,9 +81,10 @@ public:
NS_DECL_NSIDOMHTMLCANVASELEMENT
// nsICanvasElement
NS_IMETHOD GetCanvasImageContainer(imgIContainer **aImageContainer);
NS_IMETHOD GetPrimaryCanvasFrame(nsIFrame **aFrame);
NS_IMETHOD UpdateImageFrame();
NS_IMETHOD GetSize(PRUint32 *width, PRUint32 *height);
NS_IMETHOD RenderContexts(nsIRenderingContext *ctx);
NS_IMETHOD RenderContextsToSurface(struct _cairo_surface *surf);
virtual PRBool IsWriteOnly();
virtual void SetWriteOnly();
@ -109,15 +108,11 @@ public:
PRBool aNotify);
protected:
nsIntSize GetWidthHeight();
nsresult UpdateImageContainer(PRBool forceCreate);
nsresult UpdateContext();
nsString mCurrentContextId;
nsCOMPtr<nsICanvasRenderingContextInternal> mCurrentContext;
nsCOMPtr<imgIContainer> mImageContainer;
nsCOMPtr<gfxIImageFrame> mImageFrame;
public:
// Record whether this canvas should be write-only or not.
// We set this when script paints an image from a different origin.
@ -196,7 +191,7 @@ nsHTMLCanvasElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
if (NS_SUCCEEDED(rv) && mCurrentContext &&
(aName == nsHTMLAtoms::width || aName == nsHTMLAtoms::height))
{
rv = UpdateImageContainer(PR_FALSE);
rv = UpdateContext();
NS_ENSURE_SUCCESS(rv, rv);
}
@ -400,7 +395,7 @@ nsHTMLCanvasElement::GetContext(const nsAString& aContextId,
rv = mCurrentContext->SetCanvasElement(this);
NS_ENSURE_SUCCESS(rv, rv);
rv = UpdateImageContainer(PR_TRUE);
rv = UpdateContext();
NS_ENSURE_SUCCESS(rv, rv);
mCurrentContextId.Assign(aContextId);
@ -413,84 +408,53 @@ nsHTMLCanvasElement::GetContext(const nsAString& aContextId,
return NS_OK;
}
nsresult
nsHTMLCanvasElement::UpdateImageContainer(PRBool forceCreate)
{
nsresult rv = NS_OK;
// don't create if we don't already have one,
// and no frame or context has asked for one.
if (!forceCreate && !mImageFrame)
return NS_OK;
nsIntSize sz = GetWidthHeight();
PRInt32 w = 0, h = 0;
if (mImageFrame) {
mImageFrame->GetWidth(&w);
mImageFrame->GetHeight(&h);
}
if (sz.width != w || sz.height != h) {
mImageContainer = do_CreateInstance("@mozilla.org/image/container;1");
mImageContainer->Init(sz.width, sz.height, nsnull);
mImageFrame = do_CreateInstance("@mozilla.org/gfx/image/frame;2");
if (!mImageFrame)
return NS_ERROR_FAILURE;
#if defined(XP_WIN) || defined(XP_OS2) || defined(XP_BEOS) || defined(MOZ_WIDGET_PHOTON)
rv = mImageFrame->Init(0, 0, sz.width, sz.height, gfxIFormats::BGR_A8, 24);
#else
rv = mImageFrame->Init(0, 0, sz.width, sz.height, gfxIFormats::RGB_A8, 24);
#endif
NS_ENSURE_SUCCESS(rv, rv);
mImageContainer->AppendFrame(mImageFrame);
}
return UpdateContext();
}
nsresult
nsHTMLCanvasElement::UpdateContext()
{
if (mCurrentContext)
return mCurrentContext->SetTargetImageFrame(mImageFrame);
return NS_OK;
}
NS_IMETHODIMP
nsHTMLCanvasElement::GetCanvasImageContainer(imgIContainer **aImageContainer)
{
nsresult rv;
if (!mImageContainer) {
rv = UpdateImageContainer(PR_TRUE);
NS_ENSURE_SUCCESS(rv, rv);
nsresult rv = NS_OK;
if (mCurrentContext) {
nsIntSize sz = GetWidthHeight();
rv = mCurrentContext->SetDimensions(sz.width, sz.height);
}
NS_IF_ADDREF(*aImageContainer = mImageContainer);
return NS_OK;
return rv;
}
NS_IMETHODIMP
nsHTMLCanvasElement::GetPrimaryCanvasFrame(nsIFrame **aFrame)
{
*aFrame = GetPrimaryFrame(PR_FALSE);
*aFrame = GetPrimaryFrame(PR_TRUE);
return NS_OK;
}
NS_IMETHODIMP
nsHTMLCanvasElement::UpdateImageFrame()
nsHTMLCanvasElement::GetSize(PRUint32 *width, PRUint32 *height)
{
if (mCurrentContext)
return mCurrentContext->UpdateImageFrame();
nsIntSize sz = GetWidthHeight();
*width = sz.width;
*height = sz.height;
return NS_OK;
}
NS_IMETHODIMP
nsHTMLCanvasElement::RenderContexts(nsIRenderingContext *rc)
{
if (!mCurrentContext)
return NS_OK;
return mCurrentContext->Render(rc);
}
NS_IMETHODIMP
nsHTMLCanvasElement::RenderContextsToSurface(struct _cairo_surface *surf)
{
if (!mCurrentContext)
return NS_OK;
return mCurrentContext->RenderToSurface(surf);
}
PRBool
nsHTMLCanvasElement::IsWriteOnly()
{

View File

@ -39,6 +39,7 @@
#include "nsIVariant.idl"
interface nsIDOMWindow;
interface nsIDOMHTMLElement;
interface nsIDOMHTMLImageElement;
interface nsIDOMHTMLCanvasElement;
@ -53,7 +54,7 @@ interface nsIDOMCanvasPattern : nsISupports
{
};
[scriptable, uuid(15487cf4-292b-49aa-bc36-17d9099f77a7)]
[scriptable, uuid(ab27f42d-e1e1-4ef6-9c83-059a81da479b)]
interface nsIDOMCanvasRenderingContext2D : nsISupports
{
// back-reference to the canvas element for which
@ -79,8 +80,8 @@ interface nsIDOMCanvasRenderingContext2D : nsISupports
nsIDOMCanvasGradient createLinearGradient (in float x0, in float y0, in float x1, in float y1);
nsIDOMCanvasGradient createRadialGradient(in float x0, in float y0, in float r0, in float x1, in float y1, in float r1);
nsIDOMCanvasPattern createPattern(in nsIDOMHTMLImageElement image, in DOMString repetition);
//nsIDOMCanvasPattern createPattern(in nsIDOMHTMLImageElement image, in DOMString repetition);
nsIDOMCanvasPattern createPattern(in nsIDOMHTMLElement image, in DOMString repetition);
attribute float lineWidth; /* default 1 */
attribute DOMString lineCap; /* "butt", "round", "square" (default) */
attribute DOMString lineJoin; /* "round", "bevel", "miter" (default) */

View File

@ -47,6 +47,8 @@
#include "nsICanvasElement.h"
#include "nsDisplayList.h"
#include "nsTransform2D.h"
nsIFrame*
NS_NewHTMLCanvasFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
{
@ -84,20 +86,13 @@ nsHTMLCanvasFrame::Reflow(nsPresContext* aPresContext,
nsCOMPtr<nsICanvasElement> canvas(do_QueryInterface(GetContent()));
NS_ENSURE_TRUE(canvas, NS_ERROR_FAILURE);
nsresult rv = canvas->GetCanvasImageContainer(getter_AddRefs(mImageContainer));
PRUint32 w, h;
nsresult rv = canvas->GetSize (&w, &h);
NS_ENSURE_SUCCESS(rv, rv);
float p2t = GetPresContext()->PixelsToTwips();
if (mImageContainer) {
PRInt32 w, h;
mImageContainer->GetWidth(&w);
mImageContainer->GetHeight(&h);
mCanvasSize.SizeTo(NSIntPixelsToTwips(w, p2t), NSIntPixelsToTwips(h, p2t));
} else {
mCanvasSize.SizeTo(0, 0);
}
mCanvasSize.SizeTo(NSIntPixelsToTwips(w, p2t), NSIntPixelsToTwips(h, p2t));
if (aReflowState.mComputedWidth == NS_INTRINSICSIZE)
aMetrics.width = mCanvasSize.width;
@ -167,10 +162,39 @@ nsHTMLCanvasFrame::PaintCanvas(nsIRenderingContext& aRenderingContext,
const nsRect& aDirtyRect, nsPoint aPt)
{
nsRect inner = GetInnerArea() + aPt;
nsRect src(0, 0, mCanvasSize.width, mCanvasSize.height);
// XXX this should just draw the dirty area
aRenderingContext.DrawImage(mImageContainer, src, inner);
nsCOMPtr<nsICanvasElement> canvas(do_QueryInterface(GetContent()));
if (!canvas)
return;
float t2p = GetPresContext()->TwipsToPixels();
float p2t = GetPresContext()->PixelsToTwips();
// XXXvlad clip to aDirtyRect!
if (inner.width != mCanvasSize.width ||
inner.height != mCanvasSize.height)
{
float sx = inner.width / (float) mCanvasSize.width;
float sy = inner.height / (float) mCanvasSize.height;
aRenderingContext.PushState();
aRenderingContext.Translate(inner.x, inner.y);
aRenderingContext.Scale(sx, sy);
canvas->RenderContexts(&aRenderingContext);
aRenderingContext.PopState();
} else {
//nsIRenderingContext::AutoPushTranslation(&aRenderingContext, px, py);
aRenderingContext.PushState();
aRenderingContext.Translate(inner.x, inner.y);
canvas->RenderContexts(&aRenderingContext);
aRenderingContext.PopState();
}
}
static void PaintCanvas(nsIFrame* aFrame, nsIRenderingContext* aCtx,
@ -187,27 +211,12 @@ nsHTMLCanvasFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
if (!IsVisibleForPainting(aBuilder))
return NS_OK;
// REVIEW: We don't need any special logic here for deciding which layer
// to put the background in ... it goes in aLists.BorderBackground() and
// then if we have a block parent, it will put our background in the right
// place.
nsresult rv = DisplayBorderBackgroundOutline(aBuilder, aLists);
NS_ENSURE_SUCCESS(rv, rv);
// REVIEW: Checking mRect.IsEmpty() makes no sense to me, so I removed it.
// It can't have been protecting us against bad situations with zero-size
// images since adding a border would make the rect non-empty.
// make sure that the rendering context has updated the
// image frame
nsCOMPtr<nsICanvasElement> canvas(do_QueryInterface(GetContent()));
NS_ENSURE_TRUE(canvas, NS_ERROR_FAILURE);
NS_ENSURE_SUCCESS(canvas->UpdateImageFrame(), NS_ERROR_FAILURE);
if (mImageContainer) {
rv = aLists.Content()->AppendNewToTop(new (aBuilder)
nsDisplayGeneric(this, ::PaintCanvas, "Canvas"));
NS_ENSURE_SUCCESS(rv, rv);
}
rv = aLists.Content()->AppendNewToTop(new (aBuilder)
nsDisplayGeneric(this, ::PaintCanvas, "Canvas"));
NS_ENSURE_SUCCESS(rv, rv);
return DisplaySelectionOverlay(aBuilder, aLists,
nsISelectionDisplay::DISPLAY_IMAGES);

View File

@ -46,9 +46,6 @@
#include "nsPresContext.h"
#include "nsIIOService.h"
#include "gfxIImageFrame.h"
#include "imgIContainer.h"
nsIFrame* NS_NewHTMLCanvasFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
class nsHTMLCanvasFrame : public nsSplittableFrame
@ -92,8 +89,6 @@ protected:
nscoord GetContinuationOffset(nscoord* aWidth = 0) const;
nsCOMPtr<imgIContainer> mImageContainer;
nsMargin mBorderPadding;
nsSize mCanvasSize;
};