diff --git a/content/base/src/nsGkAtomList.h b/content/base/src/nsGkAtomList.h index c856ad8bb66a..e166b2fd56e3 100644 --- a/content/base/src/nsGkAtomList.h +++ b/content/base/src/nsGkAtomList.h @@ -196,6 +196,7 @@ GK_ATOM(clear, "clear") GK_ATOM(click, "click") GK_ATOM(clickcount, "clickcount") GK_ATOM(clip, "clip") +GK_ATOM(clonedTextForPrint, "clonedTextForPrint") GK_ATOM(close, "close") GK_ATOM(closed, "closed") GK_ATOM(closemenu, "closemenu") diff --git a/content/base/src/nsTextFragment.cpp b/content/base/src/nsTextFragment.cpp index ccae94356cdb..6da0456eef22 100644 --- a/content/base/src/nsTextFragment.cpp +++ b/content/base/src/nsTextFragment.cpp @@ -106,6 +106,7 @@ nsTextFragment::Shutdown() nsTextFragment::~nsTextFragment() { ReleaseText(); + MOZ_COUNT_DTOR(nsTextFragment); } void diff --git a/content/base/src/nsTextFragment.h b/content/base/src/nsTextFragment.h index 6c65e147f9f9..abf2e1517da3 100644 --- a/content/base/src/nsTextFragment.h +++ b/content/base/src/nsTextFragment.h @@ -45,6 +45,7 @@ #define nsTextFragment_h___ #include "nsAString.h" +#include "nsTraceRefcnt.h" class nsString; class nsCString; @@ -88,6 +89,7 @@ public: nsTextFragment() : m1b(nsnull), mAllBits(0) { + MOZ_COUNT_CTOR(nsTextFragment); NS_ASSERTION(sizeof(FragmentBits) == 4, "Bad field packing!"); } diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp index 371620b0e53b..dea54101389d 100644 --- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -12330,7 +12330,8 @@ nsCSSFrameConstructor::RebuildAllStyleData(nsChangeHint aExtraHint) NS_UpdateHint(aExtraHint, mRebuildAllExtraHint); mRebuildAllExtraHint = nsChangeHint(0); - if (!mPresShell || !mPresShell->GetRootFrame()) + if (!mPresShell || !mPresShell->GetRootFrame() || + !mPresShell->GetPresContext()->IsDynamic()) return; nsAutoScriptBlocker scriptBlocker; diff --git a/layout/base/nsDocumentViewer.cpp b/layout/base/nsDocumentViewer.cpp index 473064a4893c..5bc2195eabe6 100644 --- a/layout/base/nsDocumentViewer.cpp +++ b/layout/base/nsDocumentViewer.cpp @@ -456,6 +456,8 @@ protected: unsigned mClosingWhilePrinting : 1; #if NS_PRINT_PREVIEW + unsigned mPrintPreviewZoomed : 1; + // These data members support delayed printing when the document is loading unsigned mPrintIsPending : 1; unsigned mPrintDocIsFullyLoaded : 1; @@ -463,6 +465,8 @@ protected: nsCOMPtr mCachedPrintWebProgressListner; nsCOMPtr mPrintEngine; + float mOriginalPrintPreviewScale; + float mPrintPreviewZoom; #endif // NS_PRINT_PREVIEW #ifdef NS_DEBUG @@ -536,6 +540,9 @@ void DocumentViewerImpl::PrepareToStartLoad() DocumentViewerImpl::DocumentViewerImpl() : mTextZoom(1.0), mPageZoom(1.0), mIsSticky(PR_TRUE), +#ifdef NS_PRINT_PREVIEW + mPrintPreviewZoom(1.0), +#endif mHintCharsetSource(kCharsetUninitialized) { PrepareToStartLoad(); @@ -2722,10 +2729,12 @@ SetExtResourceFullZoom(nsIDocument* aDocument, void* aClosure) NS_IMETHODIMP DocumentViewerImpl::SetTextZoom(float aTextZoom) { - if (!GetIsPrintPreview()) { - mTextZoom = aTextZoom; + if (GetIsPrintPreview()) { + return NS_OK; } + mTextZoom = aTextZoom; + nsIViewManager::UpdateViewBatch batch(GetViewManager()); // Set the text zoom on all children of mContainer (even if our zoom didn't @@ -2761,9 +2770,39 @@ DocumentViewerImpl::GetTextZoom(float* aTextZoom) NS_IMETHODIMP DocumentViewerImpl::SetFullZoom(float aFullZoom) { - if (!GetIsPrintPreview()) { - mPageZoom = aFullZoom; +#ifdef NS_PRINT_PREVIEW + if (GetIsPrintPreview()) { + nsPresContext* pc = GetPresContext(); + NS_ENSURE_TRUE(pc, NS_OK); + nsCOMPtr shell = pc->GetPresShell(); + NS_ENSURE_TRUE(shell, NS_OK); + + nsIViewManager::UpdateViewBatch batch(pc->GetViewManager()); + if (!mPrintPreviewZoomed) { + mOriginalPrintPreviewScale = pc->GetPrintPreviewScale(); + mPrintPreviewZoomed = PR_TRUE; + } + + mPrintPreviewZoom = aFullZoom; + pc->SetPrintPreviewScale(aFullZoom * mOriginalPrintPreviewScale); + nsIPageSequenceFrame* pf = nsnull; + shell->GetPageSequenceFrame(&pf); + if (pf) { + nsIFrame* f = do_QueryFrame(pf); + shell->FrameNeedsReflow(f, nsIPresShell::eResize, NS_FRAME_IS_DIRTY); + } + + nsIFrame* rootFrame = shell->GetRootFrame(); + if (rootFrame) { + nsRect rect(nsPoint(0, 0), rootFrame->GetSize()); + rootFrame->Invalidate(rect); + } + batch.EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC); + return NS_OK; } +#endif + + mPageZoom = aFullZoom; nsIViewManager::UpdateViewBatch batch(GetViewManager()); @@ -2787,6 +2826,12 @@ NS_IMETHODIMP DocumentViewerImpl::GetFullZoom(float* aFullZoom) { NS_ENSURE_ARG_POINTER(aFullZoom); +#ifdef NS_PRINT_PREVIEW + if (GetIsPrintPreview()) { + *aFullZoom = mPrintPreviewZoom; + return NS_OK; + } +#endif // Check the prescontext first because it might have a temporary // setting for print-preview nsPresContext* pc = GetPresContext(); @@ -3622,6 +3667,7 @@ DocumentViewerImpl::PrintPreview(nsIPrintSettings* aPrintSettings, } rv = mPrintEngine->PrintPreview(aPrintSettings, aChildDOMWin, aWebProgressListener); + mPrintPreviewZoomed = PR_FALSE; if (NS_FAILED(rv)) { OnDonePrinting(); } diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index deeb47b4b1f3..f368c7ec7572 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -80,6 +80,7 @@ #include "gfxTypes.h" #include "gfxUserFontSet.h" #include "nsTArray.h" +#include "nsTextFragment.h" #ifdef MOZ_SVG #include "nsSVGUtils.h" @@ -3175,6 +3176,45 @@ nsLayoutUtils::IsReallyFixedPos(nsIFrame* aFrame) parentType == nsGkAtoms::pageContentFrame; } +static void DeleteTextFragment(void* aObject, nsIAtom* aPropertyName, + void* aPropertyValue, void* aData) +{ + delete static_cast(aPropertyValue); +} + + +/* static */ nsresult +nsLayoutUtils::InitTextRunContainerForPrinting(nsIContent* aContent, + nsIFrame* aFrame, + nsFrameState aBits) +{ + NS_PRECONDITION(aFrame->GetType() == nsGkAtoms::textFrame || + aFrame->GetType() == nsGkAtoms::svgGlyphFrame, + "Wrong frame type!"); + + nsPresContext* presContext = aFrame->PresContext(); + if (presContext->IsDynamic()) { + return NS_OK; + } + + if (!presContext->PropertyTable()-> + GetProperty(aContent, nsGkAtoms::clonedTextForPrint)) { + nsTextFragment* frag = new nsTextFragment(); + NS_ENSURE_TRUE(frag, NS_ERROR_OUT_OF_MEMORY); + *frag = *aContent->GetText(); + nsresult rv = presContext->PropertyTable()-> + SetProperty(aContent, nsGkAtoms::clonedTextForPrint, frag, + DeleteTextFragment, nsnull); + if (NS_FAILED(rv)) { + delete frag; + return rv; + } + } + + aFrame->AddStateBits(aBits); + return NS_OK; +} + nsSetAttrRunnable::nsSetAttrRunnable(nsIContent* aContent, nsIAtom* aAttrName, const nsAString& aValue) : mContent(aContent), diff --git a/layout/base/nsLayoutUtils.h b/layout/base/nsLayoutUtils.h index 0a481c13ed80..c92c4e3bc742 100644 --- a/layout/base/nsLayoutUtils.h +++ b/layout/base/nsLayoutUtils.h @@ -958,6 +958,21 @@ public: * disabled. */ static PRBool sDisableGetUsedXAssertions; + + /** + * Initilizes text run container for printing. Does *nothing* if + * aFrame->PresContext() is dynamic. + * @param aContainerContent The nsIContent object from which aFrame gets data + * for text run creation. + * @param aFrame The nsIFrame object which is being initialized. + * @param aBits Frame type dependent bits which will be set to + * aFrame to mark that PresContext has a text fragment + * property called nsGkAtoms::clonedTextForPrint for + * aContent. + */ + static nsresult InitTextRunContainerForPrinting(nsIContent* aContainerContent, + nsIFrame* aFrame, + nsFrameState aBits); }; class nsAutoDisableGetUsedXAssertions diff --git a/layout/base/nsPresContext.cpp b/layout/base/nsPresContext.cpp index c6c2c54b9d2d..4bd983d6fa92 100644 --- a/layout/base/nsPresContext.cpp +++ b/layout/base/nsPresContext.cpp @@ -1205,7 +1205,7 @@ nsPresContext::GetDefaultFont(PRUint8 aFontID) const void nsPresContext::SetFullZoom(float aZoom) { - if (!mShell || mFullZoom == aZoom) { + if (!mShell || mFullZoom == aZoom || !IsDynamic()) { return; } // Re-fetch the view manager's window dimensions in case there's a deferred diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index 6b41062b9b43..1676df172541 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -766,6 +766,119 @@ struct nsCallbackEventRequest nsCallbackEventRequest* next; }; + +class nsDocumentObserverForNonDynamicPresContext : public nsStubDocumentObserver +{ +public: + nsDocumentObserverForNonDynamicPresContext(nsIDocumentObserver* aBaseObserver) + : mBaseObserver(aBaseObserver) + { + NS_ASSERTION(aBaseObserver, "Null document observer!"); + } + + NS_DECL_ISUPPORTS + + virtual void BeginUpdate(nsIDocument* aDocument, nsUpdateType aUpdateType) + { + mBaseObserver->BeginUpdate(aDocument, aUpdateType); + } + virtual void EndUpdate(nsIDocument* aDocument, nsUpdateType aUpdateType) + { + mBaseObserver->EndUpdate(aDocument, aUpdateType); + } + virtual void BeginLoad(nsIDocument* aDocument) + { + mBaseObserver->BeginLoad(aDocument); + } + virtual void EndLoad(nsIDocument* aDocument) + { + mBaseObserver->EndLoad(aDocument); + } + virtual void ContentStatesChanged(nsIDocument* aDocument, + nsIContent* aContent1, + nsIContent* aContent2, + PRInt32 aStateMask) + { + if ((!aContent1 || IsInRootScrollbar(aContent1)) && + (!aContent2 || IsInRootScrollbar(aContent2))) { + mBaseObserver->ContentStatesChanged(aDocument, aContent1, aContent2, + aStateMask); + } + } + + // nsIMutationObserver + virtual void CharacterDataChanged(nsIDocument* aDocument, + nsIContent* aContent, + CharacterDataChangeInfo* aInfo) + { + if (IsInRootScrollbar(aContent)) { + mBaseObserver->CharacterDataChanged(aDocument, aContent, aInfo); + } + } + virtual void AttributeChanged(nsIDocument* aDocument, + nsIContent* aContent, + PRInt32 aNameSpaceID, + nsIAtom* aAttribute, + PRInt32 aModType, + PRUint32 aStateMask) + { + if (IsInRootScrollbar(aContent)) { + mBaseObserver->AttributeChanged(aDocument, aContent, aNameSpaceID, + aAttribute, aModType, aStateMask); + } + } + virtual void ContentAppended(nsIDocument* aDocument, + nsIContent* aContainer, + PRInt32 aNewIndexInContainer) + { + if (IsInRootScrollbar(aContainer)) { + mBaseObserver->ContentAppended(aDocument, aContainer, + aNewIndexInContainer); + } + } + virtual void ContentInserted(nsIDocument* aDocument, + nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer) + { + if (IsInRootScrollbar(aContainer)) { + mBaseObserver->ContentInserted(aDocument, aContainer, aChild, + aIndexInContainer); + } + } + virtual void ContentRemoved(nsIDocument* aDocument, + nsIContent* aContainer, + nsIContent* aChild, + PRInt32 aIndexInContainer) + { + if (IsInRootScrollbar(aContainer)) { + mBaseObserver->ContentRemoved(aDocument, aContainer, aChild, + aIndexInContainer); + } + } + + PRBool IsInRootScrollbar(nsIContent* aContent) { + if(aContent && aContent->IsInDoc()) { + nsIContent* root = aContent->GetCurrentDoc()->GetRootContent(); + while (aContent && aContent->IsInNativeAnonymousSubtree()) { + nsIContent* parent = aContent->GetParent(); + if (parent == root && aContent->IsNodeOfType(nsINode::eXUL)) { + nsIAtom* tag = aContent->Tag(); + return tag == nsGkAtoms::scrollbar || tag == nsGkAtoms::scrollcorner; + } + aContent = parent; + } + } + return PR_FALSE; + } +protected: + nsCOMPtr mBaseObserver; +}; + +NS_IMPL_ISUPPORTS2(nsDocumentObserverForNonDynamicPresContext, + nsIDocumentObserver, + nsIMutationObserver) + // ---------------------------------------------------------------------------- class nsPresShellEventCB; @@ -1198,6 +1311,9 @@ protected: static PRBool sDisableNonTestMouseEvents; + + nsCOMPtr mDocumentObserverForNonDynamicContext; + private: PRBool InZombieDocument(nsIContent *aContent); @@ -2268,7 +2384,14 @@ NS_IMETHODIMP PresShell::BeginObservingDocument() { if (mDocument && !mIsDestroying) { - mDocument->AddObserver(this); + if (mPresContext->IsDynamic()) { + mDocument->AddObserver(this); + } else { + mDocumentObserverForNonDynamicContext = + new nsDocumentObserverForNonDynamicPresContext(this); + NS_ENSURE_TRUE(mDocumentObserverForNonDynamicContext, NS_ERROR_OUT_OF_MEMORY); + mDocument->AddObserver(mDocumentObserverForNonDynamicContext); + } if (mIsDocumentGone) { NS_WARNING("Adding a presshell that was disconnected from the document " "as a document observer? Sounds wrong..."); @@ -2286,7 +2409,10 @@ PresShell::EndObservingDocument() // is gone, perhaps? Except for printing it's NOT gone, sometimes. mIsDocumentGone = PR_TRUE; if (mDocument) { - mDocument->RemoveObserver(this); + mDocument->RemoveObserver(mDocumentObserverForNonDynamicContext ? + mDocumentObserverForNonDynamicContext.get() : + this); + mDocumentObserverForNonDynamicContext = nsnull; } return NS_OK; } @@ -3357,6 +3483,10 @@ PresShell::RecreateFramesFor(nsIContent* aContent) return NS_OK; } + if (!mPresContext->IsDynamic()) { + return NS_OK; + } + // Don't call RecreateFramesForContent since that is not exported and we want // to keep the number of entrypoints down. @@ -4770,6 +4900,9 @@ PresShell::ContentRemoved(nsIDocument *aDocument, nsresult PresShell::ReconstructFrames(void) { + if (!mPresContext || !mPresContext->IsDynamic()) { + return NS_OK; + } nsAutoScriptBlocker scriptBlocker; mFrameConstructor->BeginUpdate(); nsresult rv = mFrameConstructor->ReconstructDocElementHierarchy(); diff --git a/layout/generic/nsSimplePageSequence.cpp b/layout/generic/nsSimplePageSequence.cpp index e8d42d5d098f..19052481ae50 100644 --- a/layout/generic/nsSimplePageSequence.cpp +++ b/layout/generic/nsSimplePageSequence.cpp @@ -172,8 +172,8 @@ nsSimplePageSequenceFrame::Reflow(nsPresContext* aPresContext, // it right in paginated mode. if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) { // Return our desired size - aDesiredSize.height = mSize.height; - aDesiredSize.width = mSize.width; + aDesiredSize.height = mSize.height * PresContext()->GetPrintPreviewScale(); + aDesiredSize.width = mSize.width * PresContext()->GetPrintPreviewScale(); aDesiredSize.mOverflowArea = nsRect(0, 0, aDesiredSize.width, aDesiredSize.height); FinishAndStoreOverflow(&aDesiredSize); @@ -355,8 +355,9 @@ nsSimplePageSequenceFrame::Reflow(nsPresContext* aPresContext, // Return our desired size // Adjustr the reflow size by PrintPreviewScale so the scrollbars end up the // correct size + nscoord w = (x + availSize.width + deadSpaceGap); aDesiredSize.height = y * PresContext()->GetPrintPreviewScale(); // includes page heights and dead space - aDesiredSize.width = (x + availSize.width + deadSpaceGap) * PresContext()->GetPrintPreviewScale(); + aDesiredSize.width = w * PresContext()->GetPrintPreviewScale(); aDesiredSize.mOverflowArea = nsRect(0, 0, aDesiredSize.width, aDesiredSize.height); @@ -364,8 +365,8 @@ nsSimplePageSequenceFrame::Reflow(nsPresContext* aPresContext, // cache the size so we can set the desired size // for the other reflows that happen - mSize.width = aDesiredSize.width; - mSize.height = aDesiredSize.height; + mSize.width = w; + mSize.height = y; NS_FRAME_TRACE_REFLOW_OUT("nsSimplePageSequeceFrame::Reflow", aStatus); NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); diff --git a/layout/generic/nsTextFrame.h b/layout/generic/nsTextFrame.h index 18c551af91ab..e4dfacf54db6 100644 --- a/layout/generic/nsTextFrame.h +++ b/layout/generic/nsTextFrame.h @@ -59,6 +59,10 @@ class nsTextPaintStyle; class PropertyProvider; +// This bit is set while the frame is registered as a blinking frame or if +// frame is within a non-dynamic PresContext. +#define TEXT_BLINK_ON_OR_PRINTING 0x20000000 + // This state bit is set on frames that have some non-collapsed characters after // reflow #define TEXT_HAS_NONCOLLAPSED_CHARACTERS 0x80000000 @@ -353,9 +357,17 @@ public: TrimmedOffsets GetTrimmedOffsets(const nsTextFragment* aFrag, PRBool aTrimAfter); + const nsTextFragment* GetFragment() const + { + return !(GetStateBits() & TEXT_BLINK_ON_OR_PRINTING) ? + mContent->GetText() : GetFragmentInternal(); + } + protected: virtual ~nsTextFrame(); - + + const nsTextFragment* GetFragmentInternal() const; + nsIFrame* mNextContinuation; // The key invariant here is that mContentOffset never decreases along // a next-continuation chain. And of course mContentOffset is always <= the diff --git a/layout/generic/nsTextFrameThebes.cpp b/layout/generic/nsTextFrameThebes.cpp index 9df2d37f643c..9ba9168420af 100644 --- a/layout/generic/nsTextFrameThebes.cpp +++ b/layout/generic/nsTextFrameThebes.cpp @@ -163,8 +163,9 @@ #define TEXT_ISNOT_ONLY_WHITESPACE 0x10000000 #define TEXT_WHITESPACE_FLAGS 0x18000000 -// This bit is set while the frame is registered as a blinking frame. -#define TEXT_BLINK_ON 0x20000000 + +// nsTextFrame.h has +// #define TEXT_BLINK_ON_OR_PRINTING 0x20000000 // Set when this text frame is mentioned in the userdata for a textrun #define TEXT_IN_TEXTRUN_USER_DATA 0x40000000 @@ -453,7 +454,7 @@ nsTextFrameTextRunCache::Shutdown() { PRInt32 nsTextFrame::GetContentEnd() const { nsTextFrame* next = static_cast(GetNextContinuation()); - return next ? next->GetContentOffset() : mContent->GetText()->GetLength(); + return next ? next->GetContentOffset() : GetFragment()->GetLength(); } PRInt32 nsTextFrame::GetInFlowContentLength() { @@ -698,7 +699,7 @@ public: PRInt32 GetContentEnd() { return mEndFrame ? mEndFrame->GetContentOffset() - : mStartFrame->GetContent()->GetText()->GetLength(); + : mStartFrame->GetFragment()->GetLength(); } }; @@ -904,7 +905,7 @@ BuildTextRunsScanner::FindBoundaries(nsIFrame* aFrame, FindBoundaryState* aState if (textFrame) { if (!aState->mSeenSpaceForLineBreakingOnThisLine) { - const nsTextFragment* frag = textFrame->GetContent()->GetText(); + const nsTextFragment* frag = textFrame->GetFragment(); PRUint32 start = textFrame->GetContentOffset(); const void* text = frag->Is2b() ? static_cast(frag->Get2b() + start) @@ -1229,7 +1230,7 @@ void BuildTextRunsScanner::AccumulateRunInfo(nsTextFrame* aFrame) { NS_ASSERTION(mMaxTextLength <= mMaxTextLength + aFrame->GetContentLength(), "integer overflow"); mMaxTextLength += aFrame->GetContentLength(); - mDoubleByteText |= aFrame->GetContent()->GetText()->Is2b(); + mDoubleByteText |= aFrame->GetFragment()->Is2b(); mLastFrame = aFrame; mCommonAncestorWithLastFrame = aFrame->GetParent(); @@ -1262,7 +1263,7 @@ HasTerminalNewline(const nsTextFrame* aFrame) { if (aFrame->GetContentLength() == 0) return PR_FALSE; - const nsTextFragment* frag = aFrame->GetContent()->GetText(); + const nsTextFragment* frag = aFrame->GetFragment(); return frag->CharAt(aFrame->GetContentEnd() - 1) == '\n'; } @@ -1589,7 +1590,7 @@ BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer) // Figure out what content is included in this flow. nsIContent* content = f->GetContent(); - const nsTextFragment* frag = content->GetText(); + const nsTextFragment* frag = f->GetFragment(); PRInt32 contentStart = mappedFlow->mStartFrame->GetContentOffset(); PRInt32 contentEnd = mappedFlow->GetContentEnd(); PRInt32 contentLength = contentEnd - contentStart; @@ -1835,7 +1836,7 @@ HasCompressedLeadingWhitespace(nsTextFrame* aFrame, const nsStyleText* aStyleTex gfxSkipCharsIterator iter = aIterator; PRInt32 frameContentOffset = aFrame->GetContentOffset(); - const nsTextFragment* frag = aFrame->GetContent()->GetText(); + const nsTextFragment* frag = aFrame->GetFragment(); while (frameContentOffset < aContentEndOffset && iter.IsOriginalCharSkipped()) { if (IsTrimmableSpace(frag, frameContentOffset, aStyleText)) return PR_TRUE; @@ -2207,7 +2208,7 @@ public: PropertyProvider(nsTextFrame* aFrame, const gfxSkipCharsIterator& aStart) : mTextRun(aFrame->GetTextRun()), mFontGroup(nsnull), mTextStyle(aFrame->GetStyleText()), - mFrag(aFrame->GetContent()->GetText()), + mFrag(aFrame->GetFragment()), mLineContainer(nsnull), mFrame(aFrame), mStart(aStart), mTempIterator(aStart), mTabWidths(nsnull), @@ -3331,6 +3332,12 @@ nsTextFrame::Init(nsIContent* aContent, NS_ASSERTION(!aPrevInFlow, "Can't be a continuation!"); NS_PRECONDITION(aContent->IsNodeOfType(nsINode::eTEXT), "Bogus content!"); + + nsresult rv = nsLayoutUtils::InitTextRunContainerForPrinting(aContent, + this, + TEXT_BLINK_ON_OR_PRINTING); + NS_ENSURE_SUCCESS(rv, rv); + // We're not a continuing frame. // mContentOffset = 0; not necessary since we get zeroed out at init return nsFrame::Init(aContent, aParent, aPrevInFlow); @@ -3408,8 +3415,14 @@ nsContinuingTextFrame::Init(nsIContent* aContent, nsIFrame* aPrevInFlow) { NS_ASSERTION(aPrevInFlow, "Must be a continuation!"); + + nsresult rv = nsLayoutUtils::InitTextRunContainerForPrinting(aContent, + this, + TEXT_BLINK_ON_OR_PRINTING); + NS_ENSURE_SUCCESS(rv, rv); + // NOTE: bypassing nsTextFrame::Init!!! - nsresult rv = nsFrame::Init(aContent, aParent, aPrevInFlow); + rv = nsFrame::Init(aContent, aParent, aPrevInFlow); #ifdef IBMBIDI nsTextFrame* nextContinuation = @@ -3420,7 +3433,7 @@ nsContinuingTextFrame::Init(nsIContent* aContent, aPrevInFlow->SetNextInFlow(this); nsTextFrame* prev = static_cast(aPrevInFlow); mContentOffset = prev->GetContentOffset() + prev->GetContentLengthHint(); - NS_ASSERTION(mContentOffset < PRInt32(aContent->GetText()->GetLength()), + NS_ASSERTION(mContentOffset < PRInt32(GetFragment()->GetLength()), "Creating ContinuingTextFrame, but there is no more content"); if (prev->GetStyleContext() != GetStyleContext()) { // We're taking part of prev's text, and its style may be different @@ -3600,7 +3613,7 @@ NS_NewContinuingTextFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) nsTextFrame::~nsTextFrame() { - if (0 != (mState & TEXT_BLINK_ON)) + if (0 != (mState & TEXT_BLINK_ON_OR_PRINTING) && PresContext()->IsDynamic()) { nsBlinkTimer::RemoveBlinkFrame(this); } @@ -3784,7 +3797,7 @@ nsTextFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, DO_GLOBAL_REFLOW_COUNT_DSP("nsTextFrame"); - if ((0 != (mState & TEXT_BLINK_ON)) && nsBlinkTimer::GetBlinkIsOff() && + if ((0 != (mState & TEXT_BLINK_ON_OR_PRINTING)) && nsBlinkTimer::GetBlinkIsOff() && PresContext()->IsDynamic()) return NS_OK; @@ -4961,7 +4974,7 @@ nsTextFrame::PeekOffsetNoAmount(PRBool aForward, PRInt32* aOffset) if (!mTextRun) return PR_FALSE; - TrimmedOffsets trimmed = GetTrimmedOffsets(mContent->GetText(), PR_TRUE); + TrimmedOffsets trimmed = GetTrimmedOffsets(GetFragment(), PR_TRUE); // Check whether there are nonskipped characters in the trimmmed range return iter.ConvertOriginalToSkipped(trimmed.GetEnd()) > iter.ConvertOriginalToSkipped(trimmed.mStart); @@ -5028,7 +5041,7 @@ nsTextFrame::PeekOffsetCharacter(PRBool aForward, PRInt32* aOffset) if (!mTextRun) return PR_FALSE; - TrimmedOffsets trimmed = GetTrimmedOffsets(mContent->GetText(), PR_FALSE); + TrimmedOffsets trimmed = GetTrimmedOffsets(GetFragment(), PR_FALSE); // A negative offset means "end of frame". PRInt32 startOffset = GetContentOffset() + (*aOffset < 0 ? contentLength : *aOffset); @@ -5143,7 +5156,7 @@ ClusterIterator::ClusterIterator(nsTextFrame* aTextFrame, PRInt32 aPosition, mCategories = do_GetService(NS_UNICHARCATEGORY_CONTRACTID); - mFrag = aTextFrame->GetContent()->GetText(); + mFrag = aTextFrame->GetFragment(); mTrimmed = aTextFrame->GetTrimmedOffsets(mFrag, PR_TRUE); PRInt32 textOffset = aTextFrame->GetContentOffset(); @@ -5384,7 +5397,7 @@ nsTextFrame::AddInlineMinWidthForFlow(nsIRenderingContext *aRenderingContext, // Pass null for the line container. This will disable tab spacing, but that's // OK since we can't really handle tabs for intrinsic sizing anyway. const nsStyleText* textStyle = GetStyleText(); - const nsTextFragment* frag = mContent->GetText(); + const nsTextFragment* frag = GetFragment(); PropertyProvider provider(mTextRun, textStyle, frag, this, iter, PR_INT32_MAX, nsnull, 0); @@ -5512,7 +5525,7 @@ nsTextFrame::AddInlinePrefWidthForFlow(nsIRenderingContext *aRenderingContext, // OK since we can't really handle tabs for intrinsic sizing anyway. const nsStyleText* textStyle = GetStyleText(); - const nsTextFragment* frag = mContent->GetText(); + const nsTextFragment* frag = GetFragment(); PropertyProvider provider(mTextRun, textStyle, frag, this, iter, PR_INT32_MAX, nsnull, 0); @@ -5750,8 +5763,8 @@ nsTextFrame::Reflow(nsPresContext* aPresContext, ///////////////////////////////////////////////////////////////////// // Clear out the reflow state flags in mState (without destroying - // the TEXT_BLINK_ON bit). We also clear the whitespace flags because this - // can change whether the frame maps whitespace-only text or not. + // the TEXT_BLINK_ON_OR_PRINTING bit). We also clear the whitespace flags + // because this can change whether the frame maps whitespace-only text or not. RemoveStateBits(TEXT_REFLOW_FLAGS | TEXT_WHITESPACE_FLAGS); // Temporarily map all possible content while we construct our new textrun. @@ -5773,14 +5786,14 @@ nsTextFrame::Reflow(nsPresContext* aPresContext, nsLineLayout& lineLayout = *aReflowState.mLineLayout; if (aReflowState.mFlags.mBlinks) { - if (0 == (mState & TEXT_BLINK_ON)) { - mState |= TEXT_BLINK_ON; + if (0 == (mState & TEXT_BLINK_ON_OR_PRINTING) && PresContext()->IsDynamic()) { + mState |= TEXT_BLINK_ON_OR_PRINTING; nsBlinkTimer::AddBlinkFrame(aPresContext, this); } } else { - if (0 != (mState & TEXT_BLINK_ON)) { - mState &= ~TEXT_BLINK_ON; + if (0 != (mState & TEXT_BLINK_ON_OR_PRINTING) && PresContext()->IsDynamic()) { + mState &= ~TEXT_BLINK_ON_OR_PRINTING; nsBlinkTimer::RemoveBlinkFrame(this); } } @@ -5795,7 +5808,7 @@ nsTextFrame::Reflow(nsPresContext* aPresContext, PRUint32 flowEndInTextRun; nsIFrame* lineContainer = lineLayout.GetLineContainerFrame(); gfxContext* ctx = aReflowState.rendContext->ThebesContext(); - const nsTextFragment* frag = mContent->GetText(); + const nsTextFragment* frag = GetFragment(); // DOM offsets of the text range we need to measure, after trimming // whitespace, restricting to first-letter, and restricting preformatted text @@ -6205,7 +6218,7 @@ nsTextFrame::TrimTrailingWhiteSpace(nsIRenderingContext* aRC) PRUint32 trimmedStart = start.GetSkippedOffset(); - const nsTextFragment* frag = mContent->GetText(); + const nsTextFragment* frag = GetFragment(); TrimmedOffsets trimmed = GetTrimmedOffsets(frag, PR_TRUE); gfxSkipCharsIterator trimmedEndIter = start; const nsStyleText* textStyle = GetStyleText(); @@ -6342,7 +6355,7 @@ nsresult nsTextFrame::GetRenderedText(nsAString* aAppendToString, // The handling of aSkippedStartOffset and aSkippedMaxLength could be more efficient... gfxSkipCharsBuilder skipCharsBuilder; nsTextFrame* textFrame; - const nsTextFragment* textFrag = mContent->GetText(); + const nsTextFragment* textFrag = GetFragment(); PRUint32 keptCharsLength = 0; PRUint32 validCharsLength = 0; @@ -6408,7 +6421,7 @@ void nsTextFrame::ToCString(nsCString& aBuf, PRInt32* aTotalContentLength) const { // Get the frames text content - const nsTextFragment* frag = mContent->GetText(); + const nsTextFragment* frag = GetFragment(); if (!frag) { return; } @@ -6468,7 +6481,7 @@ nsTextFrame::IsEmpty() return PR_TRUE; } - PRBool isEmpty = IsAllWhitespace(mContent->GetText(), + PRBool isEmpty = IsAllWhitespace(GetFragment(), textStyle->mWhiteSpace != NS_STYLE_WHITESPACE_PRE_LINE); mState |= (isEmpty ? TEXT_IS_ONLY_WHITESPACE : TEXT_ISNOT_ONLY_WHITESPACE); return isEmpty; @@ -6605,3 +6618,11 @@ nsTextFrame::IsAtEndOfLine() const { return (GetStateBits() & TEXT_END_OF_LINE) != 0; } + +const nsTextFragment* +nsTextFrame::GetFragmentInternal() const +{ + return PresContext()->IsDynamic() ? mContent->GetText() : + static_cast(PresContext()->PropertyTable()-> + GetProperty(mContent, nsGkAtoms::clonedTextForPrint)); +} diff --git a/layout/svg/base/src/nsSVGGlyphFrame.cpp b/layout/svg/base/src/nsSVGGlyphFrame.cpp index 1e01929e121b..00fb56e8bdcc 100644 --- a/layout/svg/base/src/nsSVGGlyphFrame.cpp +++ b/layout/svg/base/src/nsSVGGlyphFrame.cpp @@ -54,6 +54,7 @@ #include "gfxMatrix.h" #include "gfxPlatform.h" #include "gfxTextRunWordCache.h" +#include "nsTextFrame.h" struct CharacterPosition { gfxPoint pos; @@ -298,6 +299,11 @@ nsSVGGlyphFrame::Init(nsIContent* aContent, NS_ASSERTION(aContent->IsNodeOfType(nsINode::eTEXT), "trying to construct an SVGGlyphFrame for wrong content element"); + nsresult rv = nsLayoutUtils::InitTextRunContainerForPrinting(aContent, + this, + NS_STATE_SVG_PRINTING); + NS_ENSURE_SUCCESS(rv, rv); + return nsSVGGlyphFrameBase::Init(aContent, aParent, aPrevInFlow); } #endif /* DEBUG */ @@ -610,7 +616,7 @@ PRBool nsSVGGlyphFrame::GetCharacterData(nsAString & aCharacterData) { nsAutoString characterData; - mContent->AppendTextTo(characterData); + GetFragment()->AppendTo(characterData); if (mWhitespaceHandling & COMPRESS_WHITESPACE) { PRBool trimLeadingWhitespace, trimTrailingWhitespace; @@ -762,7 +768,7 @@ nsSVGGlyphFrame::GetHighlight(PRUint32 *charnum, PRUint32 *nchars, // The selection ranges are relative to the uncompressed text in // the content element. We'll need the text fragment: - const nsTextFragment *fragment = mContent->GetText(); + const nsTextFragment* fragment = GetFragment(); NS_ASSERTION(fragment, "no text"); // get the selection details @@ -1080,7 +1086,7 @@ NS_IMETHODIMP_(PRUint32) nsSVGGlyphFrame::GetNumberOfChars() { if (mWhitespaceHandling == PRESERVE_WHITESPACE) - return mContent->TextLength(); + return GetFragment()->GetLength(); nsAutoString text; GetCharacterData(text); diff --git a/layout/svg/base/src/nsSVGGlyphFrame.h b/layout/svg/base/src/nsSVGGlyphFrame.h index fca02c0840fd..3f474672aa94 100644 --- a/layout/svg/base/src/nsSVGGlyphFrame.h +++ b/layout/svg/base/src/nsSVGGlyphFrame.h @@ -215,6 +215,13 @@ protected: void SetupGlobalTransform(gfxContext *aContext); nsresult GetHighlight(PRUint32 *charnum, PRUint32 *nchars, nscolor *foreground, nscolor *background); + const nsTextFragment* GetFragment() const + { + return !(GetStateBits() & NS_STATE_SVG_PRINTING) ? + mContent->GetText() : + static_cast(PresContext()->PropertyTable()-> + GetProperty(mContent, nsGkAtoms::clonedTextForPrint)); + } // Owning pointer, must call gfxTextRunWordCache::RemoveTextRun before deleting gfxTextRun *mTextRun; diff --git a/layout/svg/base/src/nsSVGUtils.h b/layout/svg/base/src/nsSVGUtils.h index f3b4356f68b1..a05034516ec7 100644 --- a/layout/svg/base/src/nsSVGUtils.h +++ b/layout/svg/base/src/nsSVGUtils.h @@ -93,6 +93,9 @@ class nsISVGChildFrame; #define NS_STATE_SVG_PROPAGATE_TRANSFORM 0x00800000 +// nsSVGGlyphFrame uses this when the frame is within a non-dynamic PresContext. +#define NS_STATE_SVG_PRINTING 0x01000000 + /** * Byte offsets of channels in a native packed gfxColor or cairo image surface. */