I've been taking a stab at bug #276431, which, in a nutshell, regards
treating SVG as just another image type by rasterizing it inside an
imgIDecoder. So far I've managed to get the decoder to parse the
source into an nsSVGDocument, and once I have a thebes surface of the
rendered document I think the rest will be relatively straightforward.
However, I'm currently running into problems in the layout process and
am hoping it's something that would be obvious to somebody who knows
this subsystem better.
Since this requires a lot of access to layout internals, I had to
create a component in the layout module to render a document to a
surface, which I'm calling from the decoder. I looked at some of the
other places where something similar is being done (nsPrintEngine,
nsCanvasRenderingContext2D, nsPresShell) and tried to do something
similar. The layout specifics are largely inspired by the incremental
reflow verification code in nsPresShell. I'll put the relevant method
at the bottom of this post.
My test involves rendering a simple SVG document to a 1000x1000 pixel
surface, and I'm getting the following error message:
###!!! ASSERTION: XXX. We shouldn't get here. Viewbox width/height is
set to 0. Need to disable display of element as per specs.: 'Error',
file
/Users/dwalters/src/mozilla/content/svg/content/src/nsSVGSVGElement.cpp,
line 1250
The resulting image is blank. I've poked around in the debugger some,
and it looks like nsSVGOuterSVGFrame::Reflow() is seeing
availableHeight as 1000 (as it's supposed to be) but availableWidth is
0. It looks like nsHTMLScrollFrame::ReflowScrolledFrame() is
responsible for knocking it down to 0 from 1000.
Does anybody have any thoughts as to why this is happening and how I
can prevent it? Maybe some tips on how to diagnose? Am I maybe just
not setting up a piece of the overall process correctly? I'd be happy
to provide the full patch if anybody is interested in taking a look.
Thanks!
Dan
NS_IMETHODIMP
nsRenderService::RenderToSurface(nsIDocument *aDocument, gfxASurface
*surface, const gfxIntSize size)
{
nsresult rv;
nsRect bounds(0, 0, size.width, size.height);
// jump through some hoops to create a nsPresShell
nsCOMPtr<nsIDeviceContext> deviceContext =
do_CreateInstance("@mozilla.org/gfx/devicecontext;1");
NS_ENSURE_TRUE(deviceContext, NS_ERROR_OUT_OF_MEMORY);
rv = deviceContext->InitForOffscreen(surface); // this is pretty
much the same as InitForPrinting, except the printing surface is
directly passed in
NS_ENSURE_SUCCESS(rv, rv);
nsRefPtr<nsPresContext> presContext = new nsPresContext(aDocument,
nsPresContext::eContext_Print);
NS_ENSURE_TRUE(presContext, NS_ERROR_OUT_OF_MEMORY);
rv = presContext->Init(deviceContext);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIViewManager> viewManager =
do_CreateInstance("@mozilla.org/view-manager;1");
NS_ENSURE_TRUE(viewManager, NS_ERROR_OUT_OF_MEMORY);
rv = viewManager->Init(deviceContext);
NS_ENSURE_SUCCESS(rv, rv);
nsIView* rootView = viewManager->CreateView(bounds, nsnull);
NS_ENSURE_TRUE(rootView, PR_FALSE);
rv = viewManager->SetRootView(rootView);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoPtr<nsStyleSet> styleSet(new nsStyleSet());
NS_ENSURE_TRUE(styleSet, NS_ERROR_OUT_OF_MEMORY);
nsCOMPtr<nsIPresShell> presShell;
rv = aDocument->CreateShell(presContext, viewManager, styleSet,
getter_AddRefs(presShell));
NS_ENSURE_SUCCESS(rv, rv);
styleSet.forget();
// layout and render the document
nsCOMPtr<nsIViewObserver> viewObserver(do_QueryInterface(presShell));
NS_ENSURE_TRUE(viewObserver, PR_FALSE);
viewManager->SetViewObserver(viewObserver);
rv = presShell->InitialReflow(bounds.width, bounds.height);
NS_ENSURE_SUCCESS(rv, rv);
rv = presShell->FlushPendingNotifications(Flush_Display);
NS_ENSURE_SUCCESS(rv, rv);
nsRefPtr<gfxContext> context = new gfxContext(surface);
NS_ENSURE_TRUE(context, NS_ERROR_OUT_OF_MEMORY);
rv = presShell->RenderDocument(bounds, PR_FALSE, PR_FALSE,
NS_RGB(255, 255, 0), context);
NS_ENSURE_SUCCESS(rv, rv);
presShell->Destroy();
#ifdef DEBUG
rv = DumpToPNG(surface, size); // similar to the one in nsPresShell.cpp
NS_ENSURE_SUCCESS(rv, rv);
#endif
return NS_OK;
}
If it makes a difference, the SVG document I'm testing with is:
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
version="1.1"
baseProfile="full">
<g fill-opacity="0.7" stroke="black" stroke-width="0.1cm">
<circle cx="6cm" cy="2cm" r="100" fill="red"
transform="translate(0,50)" />
<circle cx="6cm" cy="2cm" r="100" fill="blue"
transform="translate(70,150)" />
<circle cx="6cm" cy="2cm" r="100" fill="green"
transform="translate(-70,150)" />
</g>
</svg>
_______________________________________________
dev-tech-layout mailing list
[email protected]
https://lists.mozilla.org/listinfo/dev-tech-layout