diff --git a/mozilla/layout/base/nsDocumentViewer.cpp b/mozilla/layout/base/nsDocumentViewer.cpp index a0c9307f811..272f036534a 100644 --- a/mozilla/layout/base/nsDocumentViewer.cpp +++ b/mozilla/layout/base/nsDocumentViewer.cpp @@ -894,110 +894,6 @@ DocumentViewerImpl::InitInternal(nsIWidget* aParentWidget, return rv; } -void -DocumentViewerImpl::DumpContentToPPM(const char* aFileName) -{ - mDocument->FlushPendingNotifications(Flush_Display); - - nsIScrollableView* scrollableView; - mViewManager->GetRootScrollableView(&scrollableView); - nsIView* view; - if (scrollableView) { - scrollableView->GetScrolledView(view); - } else { - mViewManager->GetRootView(view); - } - nsRect r = view->GetBounds() - view->GetPosition(); - // Limit the bitmap size to 5000x5000 - nscoord twipLimit = mPresContext->DevPixelsToAppUnits(5000); - if (r.height > twipLimit) - r.height = twipLimit; - if (r.width > twipLimit) - r.width = twipLimit; - - const char* status; - - if (r.IsEmpty()) { - status = "EMPTY"; - } else { - nsCOMPtr context; - nsresult rv = mPresShell->RenderOffscreen(r, PR_FALSE, PR_TRUE, - NS_RGB(255, 255, 255), - getter_AddRefs(context)); - - if (NS_FAILED(rv)) { - status = "FAILEDRENDER"; - } else { - nsIDrawingSurface* surface; - context->GetDrawingSurface(&surface); - if (!surface) { - status = "NOSURFACE"; - } else { - PRUint32 width = mPresContext->AppUnitsToDevPixels(view->GetBounds().width); - PRUint32 height = mPresContext->AppUnitsToDevPixels(view->GetBounds().height); - - PRUint8* data; - PRInt32 rowLen, rowSpan; - rv = surface->Lock(0, 0, width, height, (void**)&data, &rowSpan, &rowLen, - NS_LOCK_SURFACE_READ_ONLY); - if (NS_FAILED(rv)) { - status = "FAILEDLOCK"; - } else { - PRUint32 bytesPerPix = rowLen/width; - nsPixelFormat format; - surface->GetPixelFormat(&format); - - PRUint8* buf = new PRUint8[3*width]; - if (buf) { - FILE* f = fopen(aFileName, "wb"); - if (!f) { - status = "FOPENFAILED"; - } else { - fprintf(f, "P6\n%d\n%d\n255\n", width, height); - for (PRUint32 i = 0; i < height; ++i) { - PRUint8* src = data + i*rowSpan; - PRUint8* dest = buf; - for (PRUint32 j = 0; j < width; ++j) { - /* v is the pixel value */ -#ifdef IS_BIG_ENDIAN - PRUint32 v = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3]; - v >>= (32 - 8*bytesPerPix); -#else - PRUint32 v = src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24); -#endif - dest[0] = ((v & format.mRedMask) >> format.mRedShift) << (8 - format.mRedCount); - dest[1] = ((v & format.mGreenMask) >> format.mGreenShift) << (8 - format.mGreenCount); - dest[2] = ((v & format.mBlueMask) >> format.mBlueShift) << (8 - format.mBlueCount); - src += bytesPerPix; - dest += 3; - } - fwrite(buf, 3, width, f); - } - fclose(f); - status = "OK"; - } - - delete[] buf; - } - else { - status = "OOM"; - } - surface->Unlock(); - } - context->DestroyDrawingSurface(surface); - } - } - } - - nsIURI *uri = mDocument->GetDocumentURI(); - nsCAutoString spec; - if (uri) { - uri->GetAsciiSpec(spec); - } - printf("GECKO: PAINT FORCED AFTER ONLOAD: %s %s (%s)\n", spec.get(), aFileName, status); - fflush(stdout); -} - // // LoadComplete(aStatus) // @@ -1092,17 +988,6 @@ DocumentViewerImpl::LoadComplete(nsresult aStatus) mPresShell->UnsuppressPainting(); } - static PRBool forcePaint - = PR_GetEnv("MOZ_FORCE_PAINT_AFTER_ONLOAD") != nsnull; - static PRUint32 index = 0; - if (forcePaint) { - nsCAutoString name(PR_GetEnv("MOZ_FORCE_PAINT_AFTER_ONLOAD")); - name.AppendLiteral("-"); - ++index; - name.AppendInt(index); - DumpContentToPPM(name.get()); - } - nsJSContext::LoadEnd(); #ifdef NS_PRINTING diff --git a/mozilla/layout/base/nsIPresShell.h b/mozilla/layout/base/nsIPresShell.h index 82a9a95c796..6b955deba1b 100644 --- a/mozilla/layout/base/nsIPresShell.h +++ b/mozilla/layout/base/nsIPresShell.h @@ -97,14 +97,15 @@ template class nsCOMArray; class nsWeakFrame; class nsIScrollableFrame; class gfxASurface; +class gfxContext; typedef short SelectionType; typedef PRUint32 nsFrameState; -// DC543B71-6F1A-4B9F-B4CF-693AEC4BA24A +// 9562bb2b-990c-4875-aafd-bd46fc9a4fc1 #define NS_IPRESSHELL_IID \ -{ 0xdc543b71, 0x6f1a, 0x4b9f, \ - { 0xb4, 0xcf, 0x69, 0x3a, 0xec, 0x4b, 0xa2, 0x4a } } +{ 0x9562bb2b, 0x990c, 0x4875, \ + { 0xaa, 0xfd, 0xbd, 0x46, 0xfc, 0x9a, 0x4f, 0xc1 } } // Constants for ScrollContentIntoView() function #define NS_PRESSHELL_SCROLL_TOP 0 @@ -672,7 +673,10 @@ public: } /** - * Dump window contents into a new offscreen rendering context. + * Render the document into an arbitrary gfxContext + * Designed for getting a picture of a document or a piece of a document + * Note that callers will generally want to call FlushPendingNotifications + * to get an up-to-date view of the document * @param aRect is the region to capture into the offscreen buffer, in the * root frame's coordinate system (if aIgnoreViewportScrolling is false) * or in the root scrolled frame's coordinate system @@ -684,15 +688,12 @@ public: * @param aIgnoreViewportScrolling ignore clipping/scrolling/scrollbar painting * due to scrolling in the viewport * @param aBackgroundColor a background color to render onto - * @param aRenderedContext gets set to a rendering context whose offscreen - * buffer can be locked to get the data. The buffer's size will be aRect's size. - * In all cases the caller must clean it up by calling - * cx->DestroyDrawingSurface(cx->GetDrawingSurface()). + * @param aRenderedContext the gfxContext to render to */ - NS_IMETHOD RenderOffscreen(nsRect aRect, PRBool aUntrusted, - PRBool aIgnoreViewportScrolling, - nscolor aBackgroundColor, - nsIRenderingContext** aRenderedContext) = 0; + NS_IMETHOD RenderDocument(const nsRect& aRect, PRBool aUntrusted, + PRBool aIgnoreViewportScrolling, + nscolor aBackgroundColor, + gfxContext* aRenderedContext) = 0; /** * Renders a node aNode to a surface and returns it. The aRegion may be used diff --git a/mozilla/layout/base/nsPresShell.cpp b/mozilla/layout/base/nsPresShell.cpp index 399b96d4184..abc99cb72d6 100644 --- a/mozilla/layout/base/nsPresShell.cpp +++ b/mozilla/layout/base/nsPresShell.cpp @@ -199,6 +199,8 @@ // Content viewer interfaces #include "nsIContentViewer.h" +#include "imgIEncoder.h" +#include "gfxPlatform.h" #include "nsContentCID.h" static NS_DEFINE_CID(kCSSStyleSheetCID, NS_CSS_STYLESHEET_CID); @@ -873,10 +875,10 @@ public: virtual void Freeze(); virtual void Thaw(); - NS_IMETHOD RenderOffscreen(nsRect aRect, PRBool aUntrusted, - PRBool aIgnoreViewportScrolling, - nscolor aBackgroundColor, - nsIRenderingContext** aRenderedContext); + NS_IMETHOD RenderDocument(const nsRect& aRect, PRBool aUntrusted, + PRBool aIgnoreViewportScrolling, + nscolor aBackgroundColor, + gfxContext* aThebesContext); virtual already_AddRefed RenderNode(nsIDOMNode* aNode, nsIRegion* aRegion, @@ -2918,6 +2920,8 @@ nsIPresShell::GetRootScrollFrameAsScrollable() const return nsnull; nsIScrollableFrame* scrollableFrame = nsnull; CallQueryInterface(frame, &scrollableFrame); + NS_ASSERTION(scrollableFrame, + "All scroll frames must implement nsIScrollableFrame"); return scrollableFrame; } @@ -3082,6 +3086,7 @@ PresShell::FrameNeedsReflow(nsIFrame *aFrame, IntrinsicDirty aIntrinsicDirty, if (mInVerifyReflow) { return NS_OK; } + if (VERIFY_REFLOW_NOISY_RC & gVerifyReflowFlags) { printf("\nPresShell@%p: frame %p needs reflow\n", (void*)this, (void*)aFrame); if (VERIFY_REFLOW_REALLY_NOISY_RC & gVerifyReflowFlags) { @@ -4633,83 +4638,76 @@ PresShell::ComputeRepaintRegionForCopy(nsIView* aRootView, } NS_IMETHODIMP -PresShell::RenderOffscreen(nsRect aRect, PRBool aUntrusted, - PRBool aIgnoreViewportScrolling, - nscolor aBackgroundColor, - nsIRenderingContext** aRenderedContext) +PresShell::RenderDocument(const nsRect& aRect, PRBool aUntrusted, + PRBool aIgnoreViewportScrolling, + nscolor aBackgroundColor, + gfxContext* aThebesContext) { - nsIView* rootView; - mViewManager->GetRootView(rootView); - NS_ASSERTION(rootView, "No root view?"); - nsIWidget* rootWidget = rootView->GetWidget(); - NS_ASSERTION(rootWidget, "No root widget?"); + NS_ENSURE_TRUE(!aUntrusted, NS_ERROR_NOT_IMPLEMENTED); - *aRenderedContext = nsnull; + aThebesContext->PushGroup(NS_GET_A(aBackgroundColor) == 0xff ? + gfxASurface::CONTENT_COLOR : + gfxASurface::CONTENT_COLOR_ALPHA); - NS_ASSERTION(!aUntrusted, "We don't support untrusted yet"); - if (aUntrusted) - return NS_ERROR_NOT_IMPLEMENTED; + aThebesContext->Save(); - nsCOMPtr tmpContext; - mPresContext->DeviceContext()->CreateRenderingContext(rootWidget, - *getter_AddRefs(tmpContext)); - if (!tmpContext) - return NS_ERROR_FAILURE; - - nsRect bounds(nsPoint(0, 0), aRect.Size()); - bounds.ScaleRoundOut(1.0f / mPresContext->AppUnitsPerDevPixel()); - - nsIDrawingSurface* surface; - nsresult rv - = tmpContext->CreateDrawingSurface(bounds, NS_CREATEDRAWINGSURFACE_FOR_PIXEL_ACCESS, - surface); - if (NS_FAILED(rv)) - return NS_ERROR_FAILURE; - nsCOMPtr localcx; - rv = nsLayoutUtils::CreateOffscreenContext(mPresContext->DeviceContext(), - surface, aRect, getter_AddRefs(localcx)); - if (NS_FAILED(rv)) { - tmpContext->DestroyDrawingSurface(surface); - return NS_ERROR_FAILURE; + // draw background color + if (NS_GET_A(aBackgroundColor) > 0) { + aThebesContext->SetColor(gfxRGBA(aBackgroundColor)); + aThebesContext->SetOperator(gfxContext::OPERATOR_SOURCE); + aThebesContext->Paint(); } - // clipping and translation is set by CreateOffscreenContext - localcx->SetColor(aBackgroundColor); - localcx->FillRect(aRect); + // we want the window to be composited as a single image using + // whatever operator was set, so set this to the default OVER; + // the original operator will be present when we PopGroup + aThebesContext->SetOperator(gfxContext::OPERATOR_OVER); nsIFrame* rootFrame = FrameManager()->GetRootFrame(); - if (!rootFrame) { - localcx.swap(*aRenderedContext); - return NS_OK; - } - - nsDisplayListBuilder builder(rootFrame, PR_FALSE, PR_FALSE); - nsDisplayList list; - nsIScrollableView* scrollingView = nsnull; - mViewManager->GetRootScrollableView(&scrollingView); - nsRect r = aRect; - if (aIgnoreViewportScrolling && scrollingView) { - nscoord x, y; - scrollingView->GetScrollPosition(x, y); - localcx->Translate(x, y); - r.MoveBy(-x, -y); - builder.SetIgnoreScrollFrame(GetRootScrollFrame()); + if (rootFrame) { + nsDisplayListBuilder builder(rootFrame, PR_FALSE, PR_FALSE); + nsDisplayList list; + + nsRect rect(aRect); + nsIFrame* rootScrollFrame = GetRootScrollFrame(); + if (aIgnoreViewportScrolling && rootScrollFrame) { + nsPoint pos = GetRootScrollFrameAsScrollable()->GetScrollPosition(); + rect.MoveBy(-pos); + builder.SetIgnoreScrollFrame(rootScrollFrame); + } + + builder.EnterPresShell(rootFrame, rect); + + nsresult rv = rootFrame->BuildDisplayListForStackingContext(&builder, rect, &list); + + builder.LeavePresShell(rootFrame, rect); + + if (NS_SUCCEEDED(rv)) { + nscoord appUnitsPerDevPixel = mPresContext->AppUnitsPerDevPixel(); + // Ensure that r.x,r.y gets drawn at (0,0) + aThebesContext->Save(); + aThebesContext->Translate(gfxPoint(-NSAppUnitsToFloatPixels(rect.x,appUnitsPerDevPixel), + -NSAppUnitsToFloatPixels(rect.y,appUnitsPerDevPixel))); + + nsIDeviceContext* devCtx = mPresContext->DeviceContext(); + nsCOMPtr rc; + devCtx->CreateRenderingContextInstance(*getter_AddRefs(rc)); + rc->Init(devCtx, aThebesContext); + + nsRegion region(rect); + list.OptimizeVisibility(&builder, ®ion); + list.Paint(&builder, rc, rect); + // Flush the list so we don't trigger the IsEmpty-on-destruction assertion + list.DeleteAll(); + + aThebesContext->Restore(); + } } - builder.EnterPresShell(rootFrame, r); + aThebesContext->Restore(); + aThebesContext->PopGroupToSource(); + aThebesContext->Paint(); - rv = rootFrame->BuildDisplayListForStackingContext(&builder, r, &list); - - builder.LeavePresShell(rootFrame, r); - NS_ENSURE_SUCCESS(rv, rv); - - nsRegion region(r); - list.OptimizeVisibility(&builder, ®ion); - list.Paint(&builder, localcx, r); - // Flush the list so we don't trigger the IsEmpty-on-destruction assertion - list.DeleteAll(); - - localcx.swap(*aRenderedContext); return NS_OK; } @@ -6442,6 +6440,10 @@ CompareTrees(nsPresContext* aFirstPresContext, nsIFrame* aFirstFrame, { if (!aFirstPresContext || !aFirstFrame || !aSecondPresContext || !aSecondFrame) return PR_TRUE; + // XXX Evil hack to reduce false positives; I can't seem to figure + // out how to flush scrollbar changes correctly + //if (aFirstFrame->GetType() == nsGkAtoms::scrollbarFrame) + // return PR_TRUE; PRBool ok = PR_TRUE; nsIAtom* listName = nsnull; PRInt32 listIndex = 0; @@ -6706,12 +6708,16 @@ PresShell::CloneStyleSet(nsStyleSet* aSet, nsStyleSet** aResult) clone->AppendStyleSheet(nsStyleSet::eOverrideSheet, ss); } + // The document expects to insert document stylesheets itself +#if 0 n = aSet->SheetCount(nsStyleSet::eDocSheet); for (i = 0; i < n; i++) { nsIStyleSheet* ss = aSet->StyleSheetAt(nsStyleSet::eDocSheet, i); if (ss) clone->AddDocStyleSheet(ss, mDocument); } +#endif + n = aSet->SheetCount(nsStyleSet::eUserSheet); for (i = 0; i < n; i++) { nsIStyleSheet* ss = aSet->StyleSheetAt(nsStyleSet::eUserSheet, i); @@ -6729,6 +6735,66 @@ PresShell::CloneStyleSet(nsStyleSet* aSet, nsStyleSet** aResult) return NS_OK; } +#ifdef DEBUG_Eli +static nsresult +DumpToPNG(nsIPresShell* shell, nsAString& name) { + PRInt32 width=1000, height=1000; + nsRect r(0, 0, shell->GetPresContext()->DevPixelsToAppUnits(width), + shell->GetPresContext()->DevPixelsToAppUnits(height)); + + nsRefPtr imgSurface = + new gfxImageSurface(gfxIntSize(width, height), + gfxImageSurface::ImageFormatARGB32); + NS_ENSURE_TRUE(imgSurface, NS_ERROR_OUT_OF_MEMORY); + + nsRefPtr imgContext = new gfxContext(imgSurface); + + nsRefPtr surface = + gfxPlatform::GetPlatform()-> + CreateOffscreenSurface(gfxIntSize(width, height), + gfxASurface::ImageFormatARGB32); + NS_ENSURE_TRUE(surface, NS_ERROR_OUT_OF_MEMORY); + + nsRefPtr context = new gfxContext(surface); + NS_ENSURE_TRUE(context, NS_ERROR_OUT_OF_MEMORY); + + nsresult rv = shell->RenderDocument(r, PR_FALSE, PR_FALSE, + NS_RGB(255, 255, 0), context); + NS_ENSURE_SUCCESS(rv, rv); + + imgContext->DrawSurface(surface, gfxSize(width, height)); + + nsCOMPtr encoder = do_CreateInstance("@mozilla.org/image/encoder;2?type=image/png"); + NS_ENSURE_TRUE(encoder, NS_ERROR_FAILURE); + encoder->InitFromData(imgSurface->Data(), imgSurface->Stride() * height, + width, height, imgSurface->Stride(), + imgIEncoder::INPUT_FORMAT_HOSTARGB, EmptyString()); + + // XXX not sure if this is the right way to write to a file + nsCOMPtr file = do_CreateInstance("@mozilla.org/file/local;1"); + NS_ENSURE_TRUE(file, NS_ERROR_FAILURE); + rv = file->InitWithPath(name); + NS_ENSURE_SUCCESS(rv, rv); + + PRUint32 length; + encoder->Available(&length); + + nsCOMPtr outputStream; + rv = NS_NewLocalFileOutputStream(getter_AddRefs(outputStream), file); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr bufferedOutputStream; + rv = NS_NewBufferedOutputStream(getter_AddRefs(bufferedOutputStream), + outputStream, length); + + PRUint32 numWritten; + rv = bufferedOutputStream->WriteFrom(encoder, length, &numWritten); + NS_ENSURE_SUCCESS(rv, rv); + + return NS_OK; +} +#endif + // After an incremental reflow, we verify the correctness by doing a // full reflow into a fresh frame tree. PRBool @@ -6796,6 +6862,9 @@ PresShell::VerifyIncrementalReflow() mDocument->BindingManager()->ProcessAttachedQueue(); sh->FlushPendingNotifications(Flush_Layout); sh->SetVerifyReflowEnable(PR_TRUE); // turn on verify reflow again now that we're done reflowing the test frame tree + // Force the non-primary presshell to unsuppress; it doesn't want to normally + // because it thinks it's hidden + ((PresShell*)sh.get())->mPaintingSuppressed = PR_FALSE; if (VERIFY_REFLOW_NOISY & gVerifyReflowFlags) { printf("Verification Tree built, comparing...\n"); } @@ -6818,6 +6887,25 @@ PresShell::VerifyIncrementalReflow() } } +#ifdef DEBUG_Eli + // Sample code for dumping page to png + // XXX Needs to be made more flexible + if (!ok) { + nsString stra; + static int num = 0; + stra.AppendLiteral("C:\\mozilla\\mozilla\\debug\\filea"); + stra.AppendInt(num); + stra.AppendLiteral(".png"); + DumpToPNG(sh, stra); + nsString strb; + strb.AppendLiteral("C:\\mozilla\\mozilla\\debug\\fileb"); + strb.AppendInt(num); + strb.AppendLiteral(".png"); + DumpToPNG(this, strb); + ++num; + } +#endif + sh->EndObservingDocument(); sh->Destroy(); if (VERIFY_REFLOW_NOISY & gVerifyReflowFlags) { diff --git a/mozilla/view/public/nsIViewObserver.h b/mozilla/view/public/nsIViewObserver.h index 07b185a6bf0..224379cab33 100644 --- a/mozilla/view/public/nsIViewObserver.h +++ b/mozilla/view/public/nsIViewObserver.h @@ -91,15 +91,6 @@ public: nsGUIEvent* aEvent, nsEventStatus* aEventStatus) = 0; - /** - * This is temporary until nsIViewManager::RenderOffscreen goes away (which - * will happen when views, and hence this entire interface, go away!). - */ - NS_IMETHOD RenderOffscreen(nsRect aRect, PRBool aUntrusted, - PRBool aIgnoreViewportScrolling, - nscolor aBackgroundColor, - nsIRenderingContext** aRenderedContext) = 0; - /* called when the view has been resized and the * content within the view needs to be reflowed. * @param aWidth - new width of view