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

Reply via email to