diff --git a/mozilla/configure.in b/mozilla/configure.in index 373f1444f54..c71bd12d7f2 100644 --- a/mozilla/configure.in +++ b/mozilla/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 dnl ======================================================== -dnl MOZ_ARG_ENABLE_BOOL(svg-foreignobject, -dnl [ --enable-svg-foreignobject -dnl Enable SVG 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 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([ requires cairo gfx]) + else + AC_DEFINE(MOZ_SVG_FOREIGNOBJECT) + fi +fi dnl ======================================================== dnl Installer diff --git a/mozilla/layout/base/nsLayoutUtils.cpp b/mozilla/layout/base/nsLayoutUtils.cpp index ba0f1256452..c03c2f3fc9d 100644 --- a/mozilla/layout/base/nsLayoutUtils.cpp +++ b/mozilla/layout/base/nsLayoutUtils.cpp @@ -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 diff --git a/mozilla/layout/svg/base/src/Makefile.in b/mozilla/layout/svg/base/src/Makefile.in index 20aaba94c7e..e8d4a9eb63f 100644 --- a/mozilla/layout/svg/base/src/Makefile.in +++ b/mozilla/layout/svg/base/src/Makefile.in @@ -108,6 +108,7 @@ FORCE_STATIC_LIB = 1 EXPORTS = \ nsSVGUtils.h \ nsSVGFilterInstance.h \ + nsSVGForeignObjectFrame.h \ $(NULL) include $(topsrcdir)/config/rules.mk diff --git a/mozilla/layout/svg/base/src/nsSVGForeignObjectFrame.cpp b/mozilla/layout/svg/base/src/nsSVGForeignObjectFrame.cpp index 86c48e691b3..27e0cbb0f75 100644 --- a/mozilla/layout/svg/base/src/nsSVGForeignObjectFrame.cpp +++ b/mozilla/layout/svg/base/src/nsSVGForeignObjectFrame.cpp @@ -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) 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 GetCanvasTM(); - already_AddRefed GetCoordContextProvider(); - -protected: - // implementation helpers: - void Update(); - already_AddRefed DoReflow(); - float GetPxPerTwips(); - float GetTwipsPerPx(); - void TransformPoint(float& x, float& y); - void TransformVector(float& x, float& y); - - PRBool mIsDirty; - nsCOMPtr mX; - nsCOMPtr mY; - nsCOMPtr mWidth; - nsCOMPtr mHeight; - nsCOMPtr mCanvasTM; - PRBool mPropagateTransform; - nsCOMPtr 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 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 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 region = DoReflow(); } - nsPresContext *presContext = GetPresContext(); - - nsRect r(mRect); - if (!r.IntersectRect(dirtyRectTwips, r)) - return PR_TRUE; + /* check for filter */ + if (!ignoreFilter) { + if (!mFilter) { + nsCOMPtr 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 tm = GetTMIncludingOffset(); + nsCOMPtr 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 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 tm = GetTMIncludingOffset(); + nsCOMPtr 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) 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 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 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 +nsSVGForeignObjectFrame::GetTMIncludingOffset() +{ + nsCOMPtr 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 nsSVGForeignObjectFrame::GetCanvasTM() { @@ -786,42 +785,3 @@ float nsSVGForeignObjectFrame::GetTwipsPerPx() { return GetPresContext()->ScaledPixelsToTwips(); } - -void nsSVGForeignObjectFrame::TransformPoint(float& x, float& y) -{ - nsCOMPtr 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 point; - NS_NewSVGPoint(getter_AddRefs(point), x, y); - if (!point) - return; - - nsCOMPtr 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; -} - - - diff --git a/mozilla/layout/svg/base/src/nsSVGForeignObjectFrame.h b/mozilla/layout/svg/base/src/nsSVGForeignObjectFrame.h new file mode 100644 index 00000000000..53d881e88e4 --- /dev/null +++ b/mozilla/layout/svg/base/src/nsSVGForeignObjectFrame.h @@ -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 (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) 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 GetCanvasTM(); + virtual already_AddRefed 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 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 GetTMIncludingOffset(); + nsresult TransformPointFromOuterPx(float aX, float aY, nsPoint* aOut); + + PRBool mIsDirty; + nsCOMPtr mX; + nsCOMPtr mY; + nsCOMPtr mWidth; + nsCOMPtr mHeight; + nsCOMPtr mCanvasTM; + PRBool mPropagateTransform; + nsCOMPtr mOverrideCTM; + + nsCOMPtr mFilterRegion; + nsISVGFilterFrame *mFilter; +}; + +#endif diff --git a/mozilla/layout/svg/renderer/public/nsISVGRendererCanvas.idl b/mozilla/layout/svg/renderer/public/nsISVGRendererCanvas.idl index 3fb1d63da10..89f5b041ea8 100644 --- a/mozilla/layout/svg/renderer/public/nsISVGRendererCanvas.idl +++ b/mozilla/layout/svg/renderer/public/nsISVGRendererCanvas.idl @@ -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 diff --git a/mozilla/layout/svg/renderer/src/cairo/nsSVGCairoCanvas.cpp b/mozilla/layout/svg/renderer/src/cairo/nsSVGCairoCanvas.cpp index ae2a0f1a0f4..efe80a379a5 100644 --- a/mozilla/layout/svg/renderer/src/cairo/nsSVGCairoCanvas.cpp +++ b/mozilla/layout/svg/renderer/src/cairo/nsSVGCairoCanvas.cpp @@ -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 mMozContext; nsCOMPtr 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); diff --git a/mozilla/layout/svg/renderer/src/gdiplus/nsSVGGDIPlusCanvas.cpp b/mozilla/layout/svg/renderer/src/gdiplus/nsSVGGDIPlusCanvas.cpp index 43172b921d4..74ae55836a5 100644 --- a/mozilla/layout/svg/renderer/src/gdiplus/nsSVGGDIPlusCanvas.cpp +++ b/mozilla/layout/svg/renderer/src/gdiplus/nsSVGGDIPlusCanvas.cpp @@ -231,7 +231,7 @@ NS_INTERFACE_MAP_END /** Implements [noscript] nsIRenderingContext lockRenderingContext(const in nsRectRef rect); */ NS_IMETHODIMP -nsSVGGDIPlusCanvas::LockRenderingContext(const nsRect & rect, +nsSVGGDIPlusCanvas::LockRenderingContext(nsIDOMSVGMatrix* aCTM, nsIRenderingContext **_retval) { #ifdef SVG_GDIPLUS_ENABLE_OFFSCREEN_BUFFER diff --git a/mozilla/layout/svg/renderer/src/libart/nsSVGLibartCanvas.cpp b/mozilla/layout/svg/renderer/src/libart/nsSVGLibartCanvas.cpp index b43ebd5b266..83cd9525824 100644 --- a/mozilla/layout/svg/renderer/src/libart/nsSVGLibartCanvas.cpp +++ b/mozilla/layout/svg/renderer/src/libart/nsSVGLibartCanvas.cpp @@ -158,13 +158,10 @@ NS_INTERFACE_MAP_END /** Implements [noscript] nsIRenderingContext lockRenderingContext(const in nsRectRef rect); */ NS_IMETHODIMP -nsSVGLibartCanvas::LockRenderingContext(const nsRect & rect, +nsSVGLibartCanvas::LockRenderingContext(nsIDOMSVGMatrix* aCTM, nsIRenderingContext **_retval) { - *_retval = nsnull; - mBitmap->LockRenderingContext(rect, _retval); - if (!*_retval) return NS_ERROR_FAILURE; - return NS_OK; + return NS_ERROR_FAILURE; } /** Implements void unlockRenderingContext(); */