Bug 326966. Reenable SVG <foreignobject> for cairo-gfx builds. r+sr=tor

This commit is contained in:
roc+%cs.cmu.edu 2006-02-21 00:33:27 +00:00
Родитель 3836721172
Коммит 3b39730db2
9 изменённых файлов: 473 добавлений и 1325 удалений

Просмотреть файл

@ -4244,6 +4244,7 @@ MOZ_REFLOW_PERF=
MOZ_REORDER=
MOZ_SINGLE_PROFILE=
MOZ_STATIC_MAIL_BUILD=
MOZ_SVG_FOREIGNOBJECT=$MOZ_ENABLE_CAIRO_GFX
MOZ_TIMELINE=
MOZ_UI_LOCALE=en-US
MOZ_UNIVERSALCHARDET=1
@ -5396,19 +5397,21 @@ if test -n "$MOZ_SVG"; then
esac
fi
dnl COMMENTED OUT because foreignobject support should
dnl not be tweakable by distributors!
dnl ========================================================
dnl SVG <foreignObject>
dnl ========================================================
dnl MOZ_ARG_ENABLE_BOOL(svg-foreignobject,
dnl [ --enable-svg-foreignobject
dnl Enable SVG <foreignObject> support],
dnl MOZ_SVG_FOREIGNOBJECT=1,
dnl MOZ_SVG_FOREIGNOBJECT= )
dnl if test -n "$MOZ_SVG_FOREIGNOBJECT"; then
dnl AC_DEFINE(MOZ_SVG_FOREIGNOBJECT)
dnl fi
MOZ_ARG_DISABLE_BOOL(svg-foreignobject,
[ --disable-svg-foreignobject
Disable SVG <foreignObject> support],
MOZ_SVG_FOREIGNOBJECT=,
MOZ_SVG_FOREIGNOBJECT=1 )
if test "$MOZ_SVG_FOREIGNOBJECT"; then
if test -z "$MOZ_ENABLE_CAIRO_GFX"; then
AC_MSG_ERROR([<foreignobject> requires cairo gfx])
else
AC_DEFINE(MOZ_SVG_FOREIGNOBJECT)
fi
fi
dnl ========================================================
dnl Installer

Просмотреть файл

