зеркало из https://github.com/mozilla/pjs.git
Bug 326966. Reenable SVG <foreignobject> for cairo-gfx builds. r+sr=tor
This commit is contained in:
Родитель
3836721172
Коммит
3b39730db2
23
configure.in
23
configure.in
|
@ -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,
|
||||
®ion);
|
||||
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, ®ion);
|
||||
|
||||
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;
|
||||
}
|
||||
|
Загрузка…
Ссылка в новой задаче