@ -54,6 +54,9 @@
#include "nsGUIEvent.h"
#include "nsDisplayList.h"
#include "nsRegion.h"
#include "nsSVGForeignObjectFrame.h"
#include "nsSVGUtils.h"
#include "nsISVGOuterSVGFrame.h"
/**
* A namespace class for static layout utilities.
@ -492,17 +495,33 @@ nsLayoutUtils::GetEventCoordinatesRelativeTo(nsEvent* aEvent, nsIFrame* aFrame)
if (!GUIEvent->widget)
return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
nsPoint frameToView;
nsIView* frameView = aFrame->GetClosestView(&frameToView);
// If it is, or is a descendant of, an SVG foreignobject frame,
// then we need to do extra work
nsIFrame* rootFrame;
for (nsIFrame* f = aFrame; f; f = GetCrossDocParentFrame(f)) {
if (f->IsFrameOfType(nsIFrame::eSVGForeignObject)) {
nsSVGForeignObjectFrame* fo = NS_STATIC_CAST(nsSVGForeignObjectFrame*, f);
nsIFrame* outer;
CallQueryInterface(nsSVGUtils::GetOuterSVGFrame(fo), &outer);
return fo->TransformPointFromOuter(
GetEventCoordinatesRelativeTo(aEvent, outer)) -
aFrame->GetOffsetTo(fo);
}
rootFrame = f;
}
nsPoint widgetToView = TranslateWidgetToView(aFrame->GetPresContext(),
nsIView* rootView = rootFrame->GetView();
if (!rootView)
return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
nsPoint widgetToView = TranslateWidgetToView(rootFrame->GetPresContext(),
GUIEvent->widget, GUIEvent->refPoint,
frameView);
rootView);
if (widgetToView == nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE))
return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
return widgetToView - frameToView;
return widgetToView - aFrame->GetOffsetTo(rootFrame);
}
nsPoint

Просмотреть файл

@ -108,6 +108,7 @@ FORCE_STATIC_LIB = 1
EXPORTS = \
nsSVGUtils.h \
nsSVGFilterInstance.h \
nsSVGForeignObjectFrame.h \
$(NULL)
include $(topsrcdir)/config/rules.mk

Просмотреть файл

@ -36,15 +36,11 @@
*
* ***** END LICENSE BLOCK ***** */
#include "nsBlockFrame.h"
#include "nsIDOMSVGGElement.h"
#include "nsPresContext.h"
#include "nsISVGChildFrame.h"
#include "nsISVGContainerFrame.h"
#include "nsSVGForeignObjectFrame.h"
#include "nsISVGRendererCanvas.h"
#include "nsWeakReference.h"
#include "nsISVGValue.h"
#include "nsISVGValueObserver.h"
#include "nsIDOMSVGGElement.h"
#include "nsIDOMSVGTransformable.h"
#include "nsIDOMSVGAnimTransformList.h"
#include "nsIDOMSVGTransformList.h"
@ -58,118 +54,16 @@
#include "nsISVGRendererRegion.h"
#include "nsISVGRenderer.h"
#include "nsISVGOuterSVGFrame.h"
#include "nsTransform2D.h"
#include "nsISVGValueUtils.h"
#include "nsRegion.h"
#include "nsLayoutAtoms.h"
#include "nsLayoutUtils.h"
#include "nsSVGUtils.h"
#include "nsIURI.h"
#include "nsSVGFilterFrame.h"
#include "nsSVGPoint.h"
#include "nsSVGRect.h"
#include "nsSVGMatrix.h"
#include "nsLayoutAtoms.h"
typedef nsBlockFrame nsSVGForeignObjectFrameBase;
class nsSVGForeignObjectFrame : public nsSVGForeignObjectFrameBase,
public nsISVGContainerFrame,
public nsISVGChildFrame,
public nsISVGValueObserver,
public nsSupportsWeakReference
{
friend nsIFrame*
NS_NewSVGForeignObjectFrame(nsIPresShell* aPresShell, nsIContent* aContent);
protected:
nsSVGForeignObjectFrame();
virtual ~nsSVGForeignObjectFrame();
nsresult Init();
// nsISupports interface:
NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr);
private:
NS_IMETHOD_(nsrefcnt) AddRef() { return NS_OK; }
NS_IMETHOD_(nsrefcnt) Release() { return NS_OK; }
public:
// nsIFrame:
NS_IMETHOD Init(nsPresContext* aPresContext,
nsIContent* aContent,
nsIFrame* aParent,
nsStyleContext* aContext,
nsIFrame* aPrevInFlow);
NS_IMETHOD Reflow(nsPresContext* aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus);
NS_IMETHOD AppendFrames(nsIAtom* aListName,
nsIFrame* aFrameList);
NS_IMETHOD InsertFrames(nsIAtom* aListName,
nsIFrame* aPrevFrame,
nsIFrame* aFrameList);
NS_IMETHOD RemoveFrame(nsIAtom* aListName,
nsIFrame* aOldFrame);
/**
* Get the "type" of the frame
*
* @see nsLayoutAtoms::svgForeignObjectFrame
*/
// XXX Need to make sure that any of the code examining
// frametypes, particularly code looking at block and area
// also handles foreignObject before we return our own frametype
// virtual nsIAtom* GetType() const;
virtual PRBool IsFrameOfType(PRUint32 aFlags) const;
#ifdef DEBUG
NS_IMETHOD GetFrameName(nsAString& aResult) const
{
return MakeFrameName(NS_LITERAL_STRING("SVGForeignObject"), aResult);
}
#endif
// nsISVGValueObserver
NS_IMETHOD WillModifySVGObservable(nsISVGValue* observable,
nsISVGValue::modificationType aModType);
NS_IMETHOD DidModifySVGObservable (nsISVGValue* observable,
nsISVGValue::modificationType aModType);
// nsISupportsWeakReference
// implementation inherited from nsSupportsWeakReference
// nsISVGChildFrame interface:
NS_IMETHOD PaintSVG(nsISVGRendererCanvas* canvas,
const nsRect& dirtyRectTwips,
PRBool ignoreFilter);
NS_IMETHOD GetFrameForPointSVG(float x, float y, nsIFrame** hit);
NS_IMETHOD_(already_AddRefed<nsISVGRendererRegion>) GetCoveredRegion();
NS_IMETHOD InitialUpdate();
NS_IMETHOD NotifyCanvasTMChanged(PRBool suppressInvalidation);
NS_IMETHOD NotifyRedrawSuspended();
NS_IMETHOD NotifyRedrawUnsuspended();
NS_IMETHOD SetMatrixPropagation(PRBool aPropagate);
NS_IMETHOD SetOverrideCTM(nsIDOMSVGMatrix *aCTM);
NS_IMETHOD GetBBox(nsIDOMSVGRect **_retval);
// nsISVGContainerFrame interface:
already_AddRefed<nsIDOMSVGMatrix> GetCanvasTM();
already_AddRefed<nsSVGCoordCtxProvider> GetCoordContextProvider();
protected:
// implementation helpers:
void Update();
already_AddRefed<nsISVGRendererRegion> DoReflow();
float GetPxPerTwips();
float GetTwipsPerPx();
void TransformPoint(float& x, float& y);
void TransformVector(float& x, float& y);
PRBool mIsDirty;
nsCOMPtr<nsIDOMSVGLength> mX;
nsCOMPtr<nsIDOMSVGLength> mY;
nsCOMPtr<nsIDOMSVGLength> mWidth;
nsCOMPtr<nsIDOMSVGLength> mHeight;
nsCOMPtr<nsIDOMSVGMatrix> mCanvasTM;
PRBool mPropagateTransform;
nsCOMPtr<nsIDOMSVGMatrix> mOverrideCTM;
};
//----------------------------------------------------------------------
// Implementation
@ -189,7 +83,7 @@ NS_NewSVGForeignObjectFrame(nsIPresShell* aPresShell, nsIContent* aContent)
}
nsSVGForeignObjectFrame::nsSVGForeignObjectFrame()
: mIsDirty(PR_TRUE), mPropagateTransform(PR_TRUE)
: mIsDirty(PR_TRUE), mPropagateTransform(PR_TRUE), mFilter(nsnull)
{
}
@ -212,6 +106,10 @@ nsSVGForeignObjectFrame::~nsSVGForeignObjectFrame()
value->RemoveObserver(this);
if (mHeight && (value = do_QueryInterface(mHeight)))
value->RemoveObserver(this);
if (mFilter) {
NS_REMOVE_SVGVALUE_OBSERVER(mFilter);
}
}
nsresult nsSVGForeignObjectFrame::Init()
@ -323,37 +221,15 @@ nsSVGForeignObjectFrame::Reflow(nsPresContext* aPresContext,
NS_ENSURE_TRUE(mX && mY && mWidth && mHeight, NS_ERROR_FAILURE);
float x, y, width, height;
mX->GetValue(&x);
mY->GetValue(&y);
float width, height;
mWidth->GetValue(&width);
mHeight->GetValue(&height);
// transform x,y,width,height according to the current canvastm:
// XXX we're ignoring rotation at the moment
// (x, y): (left, top) -> (center_x, center_y)
x+=width/2.0f;
y+=height/2.0f;
// (x, y): (cx, cy) -> (cx', cy')
TransformPoint(x, y);
// find new ex & ey unit vectors
float e1x = 1.0f, e1y = 0.0f, e2x = 0.0f, e2y = 1.0f;
TransformVector(e1x, e1y);
TransformVector(e2x, e2y);
// adopt the scale of them for (w,h)
width *= (float)sqrt(e1x*e1x + e1y*e1y);
height *= (float)sqrt(e2x*e2x + e2y*e2y);
// (x, y): (cx', cy') -> (left', top')
x -= width/2.0f;
y -= height/2.0f;
// move ourselves to (x,y):
SetPosition(nsPoint((nscoord) (x*twipsPerPx), (nscoord) (y*twipsPerPx)));
// Xxx: if zewe have a view, move that
// move our frame to (0, 0), set our size to the untransformed
// width and height. Our frame size and position are meaningless
// given the possibility of non-rectilinear transforms; our size
// is only useful for reflowing our content
SetPosition(nsPoint(0, 0));
// create a new reflow state, setting our max size to (width,height):
nsSize availableSpace((nscoord)(width*twipsPerPx), (nscoord)(height*twipsPerPx));
@ -432,6 +308,20 @@ NS_IMETHODIMP
nsSVGForeignObjectFrame::WillModifySVGObservable(nsISVGValue* observable,
nsISVGValue::modificationType aModType)
{
nsISVGFilterFrame *filter;
CallQueryInterface(observable, &filter);
// need to handle filters because we might be the topmost filtered frame and
// the filter region could be changing.
if (filter && mFilterRegion) {
nsISVGOuterSVGFrame *outerSVGFrame = nsSVGUtils::GetOuterSVGFrame(this);
if (!outerSVGFrame)
return NS_ERROR_FAILURE;
nsCOMPtr<nsISVGRendererRegion> region;
nsSVGUtils::FindFilterInvalidation(this, getter_AddRefs(region));
outerSVGFrame->InvalidateRegion(region, PR_TRUE);
}
return NS_OK;
}
@ -442,6 +332,29 @@ nsSVGForeignObjectFrame::DidModifySVGObservable (nsISVGValue* observable,
{
Update();
nsISVGFilterFrame *filter;
CallQueryInterface(observable, &filter);
if (filter) {
if (aModType == nsISVGValue::mod_die) {
mFilter = nsnull;
mFilterRegion = nsnull;
}
nsISVGOuterSVGFrame *outerSVGFrame = nsSVGUtils::GetOuterSVGFrame(this);
if (!outerSVGFrame)
return NS_ERROR_FAILURE;
if (mFilter)
mFilter->GetInvalidationRegion(this, getter_AddRefs(mFilterRegion));
nsCOMPtr<nsISVGRendererRegion> region;
nsSVGUtils::FindFilterInvalidation(this, getter_AddRefs(region));
if (region)
outerSVGFrame->InvalidateRegion(region, PR_TRUE);
}
return NS_OK;
}
@ -449,6 +362,50 @@ nsSVGForeignObjectFrame::DidModifySVGObservable (nsISVGValue* observable,
//----------------------------------------------------------------------
// nsISVGChildFrame methods
/**
* Transform a rectangle with a given matrix. Since the image of the
* rectangle may not be a rectangle, the output rectangle is the
* bounding box of the true image.
*/
static void
TransformRect(float* aX, float *aY, float* aWidth, float *aHeight,
nsIDOMSVGMatrix* aMatrix)
{
float x[4], y[4];
x[0] = *aX;
y[0] = *aY;
x[1] = x[0] + *aWidth;
y[1] = y[0];
x[2] = x[0] + *aWidth;
y[2] = y[0] + *aHeight;
x[3] = x[0];
y[3] = y[0] + *aHeight;
int i;
for (i = 0; i < 4; i++) {
nsSVGUtils::TransformPoint(aMatrix, &x[i], &y[i]);
}
float xmin, xmax, ymin, ymax;
xmin = xmax = x[0];
ymin = ymax = y[0];
for (int i=1; i<4; i++) {
if (x[i] < xmin)
xmin = x[i];
if (y[i] < ymin)
ymin = y[i];
if (x[i] > xmax)
xmax = x[i];
if (y[i] > ymax)
ymax = y[i];
}
*aX = xmin;
*aY = ymin;
*aWidth = xmax - xmin;
*aHeight = ymax - ymin;
}
NS_IMETHODIMP
nsSVGForeignObjectFrame::PaintSVG(nsISVGRendererCanvas* canvas,
const nsRect& dirtyRectTwips,
@ -458,59 +415,106 @@ nsSVGForeignObjectFrame::PaintSVG(nsISVGRendererCanvas* canvas,
nsCOMPtr<nsISVGRendererRegion> region = DoReflow();
}
nsPresContext *presContext = GetPresContext();
nsRect r(mRect);
if (!r.IntersectRect(dirtyRectTwips, r))
return PR_TRUE;
/* check for filter */
if (!ignoreFilter) {
if (!mFilter) {
nsCOMPtr<nsIURI> aURI = GetStyleSVGReset()->mFilter;
if (aURI)
NS_GetSVGFilterFrame(&mFilter, aURI, mContent);
if (mFilter)
NS_ADD_SVGVALUE_OBSERVER(mFilter);
}
if (mFilter) {
if (!mFilterRegion)
mFilter->GetInvalidationRegion(this, getter_AddRefs(mFilterRegion));
mFilter->FilterPaint(canvas, this);
return NS_OK;
}
}
nsRect dirtyRect = nsRect(nsPoint(0, 0), GetSize());
nsCOMPtr<nsIDOMSVGMatrix> tm = GetTMIncludingOffset();
nsCOMPtr<nsIDOMSVGMatrix> inverse;
nsresult rv = tm->Inverse(getter_AddRefs(inverse));
float pxPerTwips = GetPxPerTwips();
r.x*=pxPerTwips;
r.y*=pxPerTwips;
r.width*=pxPerTwips;
r.height*=pxPerTwips;
float twipsPerPx = GetTwipsPerPx();
if (NS_SUCCEEDED(rv)) {
float x = dirtyRectTwips.x*pxPerTwips;
float y = dirtyRectTwips.y*pxPerTwips;
float w = dirtyRectTwips.width*pxPerTwips;
float h = dirtyRectTwips.height*pxPerTwips;
TransformRect(&x, &y, &w, &h, inverse);
nsRect r;
r.x = NSToCoordFloor(x*twipsPerPx);
r.y = NSToCoordFloor(y*twipsPerPx);
r.width = NSToCoordCeil((x + w)*twipsPerPx) - r.x;
r.height = NSToCoordCeil((y + h)*twipsPerPx) - r.y;
dirtyRect.IntersectRect(dirtyRect, r);
}
if (dirtyRect.IsEmpty())
return NS_OK;
nsCOMPtr<nsIRenderingContext> ctx;
canvas->LockRenderingContext(r, getter_AddRefs(ctx));
canvas->LockRenderingContext(tm, getter_AddRefs(ctx));
if (!ctx) {
NS_WARNING("Can't render foreignObject element!");
return NS_ERROR_FAILURE;
}
rv = nsLayoutUtils::PaintFrame(ctx, this, nsRegion(dirtyRect),
NS_RGBA(0,0,0,0));
nsRect dirtyRect = dirtyRectTwips;
dirtyRect.x -= mRect.x;
dirtyRect.y -= mRect.y;
{
nsIRenderingContext::AutoPushTranslation
translate(ctx, mRect.x, mRect.y);
rv = nsLayoutUtils::PaintFrame(ctx, this, nsRegion(dirtyRect));
}
ctx = nsnull;
canvas->UnlockRenderingContext();
return rv;
}
nsresult
nsSVGForeignObjectFrame::TransformPointFromOuterPx(float aX, float aY, nsPoint* aOut)
{
nsCOMPtr<nsIDOMSVGMatrix> tm = GetTMIncludingOffset();
nsCOMPtr<nsIDOMSVGMatrix> inverse;
nsresult rv = tm->Inverse(getter_AddRefs(inverse));
if (NS_FAILED(rv))
return rv;
nsSVGUtils::TransformPoint(inverse, &aX, &aY);
float twipsPerPx = GetTwipsPerPx();
*aOut = nsPoint(NSToCoordRound(aX*twipsPerPx),
NSToCoordRound(aY*twipsPerPx));
return NS_OK;
}
NS_IMETHODIMP
nsSVGForeignObjectFrame::GetFrameForPointSVG(float x, float y, nsIFrame** hit)
{
nsPoint p( (nscoord)(x*GetTwipsPerPx()),
(nscoord)(y*GetTwipsPerPx()));
*hit = nsLayoutUtils::GetFrameForPoint(this, p);
nsPoint pt;
nsresult rv = TransformPointFromOuterPx(x, y, &pt);
if (NS_FAILED(rv))
return rv;
*hit = nsLayoutUtils::GetFrameForPoint(this, pt);
return NS_OK;
}
nsPoint
nsSVGForeignObjectFrame::TransformPointFromOuter(nsPoint aPt)
{
float pxPerTwips = GetPxPerTwips();
nsPoint pt(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
TransformPointFromOuterPx(aPt.x*pxPerTwips, aPt.y*pxPerTwips, &pt);
return pt;
}
NS_IMETHODIMP_(already_AddRefed<nsISVGRendererRegion>)
nsSVGForeignObjectFrame::GetCoveredRegion()
{
// get a region from our mRect
// if (mRect.width==0 || mRect.height==0) return nsnull;
// get a region from our BBox
nsISVGOuterSVGFrame *outerSVGFrame = nsSVGUtils::GetOuterSVGFrame(this);
if (!outerSVGFrame) {
NS_ERROR("null outerSVGFrame");
@ -520,17 +524,14 @@ nsSVGForeignObjectFrame::GetCoveredRegion()
nsCOMPtr<nsISVGRenderer> renderer;
outerSVGFrame->GetRenderer(getter_AddRefs(renderer));
float pxPerTwips = GetPxPerTwips();
nsISVGRendererRegion *region = nsnull;
renderer->CreateRectRegion((mRect.x-1) * pxPerTwips,
(mRect.y-1) * pxPerTwips,
(mRect.width+2) * pxPerTwips,
(mRect.height+2) * pxPerTwips,
&region);
NS_ASSERTION(region, "could not create region");
return region;
float x, y, w, h;
GetBBoxInternal(&x, &y, &w, &h);
nsISVGRendererRegion *region = nsnull;
renderer->CreateRectRegion(x, y, w, h, &region);
NS_ASSERTION(region, "could not create region");
return region;
}
NS_IMETHODIMP
@ -583,50 +584,48 @@ nsSVGForeignObjectFrame::SetOverrideCTM(nsIDOMSVGMatrix *aCTM)
return NS_OK;
}
void
nsSVGForeignObjectFrame::GetBBoxInternal(float* aX, float *aY, float* aWidth,
float *aHeight)
{
nsCOMPtr<nsIDOMSVGMatrix> ctm = GetCanvasTM();
if (!ctm)
return;
float x, y, width, height;
mX->GetValue(&x);
mY->GetValue(&y);
mWidth->GetValue(&width);
mHeight->GetValue(&height);
TransformRect(&x, &y, &width, &height, ctm);
}
NS_IMETHODIMP
nsSVGForeignObjectFrame::GetBBox(nsIDOMSVGRect **_retval)
{
*_retval = nsnull;
float x[4], y[4], width, height;
mX->GetValue(&x[0]);
mY->GetValue(&y[0]);
mWidth->GetValue(&width);
mHeight->GetValue(&height);
x[1] = x[0] + width;
y[1] = y[0];
x[2] = x[0] + width;
y[2] = y[0] + height;
x[3] = x[0];
y[3] = y[0] + height;
TransformPoint(x[0], y[0]);
TransformPoint(x[1], y[1]);
TransformPoint(x[2], y[2]);
TransformPoint(x[3], y[3]);
float xmin, xmax, ymin, ymax;
xmin = xmax = x[0];
ymin = ymax = y[0];
for (int i=1; i<4; i++) {
if (x[i] < xmin)
xmin = x[i];
if (y[i] < ymin)
ymin = y[i];
if (x[i] > xmax)
xmax = x[i];
if (y[i] > ymax)
ymax = y[i];
}
return NS_NewSVGRect(_retval, xmin, ymin, xmax - xmin, ymax - ymin);
float x, y, w, h;
GetBBoxInternal(&x, &y, &w, &h);
return NS_NewSVGRect(_retval, x, y, w, h);
}
//----------------------------------------------------------------------
// nsISVGContainerFrame methods:
already_AddRefed<nsIDOMSVGMatrix>
nsSVGForeignObjectFrame::GetTMIncludingOffset()
{
nsCOMPtr<nsIDOMSVGMatrix> ctm = GetCanvasTM();
if (!ctm)
return nsnull;
float svgX, svgY;
mX->GetValue(&svgX);
mY->GetValue(&svgY);
nsIDOMSVGMatrix* matrix;
ctm->Translate(svgX, svgY, &matrix);
return matrix;
}
already_AddRefed<nsIDOMSVGMatrix>
nsSVGForeignObjectFrame::GetCanvasTM()
{
@ -786,42 +785,3 @@ float nsSVGForeignObjectFrame::GetTwipsPerPx()
{
return GetPresContext()->ScaledPixelsToTwips();
}
void nsSVGForeignObjectFrame::TransformPoint(float& x, float& y)
{
nsCOMPtr<nsIDOMSVGMatrix> ctm = GetCanvasTM();
if (!ctm)
return;
// XXX this is absurd! we need to add another method (interface
// even?) to nsIDOMSVGMatrix to make this easier. (something like
// nsIDOMSVGMatrix::TransformPoint(float*x,float*y))
nsCOMPtr<nsIDOMSVGPoint> point;
NS_NewSVGPoint(getter_AddRefs(point), x, y);
if (!point)
return;
nsCOMPtr<nsIDOMSVGPoint> xfpoint;
point->MatrixTransform(ctm, getter_AddRefs(xfpoint));
if (!xfpoint)
return;
xfpoint->GetX(&x);
xfpoint->GetY(&y);
}
void nsSVGForeignObjectFrame::TransformVector(float& x, float& y)
{
// XXX This is crazy. What we really want is
// nsIDOMSVGMatrix::TransformVector(x,y);
float x0=0.0f, y0=0.0f;
TransformPoint(x0, y0);
TransformPoint(x,y);
x -= x0;
y -= y0;
}

Просмотреть файл

@ -0,0 +1,177 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the Mozilla SVG project.
*
* The Initial Developer of the Original Code is
* Crocodile Clips Ltd..
* Portions created by the Initial Developer are Copyright (C) 2001
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Alex Fritze <alex.fritze@crocodile-clips.com> (original author)
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef NSSVGFOREIGNOBJECTFRAME_H__
#define NSSVGFOREIGNOBJECTFRAME_H__
#include "nsBlockFrame.h"
#include "nsISVGChildFrame.h"
#include "nsISVGContainerFrame.h"
#include "nsISVGValueObserver.h"
#include "nsWeakReference.h"
#include "nsISVGRendererRegion.h"
#include "nsIDOMSVGMatrix.h"
#include "nsIDOMSVGLength.h"
typedef nsBlockFrame nsSVGForeignObjectFrameBase;
class nsISVGFilterFrame;
class nsSVGForeignObjectFrame : public nsSVGForeignObjectFrameBase,
public nsISVGContainerFrame,
public nsISVGChildFrame,
public nsISVGValueObserver,
public nsSupportsWeakReference
{
friend nsIFrame*
NS_NewSVGForeignObjectFrame(nsIPresShell* aPresShell, nsIContent* aContent);
protected:
nsSVGForeignObjectFrame();
virtual ~nsSVGForeignObjectFrame();
nsresult Init();
// nsISupports interface:
NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr);
private:
NS_IMETHOD_(nsrefcnt) AddRef() { return NS_OK; }
NS_IMETHOD_(nsrefcnt) Release() { return NS_OK; }
public:
// nsIFrame:
NS_IMETHOD Init(nsPresContext* aPresContext,
nsIContent* aContent,
nsIFrame* aParent,
nsStyleContext* aContext,
nsIFrame* aPrevInFlow);
NS_IMETHOD Reflow(nsPresContext* aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus);
NS_IMETHOD AppendFrames(nsIAtom* aListName,
nsIFrame* aFrameList);
NS_IMETHOD InsertFrames(nsIAtom* aListName,
nsIFrame* aPrevFrame,
nsIFrame* aFrameList);
NS_IMETHOD RemoveFrame(nsIAtom* aListName,
nsIFrame* aOldFrame);
/**
* Get the "type" of the frame
*
* @see nsLayoutAtoms::svgForeignObjectFrame
*/
// XXX Need to make sure that any of the code examining
// frametypes, particularly code looking at block and area
// also handles foreignObject before we return our own frametype
// virtual nsIAtom* GetType() const;
virtual PRBool IsFrameOfType(PRUint32 aFlags) const;
#ifdef DEBUG
NS_IMETHOD GetFrameName(nsAString& aResult) const
{
return MakeFrameName(NS_LITERAL_STRING("SVGForeignObject"), aResult);
}
#endif
// nsISVGValueObserver
NS_IMETHOD WillModifySVGObservable(nsISVGValue* observable,
nsISVGValue::modificationType aModType);
NS_IMETHOD DidModifySVGObservable (nsISVGValue* observable,
nsISVGValue::modificationType aModType);
// nsISupportsWeakReference
// implementation inherited from nsSupportsWeakReference
// nsISVGChildFrame interface:
NS_IMETHOD PaintSVG(nsISVGRendererCanvas* canvas,
const nsRect& dirtyRectTwips,
PRBool ignoreFilter);
NS_IMETHOD GetFrameForPointSVG(float x, float y, nsIFrame** hit);
NS_IMETHOD_(already_AddRefed<nsISVGRendererRegion>) GetCoveredRegion();
NS_IMETHOD InitialUpdate();
NS_IMETHOD NotifyCanvasTMChanged(PRBool suppressInvalidation);
NS_IMETHOD NotifyRedrawSuspended();
NS_IMETHOD NotifyRedrawUnsuspended();
NS_IMETHOD SetMatrixPropagation(PRBool aPropagate);
NS_IMETHOD SetOverrideCTM(nsIDOMSVGMatrix *aCTM);
NS_IMETHOD GetBBox(nsIDOMSVGRect **_retval);
NS_IMETHOD GetFilterRegion(nsISVGRendererRegion **_retval) {
*_retval = mFilterRegion;
NS_IF_ADDREF(*_retval);
return NS_OK;
}
// nsISVGContainerFrame interface:
virtual already_AddRefed<nsIDOMSVGMatrix> GetCanvasTM();
virtual already_AddRefed<nsSVGCoordCtxProvider> GetCoordContextProvider();
// foreignobject public methods
/**
* @param aPt a point in the twips coordinate system of the SVG outer frame
* Transforms the point to a point in this frame's twips coordinate system
*/
nsPoint TransformPointFromOuter(nsPoint aPt);
protected:
// implementation helpers:
void Update();
already_AddRefed<nsISVGRendererRegion> DoReflow();
float GetPxPerTwips();
float GetTwipsPerPx();
// Get the bounding box relative to the outer SVG element, in user units
void GetBBoxInternal(float* aX, float *aY, float* aWidth, float *aHeight);
already_AddRefed<nsIDOMSVGMatrix> GetTMIncludingOffset();
nsresult TransformPointFromOuterPx(float aX, float aY, nsPoint* aOut);
PRBool mIsDirty;
nsCOMPtr<nsIDOMSVGLength> mX;
nsCOMPtr<nsIDOMSVGLength> mY;
nsCOMPtr<nsIDOMSVGLength> mWidth;
nsCOMPtr<nsIDOMSVGLength> mHeight;
nsCOMPtr<nsIDOMSVGMatrix> mCanvasTM;
PRBool mPropagateTransform;
nsCOMPtr<nsIDOMSVGMatrix> mOverrideCTM;
nsCOMPtr<nsISVGRendererRegion> mFilterRegion;
nsISVGFilterFrame *mFilter;
};
#endif

Просмотреть файл

@ -69,7 +69,7 @@ interface nsISVGRendererSurface;
* Mozilla-native rendering object with a call to
* nsISVGRenderer::createCanvas().
*/
[scriptable, uuid(a1ea0d56-765f-43be-88dc-e54576e5735b)]
[scriptable, uuid(81eb1fc4-ea69-45dd-b31e-fe2cbcab04a5)]
interface nsISVGRendererCanvas : nsISupports
{
/**
@ -83,7 +83,7 @@ interface nsISVGRendererCanvas : nsISupports
* @param rect Area to be locked.
* @return Mozilla-native rendering context for the locked area.
*/
[noscript] nsIRenderingContext lockRenderingContext([const] in nsRectRef rect);
[noscript] nsIRenderingContext lockRenderingContext(in nsIDOMSVGMatrix aCTM);
/**
* Unlock the canvas portion locked with a previous call to

Просмотреть файл

@ -127,7 +127,10 @@ public:
// nsISVGCairoCanvas interface:
NS_IMETHOD_(cairo_t*) GetContext() { return mCR; }
NS_IMETHOD AdjustMatrixForInitialTransform(cairo_matrix_t* aMatrix);
protected:
void SetupCairoMatrix(nsIDOMSVGMatrix *aCTM);
private:
nsCOMPtr<nsIRenderingContext> mMozContext;
nsCOMPtr<nsPresContext> mPresContext;
@ -421,14 +424,39 @@ NS_INTERFACE_MAP_END
//----------------------------------------------------------------------
// nsISVGRendererCanvas methods:
void nsSVGCairoCanvas::SetupCairoMatrix(nsIDOMSVGMatrix *aCTM)
{
float m[6];
float val;
aCTM->GetA(&val);
m[0] = val;
aCTM->GetB(&val);
m[1] = val;
aCTM->GetC(&val);
m[2] = val;
aCTM->GetD(&val);
m[3] = val;
aCTM->GetE(&val);
m[4] = val;
aCTM->GetF(&val);
m[5] = val;
cairo_matrix_t matrix = {m[0], m[1], m[2], m[3], m[4], m[5]};
AdjustMatrixForInitialTransform(&matrix);
cairo_set_matrix(mCR, &matrix);
}
/** Implements [noscript] nsIRenderingContext lockRenderingContext(const in nsRectRef rect); */
NS_IMETHODIMP
nsSVGCairoCanvas::LockRenderingContext(const nsRect & rect,
nsSVGCairoCanvas::LockRenderingContext(nsIDOMSVGMatrix* aCTM,
nsIRenderingContext **_retval)
{
// XXX do we need to flush?
Flush();
SetupCairoMatrix(aCTM);
*_retval = mMozContext;
NS_ADDREF(*_retval);
return NS_OK;
@ -663,33 +691,10 @@ nsSVGCairoCanvas::SetClipRect(nsIDOMSVGMatrix *aCTM, float aX, float aY,
if (!aCTM)
return NS_ERROR_FAILURE;
float m[6];
float val;
aCTM->GetA(&val);
m[0] = val;
aCTM->GetB(&val);
m[1] = val;
aCTM->GetC(&val);
m[2] = val;
aCTM->GetD(&val);
m[3] = val;
aCTM->GetE(&val);
m[4] = val;
aCTM->GetF(&val);
m[5] = val;
cairo_matrix_t oldMatrix;
cairo_get_matrix(mCR, &oldMatrix);
cairo_matrix_t matrix = {m[0], m[1], m[2], m[3], m[4], m[5]};
cairo_matrix_t inverse = matrix;
if (cairo_matrix_invert(&inverse))
return NS_ERROR_FAILURE;
cairo_transform(mCR, &matrix);
SetupCairoMatrix(aCTM);
cairo_new_path(mCR);
cairo_rectangle(mCR, aX, aY, aWidth, aHeight);
@ -816,28 +821,7 @@ nsSVGCairoCanvas::CompositeSurfaceMatrix(nsISVGRendererSurface *aSurface,
cairo_save(mCR);
float m[6];
float val;
aCTM->GetA(&val);
m[0] = val;
aCTM->GetB(&val);
m[1] = val;
aCTM->GetC(&val);
m[2] = val;
aCTM->GetD(&val);
m[3] = val;
aCTM->GetE(&val);
m[4] = val;
aCTM->GetF(&val);
m[5] = val;
cairo_matrix_t matrix = {m[0], m[1], m[2], m[3], m[4], m[5]};
cairo_transform(mCR, &matrix);
SetupCairoMatrix(aCTM);
cairo_set_source_surface(mCR, cairoSurface->GetSurface(), 0.0, 0.0);
cairo_paint_with_alpha(mCR, aOpacity);

Просмотреть файл

@ -1,542 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the Mozilla SVG project.
*
* The Initial Developer of the Original Code is
* Crocodile Clips Ltd..
* Portions created by the Initial Developer are Copyright (C) 2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Alex Fritze <alex.fritze@crocodile-clips.com> (original author)
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include <windows.h>
// unknwn.h is needed to build with WIN32_LEAN_AND_MEAN
#include <unknwn.h>
#include <Gdiplus.h>
using namespace Gdiplus;
#include "nsCOMPtr.h"
#include "nsSVGGDIPlusCanvas.h"
#include "nsISVGGDIPlusCanvas.h"
#include "nsIRenderingContext.h"
#include "nsIDeviceContext.h"
#include "nsTransform2D.h"
#include "nsPresContext.h"
#include "nsRect.h"
#include "nsIRenderingContextWin.h"
#include "nsIDOMSVGMatrix.h"
#include "nsISVGGDIPlusSurface.h"
#include "nsVoidArray.h"
/**
* \addtogroup gdiplus_renderer GDI+ Rendering Engine
* @{
*/
//////////////////////////////////////////////////////////////////////
/**
* GDI+ canvas implementation
*/
class nsSVGGDIPlusCanvas : public nsISVGGDIPlusCanvas
{
public:
nsSVGGDIPlusCanvas();
~nsSVGGDIPlusCanvas();
nsresult Init(nsIRenderingContext* ctx, nsPresContext* presContext,
const nsRect & dirtyRect);
// nsISupports interface:
NS_DECL_ISUPPORTS
// nsISVGRendererCanvas interface:
NS_DECL_NSISVGRENDERERCANVAS
// nsISVGGDIPlusCanvas interface:
NS_IMETHOD_(Graphics*) GetGraphics();
NS_IMETHOD_(Region*) GetClipRegion();
private:
nsCOMPtr<nsIRenderingContext> mMozContext;
nsCOMPtr<nsPresContext> mPresContext;
Graphics *mGraphics;
nsVoidArray mClipStack;
nsVoidArray mSurfaceStack;
Region mClipRegion;
PRUint16 mRenderMode;
#ifdef SVG_GDIPLUS_ENABLE_OFFSCREEN_BUFFER
Bitmap *mOffscreenBitmap;
Graphics *mOffscreenGraphics;
HDC mOffscreenHDC;
nsIDrawingSurface* mTempBuffer; // temp storage for during DC locking
#endif
};
/** @} */
//----------------------------------------------------------------------
// implementation:
nsSVGGDIPlusCanvas::nsSVGGDIPlusCanvas()
: mGraphics(nsnull)
#ifdef SVG_GDIPLUS_ENABLE_OFFSCREEN_BUFFER
, mOffscreenBitmap(nsnull), mOffscreenGraphics(nsnull), mOffscreenHDC(nsnull)
#endif
{
}
nsSVGGDIPlusCanvas::~nsSVGGDIPlusCanvas()
{
#ifdef SVG_GDIPLUS_ENABLE_OFFSCREEN_BUFFER
if (mOffscreenGraphics)
delete mOffscreenGraphics;
if (mOffscreenBitmap)
delete mOffscreenBitmap;
#endif
if (mGraphics)
delete mGraphics;
mMozContext = nsnull;
}
nsresult
nsSVGGDIPlusCanvas::Init(nsIRenderingContext* ctx,
nsPresContext* presContext,
const nsRect & dirtyRect)
{
mPresContext = presContext;
mMozContext = ctx;
NS_ASSERTION(mMozContext, "empty rendering context");
HDC hdc;
// this ctx better be what we think it is...
hdc = (HDC)(PRUint32 *)mMozContext->GetNativeGraphicData(nsIRenderingContext::NATIVE_WINDOWS_DC);
mGraphics = new Graphics(hdc);
if (!mGraphics) return NS_ERROR_FAILURE;
// Work in pixel units instead of the default DisplayUnits.
mGraphics->SetPageUnit(UnitPixel);
// We'll scale our logical 'pixles' to device units according to the
// resolution of the device. For display devices, the canonical
// pixel scale will be 1, for printers it will be some other value:
nsCOMPtr<nsIDeviceContext> devcontext;
mMozContext->GetDeviceContext(*getter_AddRefs(devcontext));
float scale;
devcontext->GetCanonicalPixelScale(scale);
mGraphics->SetPageScale(scale);
// get the translation set on the rendering context. It will be in
// displayunits (i.e. pixels*scale), *not* pixels:
nsTransform2D* xform;
mMozContext->GetCurrentTransform(xform);
float dx, dy;
xform->GetTranslation(&dx, &dy);
#if defined(DEBUG) && defined(SVG_DEBUG_PRINTING)
printf("nsSVGGDIPlusCanvas(%p)::Init()[\n", this);
printf("pagescale=%f\n", scale);
printf("page unit=%d\n", mGraphics->GetPageUnit());
printf("]\n");
#endif
#ifdef SVG_GDIPLUS_ENABLE_OFFSCREEN_BUFFER
mGraphics->TranslateTransform(dx+dirtyRect.x, dy+dirtyRect.y);
// GDI+ internally works on 32bpp surfaces. Writing directly to
// Mozilla's backbuffer can be very slow if it hasn't got the right
// format (!=32bpp). For complex SVG docs it is advantageous to
// render to a 32bppPARGB bitmap first:
mOffscreenBitmap = new Bitmap(dirtyRect.width, dirtyRect.height, PixelFormat32bppPARGB);
if (!mOffscreenBitmap) return NS_ERROR_FAILURE;
mOffscreenGraphics = new Graphics(mOffscreenBitmap);
if (!mOffscreenGraphics) return NS_ERROR_FAILURE;
mOffscreenGraphics->TranslateTransform((float)-dirtyRect.x, (float)-dirtyRect.y);
#else
mGraphics->TranslateTransform(dx/scale, dy/scale, MatrixOrderPrepend);
#endif
mRenderMode = SVG_RENDER_MODE_NORMAL;
return NS_OK;
}
nsresult
NS_NewSVGGDIPlusCanvas(nsISVGRendererCanvas **result,
nsIRenderingContext *ctx,
nsPresContext *presContext,
const nsRect & dirtyRect)
{
nsSVGGDIPlusCanvas* pg = new nsSVGGDIPlusCanvas();
if (!pg) return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(pg);
nsresult rv = pg->Init(ctx, presContext, dirtyRect);
if (NS_FAILED(rv)) {
NS_RELEASE(pg);
return rv;
}
*result = pg;
return rv;
}
//----------------------------------------------------------------------
// nsISupports methods:
NS_IMPL_ADDREF(nsSVGGDIPlusCanvas)
NS_IMPL_RELEASE(nsSVGGDIPlusCanvas)
NS_INTERFACE_MAP_BEGIN(nsSVGGDIPlusCanvas)
NS_INTERFACE_MAP_ENTRY(nsISVGRendererCanvas)
NS_INTERFACE_MAP_ENTRY(nsISVGGDIPlusCanvas)
NS_INTERFACE_MAP_ENTRY(nsISupports)
// NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISVGRendererCanvas)
NS_INTERFACE_MAP_END
//----------------------------------------------------------------------
// nsISVGRendererCanvas methods:
/** Implements [noscript] nsIRenderingContext lockRenderingContext(const in nsRectRef rect); */
NS_IMETHODIMP
nsSVGGDIPlusCanvas::LockRenderingContext(const nsRect & rect,
nsIRenderingContext **_retval)
{
#ifdef SVG_GDIPLUS_ENABLE_OFFSCREEN_BUFFER
NS_ASSERTION(!mOffscreenHDC, "offscreen hdc already created! Nested rendering context locking?");
mOffscreenHDC = mOffscreenGraphics->GetHDC();
nsCOMPtr<nsIRenderingContextWin> wincontext = do_QueryInterface(mMozContext);
NS_ASSERTION(wincontext, "no windows rendering context");
nsCOMPtr<nsIDrawingSurface> mOffscreenSurface;
wincontext->CreateDrawingSurface(mOffscreenHDC, (void*&)*getter_AddRefs(mOffscreenSurface));
mMozContext->GetDrawingSurface(&mTempBuffer);
mMozContext->SelectOffScreenDrawingSurface(mOffscreenSurface);
#else
// XXX do we need to flush?
Flush();
#endif
*_retval = mMozContext;
NS_ADDREF(*_retval);
return NS_OK;
}
/** Implements void unlockRenderingContext(); */
NS_IMETHODIMP
nsSVGGDIPlusCanvas::UnlockRenderingContext()
{
#ifdef SVG_GDIPLUS_ENABLE_OFFSCREEN_BUFFER
NS_ASSERTION(mOffscreenHDC, "offscreen hdc already freed! Nested rendering context locking?");
// restore original surface
mMozContext->SelectOffScreenDrawingSurface(mTempBuffer);
mTempBuffer = nsnull;
mOffscreenGraphics->ReleaseHDC(mOffscreenHDC);
mOffscreenHDC = nsnull;
#else
// nothing to do
#endif
return NS_OK;
}
/** Implements nsPresContext getPresContext(); */
NS_IMETHODIMP
nsSVGGDIPlusCanvas::GetPresContext(nsPresContext **_retval)
{
*_retval = mPresContext;
NS_IF_ADDREF(*_retval);
return NS_OK;
}
/** Implements void clear(in nscolor color); */
NS_IMETHODIMP
nsSVGGDIPlusCanvas::Clear(nscolor color)
{
#ifdef SVG_GDIPLUS_ENABLE_OFFSCREEN_BUFFER
mOffscreenGraphics->Clear(Color(NS_GET_R(color),
NS_GET_G(color),
NS_GET_B(color)));
#else
mGraphics->Clear(Color(NS_GET_R(color),
NS_GET_G(color),
NS_GET_B(color)));
#endif
return NS_OK;
}
/** Implements void flush(); */
NS_IMETHODIMP
nsSVGGDIPlusCanvas::Flush()
{
#ifdef SVG_GDIPLUS_ENABLE_OFFSCREEN_BUFFER
mGraphics->SetCompositingMode(CompositingModeSourceCopy);
mGraphics->DrawImage(mOffscreenBitmap, 0, 0,
mOffscreenBitmap->GetWidth(),
mOffscreenBitmap->GetHeight());
#endif
mGraphics->Flush(FlushIntentionSync);
return NS_OK;
}
//----------------------------------------------------------------------
// nsISVGGDIPlusCanvas methods:
NS_IMETHODIMP_(Graphics*)
nsSVGGDIPlusCanvas::GetGraphics()
{
#ifdef SVG_GDIPLUS_ENABLE_OFFSCREEN_BUFFER
return mOffscreenGraphics;
#else
return mGraphics;
#endif
}
NS_IMETHODIMP
nsSVGGDIPlusCanvas::GetRenderMode(PRUint16 *aMode)
{
*aMode = mRenderMode;
return NS_OK;
}
NS_IMETHODIMP
nsSVGGDIPlusCanvas::SetRenderMode(PRUint16 aMode)
{
if (mRenderMode == SVG_RENDER_MODE_CLIP && aMode == SVG_RENDER_MODE_NORMAL)
mGraphics->SetClip(&mClipRegion, CombineModeIntersect);
mRenderMode = aMode;
return NS_OK;
}
NS_IMETHODIMP_(Region*)
nsSVGGDIPlusCanvas::GetClipRegion()
{
return &mClipRegion;
}
/** Implements pushClip(); */
NS_IMETHODIMP
nsSVGGDIPlusCanvas::PushClip()
{
Region *region = new Region;
if (region)
mGraphics->GetClip(region);
// append even if we failed to allocate the region so push/pop match
mClipStack.AppendElement((void *)region);
mClipRegion.MakeEmpty();
return NS_OK;
}
/** Implements popClip(); */
NS_IMETHODIMP
nsSVGGDIPlusCanvas::PopClip()
{
PRUint32 count = mClipStack.Count();
if (count == 0)
return NS_OK;
Region *region = (Region *)mClipStack[count-1];
if (region) {
mGraphics->SetClip(region);
delete region;
}
mClipStack.RemoveElementAt(count-1);
return NS_OK;
}
/** Implements setClipRect(in nsIDOMSVGMatrix canvasTM, in float x, in float y,
in float width, in float height); */
NS_IMETHODIMP
nsSVGGDIPlusCanvas::SetClipRect(nsIDOMSVGMatrix *aCTM, float aX, float aY,
float aWidth, float aHeight)
{
if (!aCTM)
return NS_ERROR_FAILURE;
float m[6];
float val;
aCTM->GetA(&val);
m[0] = val;
aCTM->GetB(&val);
m[1] = val;
aCTM->GetC(&val);
m[2] = val;
aCTM->GetD(&val);
m[3] = val;
aCTM->GetE(&val);
m[4] = val;
aCTM->GetF(&val);
m[5] = val;
Matrix matrix(m[0], m[1], m[2], m[3], m[4], m[5]);
RectF rect(aX, aY, aWidth, aHeight);
Region clip(rect);
clip.Transform(&matrix);
mGraphics->SetClip(&clip, CombineModeIntersect);
return NS_OK;
}
/** Implements pushSurface(in nsISVGRendereerSurface surface); */
NS_IMETHODIMP
nsSVGGDIPlusCanvas::PushSurface(nsISVGRendererSurface *aSurface)
{
nsCOMPtr<nsISVGGDIPlusSurface> gdiplusSurface = do_QueryInterface(aSurface);
if (!gdiplusSurface)
return NS_ERROR_FAILURE;
mSurfaceStack.AppendElement((void *)mGraphics);
mGraphics = new Graphics(gdiplusSurface->GetSurface());
if (!mGraphics) {
PopSurface();
return NS_ERROR_FAILURE;
}
mGraphics->Clear(Color(0,0,0,0));
return NS_OK;
}
/** Implements popSurface(); */
NS_IMETHODIMP
nsSVGGDIPlusCanvas::PopSurface()
{
PRUint32 count = mSurfaceStack.Count();
if (count != 0) {
delete mGraphics;
mGraphics = (Graphics *)mSurfaceStack[count - 1];
mSurfaceStack.RemoveElementAt(count - 1);
}
return NS_OK;
}
NS_IMETHODIMP
nsSVGGDIPlusCanvas::GetSurfaceSize(PRUint32 *aWidth, PRUint32 *aHeight)
{
// XXX
return NS_ERROR_NOT_IMPLEMENTED;
}
/** Implements void compositeSurface(in nsISVGRendererSurface surface,
in unsigned long x, in unsigned long y,
in float opacity); */
NS_IMETHODIMP
nsSVGGDIPlusCanvas::CompositeSurface(nsISVGRendererSurface *aSurface,
PRUint32 aX, PRUint32 aY, float aOpacity)
{
nsCOMPtr<nsISVGGDIPlusSurface> gdiplusSurface = do_QueryInterface(aSurface);
if (!gdiplusSurface)
return NS_ERROR_FAILURE;
ColorMatrix cxform;
memset(&cxform, 0, sizeof(ColorMatrix));
cxform.m[0][0] = cxform.m[1][1] = cxform.m[2][2] = cxform.m[4][4] = 1.0f;
cxform.m[3][3] = aOpacity;
ImageAttributes attrib;
attrib.SetColorMatrix(&cxform);
PRUint32 width, height;
aSurface->GetWidth(&width);
aSurface->GetHeight(&height);
Rect rect(aX, aY, width, height);
mGraphics->DrawImage(gdiplusSurface->GetSurface(),
rect, 0, 0, width, height, UnitPixel, &attrib);
return NS_OK;
}
/** Implements void compositeSurfaceWithMask(in nsISVGRendererSurface surface,
in unsigned long x,
in unsigned long y,
in nsISVGRendererSurface mask); */
NS_IMETHODIMP
nsSVGGDIPlusCanvas::CompositeSurfaceWithMask(nsISVGRendererSurface *aSurface,
PRUint32 aX, PRUint32 aY,
nsISVGRendererSurface *aMask)
{
// XXX
return NS_ERROR_NOT_IMPLEMENTED;
}
/** Implements void compositeSurface(in nsISVGRendererSurface surface,
in nsIDOMSVGMatrix canvasTM,
in float opacity); */
NS_IMETHODIMP
nsSVGGDIPlusCanvas::CompositeSurfaceMatrix(nsISVGRendererSurface *aSurface,
nsIDOMSVGMatrix *aCTM, float aOpacity)
{
float m[6];
float val;
aCTM->GetA(&val);
m[0] = val;
aCTM->GetB(&val);
m[1] = val;
aCTM->GetC(&val);
m[2] = val;
aCTM->GetD(&val);
m[3] = val;
aCTM->GetE(&val);
m[4] = val;
aCTM->GetF(&val);
m[5] = val;
Matrix xform(m[0], m[1], m[2], m[3], m[4], m[5]), orig;
mGraphics->GetTransform(&orig);
mGraphics->MultiplyTransform(&xform);
CompositeSurface(aSurface, 0, 0, aOpacity);
mGraphics->SetTransform(&orig);
return NS_OK;
}

Просмотреть файл

@ -1,454 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the Mozilla SVG project.
*
* The Initial Developer of the Original Code is
* Alex Fritze.
* Portions created by the Initial Developer are Copyright (C) 2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Alex Fritze <alex@croczilla.com> (original author)
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsCOMPtr.h"
#include "nsSVGLibartCanvas.h"
#include "nsISVGLibartCanvas.h"
#include "nsISVGLibartBitmap.h"
#include "nsIRenderingContext.h"
#include "nsIDeviceContext.h"
#include "nsTransform2D.h"
#include "nsPresContext.h"
#include "nsRect.h"
#include "libart-incs.h"
/**
* \addtogroup libart_renderer Libart Rendering Engine
* @{
*/
////////////////////////////////////////////////////////////////////////
/**
* Libart canvas implementation
*/
class nsSVGLibartCanvas : public nsISVGLibartCanvas
{
public:
nsSVGLibartCanvas();
~nsSVGLibartCanvas();
nsresult Init(nsIRenderingContext* ctx, nsPresContext* presContext,
const nsRect & dirtyRect);
// nsISupports interface:
NS_DECL_ISUPPORTS
// nsISVGRendererCanvas interface:
NS_DECL_NSISVGRENDERERCANVAS
// nsISVGLibartCanvas interface:
NS_IMETHOD_(ArtRender*) NewRender();
NS_IMETHOD_(ArtRender*) NewRender(int x0, int y0, int x1, int y1);
NS_IMETHOD_(void) InvokeRender(ArtRender* render);
NS_IMETHOD_(void) GetArtColor(nscolor rgb, ArtColor& artColor);
private:
nsCOMPtr<nsIRenderingContext> mRenderingContext;
nsCOMPtr<nsPresContext> mPresContext;
nsCOMPtr<nsISVGLibartBitmap> mBitmap;
nsRect mDirtyRect;
};
/** @} */
//----------------------------------------------------------------------
// implementation:
nsSVGLibartCanvas::nsSVGLibartCanvas()
{
}
nsSVGLibartCanvas::~nsSVGLibartCanvas()
{
}
nsresult
nsSVGLibartCanvas::Init(nsIRenderingContext* ctx,
nsPresContext* presContext,
const nsRect & dirtyRect)
{
mPresContext = presContext;
NS_ASSERTION(mPresContext, "empty prescontext");
mRenderingContext = ctx;
NS_ASSERTION(mRenderingContext, "empty rendering context");
mDirtyRect = dirtyRect;
NS_NewSVGLibartBitmap(getter_AddRefs(mBitmap), ctx, presContext,
dirtyRect);
if (!mBitmap) {
NS_ERROR("could not construct bitmap");
return NS_ERROR_FAILURE;
}
return NS_OK;
}
nsresult
NS_NewSVGLibartCanvas(nsISVGRendererCanvas **result,
nsIRenderingContext *ctx,
nsPresContext *presContext,
const nsRect & dirtyRect)
{
nsSVGLibartCanvas* pg = new nsSVGLibartCanvas();
if (!pg) return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(pg);
nsresult rv = pg->Init(ctx, presContext, dirtyRect);
if (NS_FAILED(rv)) {
NS_RELEASE(pg);
return rv;
}
*result = pg;
return rv;
}
//----------------------------------------------------------------------
// nsISupports methods:
NS_IMPL_ADDREF(nsSVGLibartCanvas)
NS_IMPL_RELEASE(nsSVGLibartCanvas)
NS_INTERFACE_MAP_BEGIN(nsSVGLibartCanvas)
NS_INTERFACE_MAP_ENTRY(nsISVGRendererCanvas)
NS_INTERFACE_MAP_ENTRY(nsISVGLibartCanvas)
NS_INTERFACE_MAP_ENTRY(nsISupports)
// NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISVGRendererCanvas)
NS_INTERFACE_MAP_END
//----------------------------------------------------------------------
// nsISVGRendererCanvas methods:
/** Implements [noscript] nsIRenderingContext lockRenderingContext(const in nsRectRef rect); */
NS_IMETHODIMP
nsSVGLibartCanvas::LockRenderingContext(const nsRect & rect,
nsIRenderingContext **_retval)
{
*_retval = nsnull;
mBitmap->LockRenderingContext(rect, _retval);
if (!*_retval) return NS_ERROR_FAILURE;
return NS_OK;
}
/** Implements void unlockRenderingContext(); */
NS_IMETHODIMP
nsSVGLibartCanvas::UnlockRenderingContext()
{
mBitmap->UnlockRenderingContext();
return NS_OK;
}
/** Implements nsPresContext getPresContext(); */
NS_IMETHODIMP
nsSVGLibartCanvas::GetPresContext(nsPresContext **_retval)
{
*_retval = mPresContext;
NS_IF_ADDREF(*_retval);
return NS_OK;
}
/** void clear(in nscolor color); */
NS_IMETHODIMP
nsSVGLibartCanvas::Clear(nscolor color)
{
PRUint8 red = NS_GET_R(color);
PRUint8 green = NS_GET_G(color);
PRUint8 blue = NS_GET_B(color);
switch (mBitmap->GetPixelFormat()) {
case nsISVGLibartBitmap::PIXEL_FORMAT_24_RGB:
{
PRInt32 stride = mBitmap->GetLineStride();
PRInt32 width = mBitmap->GetWidth();
PRUint8* buf = mBitmap->GetBits();
PRUint8* end = buf + stride*mBitmap->GetHeight();
for ( ; buf<end; buf += stride) {
art_rgb_fill_run(buf, red, green, blue, width);
}
break;
}
case nsISVGLibartBitmap::PIXEL_FORMAT_24_BGR:
{
PRInt32 stride = mBitmap->GetLineStride();
PRInt32 width = mBitmap->GetWidth();
PRUint8* buf = mBitmap->GetBits();
PRUint8* end = buf + stride*mBitmap->GetHeight();
for ( ; buf<end; buf += stride) {
art_rgb_fill_run(buf, blue, green, red, width);
}
break;
}
case nsISVGLibartBitmap::PIXEL_FORMAT_32_ABGR:
{
NS_ASSERTION(mBitmap->GetLineStride() == 4*mBitmap->GetWidth(), "strange pixel format");
PRUint32 pixel = (blue<<24)+(green<<16)+(red<<8)+0xff;
PRUint32 *dest = (PRUint32*)mBitmap->GetBits();
PRUint32 *end = dest+mBitmap->GetWidth()*mBitmap->GetHeight();
while (dest!=end)
*dest++ = pixel;
break;
}
case nsISVGLibartBitmap::PIXEL_FORMAT_32_RGBA:
{
PRInt32 stride = mBitmap->GetLineStride();
PRInt32 width = mBitmap->GetWidth();
PRUint8* buf = mBitmap->GetBits();
PRUint8* end = buf + stride*mBitmap->GetHeight();
for ( ; buf<end; buf += stride) {
art_rgb_run_alpha(buf, red, green, blue, 0x100, width);
}
break;
}
case nsISVGLibartBitmap::PIXEL_FORMAT_32_BGRA:
{
PRInt32 stride = mBitmap->GetLineStride();
PRInt32 width = mBitmap->GetWidth();
PRUint8* buf = mBitmap->GetBits();
PRUint8* end = buf + stride*mBitmap->GetHeight();
for ( ; buf<end; buf += stride) {
art_rgb_run_alpha(buf, blue, green, red, 0x100, width);
}
break;
}
default:
NS_ERROR("Unknown pixel format");
break;
}
return NS_OK;
}
/** void flush(); */
NS_IMETHODIMP
nsSVGLibartCanvas::Flush()
{
mBitmap->Flush();
return NS_OK;
}
//----------------------------------------------------------------------
// nsISVGLibartCanvas methods:
NS_IMETHODIMP_(ArtRender*)
nsSVGLibartCanvas::NewRender()
{
ArtAlphaType alphaType = ART_ALPHA_NONE;
if (mBitmap->GetPixelFormat()==nsISVGLibartBitmap::PIXEL_FORMAT_32_ABGR ||
mBitmap->GetPixelFormat()==nsISVGLibartBitmap::PIXEL_FORMAT_32_RGBA ||
mBitmap->GetPixelFormat()==nsISVGLibartBitmap::PIXEL_FORMAT_32_BGRA)
{
alphaType = ART_ALPHA_SEPARATE;
}
return art_render_new(mDirtyRect.x, mDirtyRect.y, // x0,y0
mDirtyRect.x+mDirtyRect.width, // x1
mDirtyRect.y+mDirtyRect.height, // y1
mBitmap->GetBits(), // pixels
mBitmap->GetLineStride(), // rowstride
3, // n_chan
8, // depth
alphaType, // alpha_type
NULL //alphagamma
);
}
NS_IMETHODIMP_(ArtRender*)
nsSVGLibartCanvas::NewRender(int x0, int y0, int x1, int y1)
{
NS_ASSERTION(x0<x1 && y0<y1, "empty rect passed to NewRender()");
if (x0>=x1 || y0>=y1) return nsnull;
// only construct a render object if there is overlap with the dirty rect:
if (x1<mDirtyRect.x || x0>mDirtyRect.x+mDirtyRect.width ||
y1<mDirtyRect.y || y0>mDirtyRect.y+mDirtyRect.height)
return nsnull;
int rx0 = (x0>mDirtyRect.x ? x0 : mDirtyRect.x);
int rx1 = (x1<mDirtyRect.x+mDirtyRect.width ? x1 : mDirtyRect.x+mDirtyRect.width);
int ry0 = (y0>mDirtyRect.y ? y0 : mDirtyRect.y);
int ry1 = (y1<mDirtyRect.y+mDirtyRect.height ? y1 : mDirtyRect.y+mDirtyRect.height);
int offset = 3*(rx0-mDirtyRect.x) + mBitmap->GetLineStride()*(ry0-mDirtyRect.y);
ArtAlphaType alphaType = ART_ALPHA_NONE;
if (mBitmap->GetPixelFormat()==nsISVGLibartBitmap::PIXEL_FORMAT_32_ABGR ||
mBitmap->GetPixelFormat()==nsISVGLibartBitmap::PIXEL_FORMAT_32_RGBA ||
mBitmap->GetPixelFormat()==nsISVGLibartBitmap::PIXEL_FORMAT_32_BGRA)
{
alphaType = ART_ALPHA_SEPARATE;
}
return art_render_new(rx0, ry0, rx1, ry1,
mBitmap->GetBits()+offset, // pixels
mBitmap->GetLineStride(), // rowstride
3, // n_chan
8, // depth
alphaType, // alpha_type
NULL //alphagamma
);
}
NS_IMETHODIMP_(void)
nsSVGLibartCanvas::InvokeRender(ArtRender* render)
{
art_render_invoke(render);
}
NS_IMETHODIMP_(void)
nsSVGLibartCanvas::GetArtColor(nscolor rgb, ArtColor& artColor)
{
switch (mBitmap->GetPixelFormat()) {
case nsISVGLibartBitmap::PIXEL_FORMAT_24_RGB:
case nsISVGLibartBitmap::PIXEL_FORMAT_32_RGBA:
artColor[0] = ART_PIX_MAX_FROM_8(NS_GET_R(rgb));
artColor[1] = ART_PIX_MAX_FROM_8(NS_GET_G(rgb));
artColor[2] = ART_PIX_MAX_FROM_8(NS_GET_B(rgb));
break;
case nsISVGLibartBitmap::PIXEL_FORMAT_24_BGR:
case nsISVGLibartBitmap::PIXEL_FORMAT_32_ABGR:
case nsISVGLibartBitmap::PIXEL_FORMAT_32_BGRA:
artColor[0] = ART_PIX_MAX_FROM_8(NS_GET_B(rgb));
artColor[1] = ART_PIX_MAX_FROM_8(NS_GET_G(rgb));
artColor[2] = ART_PIX_MAX_FROM_8(NS_GET_R(rgb));
break;
default:
NS_ERROR("unknown pixel format");
break;
}
}
NS_IMETHODIMP
nsSVGLibartCanvas::GetRenderMode(PRUint16 *aMode)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsSVGLibartCanvas::SetRenderMode(PRUint16 mode)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/** Implements void flush(); */
NS_IMETHODIMP
nsSVGLibartCanvas::PushClip()
{
// XXX
return NS_ERROR_NOT_IMPLEMENTED;
}
/** Implements pushClip(); */
NS_IMETHODIMP
nsSVGLibartCanvas::PopClip()
{
// XXX
return NS_ERROR_NOT_IMPLEMENTED;
}
/** Implements setClipRect(in nsIDOMSVGMatrix canvasTM, in float x, in float y,
in float width, in float height); */
NS_IMETHODIMP
nsSVGLibartCanvas::SetClipRect(nsIDOMSVGMatrix *aCTM, float aX, float aY,
float aWidth, float aHeight)
{
// XXX
return NS_ERROR_NOT_IMPLEMENTED;
}
/** Implements pushSurface(in nsISVGRendereerSurface surface); */
NS_IMETHODIMP
nsSVGLibartCanvas::PushSurface(nsISVGRendererSurface *aSurface)
{
// XXX
return NS_ERROR_NOT_IMPLEMENTED;
}
/** Implements popSurface(); */
NS_IMETHODIMP
nsSVGLibartCanvas::PopSurface()
{
// XXX
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsSVGLibartCanvas::GetSurfaceSize(PRUint32 *aWidth, PRUint32 *aHeight)
{
// XXX
return NS_ERROR_NOT_IMPLEMENTED;
}
/** Implements void compositeSurface(in nsISVGRendererSurface surface,
in unsigned long x, in unsigned long y,
in float opacity); */
NS_IMETHODIMP
nsSVGLibartCanvas::CompositeSurface(nsISVGRendererSurface *aSurface,
PRUint32 aX, PRUint32 aY, float aOpacity)
{
// XXX
return NS_ERROR_NOT_IMPLEMENTED;
}
/** Implements void compositeSurfaceWithMask(in nsISVGRendererSurface surface,
in unsigned long x,
in unsigned long y,
in nsISVGRendererSurface mask); */
NS_IMETHODIMP
nsSVGLibartCanvas::CompositeSurfaceWithMask(nsISVGRendererSurface *aSurface,
PRUint32 aX, PRUint32 aY,
nsISVGRendererSurface *aMask)
{
// XXX
return NS_ERROR_NOT_IMPLEMENTED;
}
/** Implements void compositeSurface(in nsISVGRendererSurface surface,
in nsIDOMSVGMatrix canvasTM,
in float opacity); */
NS_IMETHODIMP
nsSVGLibartCanvas::CompositeSurfaceMatrix(nsISVGRendererSurface *aSurface,
nsIDOMSVGMatrix *aCTM, float aOpacity)
{
// XXX
return NS_ERROR_NOT_IMPLEMENTED;
}