1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either of the GNU General Public License Version 2 or later (the "GPL"),
26 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : /*
39 : * base class for rendering objects that can be split across lines,
40 : * columns, or pages
41 : */
42 :
43 : #include "nsSplittableFrame.h"
44 : #include "nsIContent.h"
45 : #include "nsPresContext.h"
46 : #include "nsStyleContext.h"
47 :
48 0 : NS_IMPL_FRAMEARENA_HELPERS(nsSplittableFrame)
49 :
50 : NS_IMETHODIMP
51 0 : nsSplittableFrame::Init(nsIContent* aContent,
52 : nsIFrame* aParent,
53 : nsIFrame* aPrevInFlow)
54 : {
55 0 : nsresult rv = nsFrame::Init(aContent, aParent, aPrevInFlow);
56 :
57 0 : if (aPrevInFlow) {
58 : // Hook the frame into the flow
59 0 : SetPrevInFlow(aPrevInFlow);
60 0 : aPrevInFlow->SetNextInFlow(this);
61 : }
62 :
63 0 : return rv;
64 : }
65 :
66 : void
67 0 : nsSplittableFrame::DestroyFrom(nsIFrame* aDestructRoot)
68 : {
69 : // Disconnect from the flow list
70 0 : if (mPrevContinuation || mNextContinuation) {
71 0 : RemoveFromFlow(this);
72 : }
73 :
74 : // Let the base class destroy the frame
75 0 : nsFrame::DestroyFrom(aDestructRoot);
76 0 : }
77 :
78 : nsSplittableType
79 0 : nsSplittableFrame::GetSplittableType() const
80 : {
81 0 : return NS_FRAME_SPLITTABLE;
82 : }
83 :
84 0 : nsIFrame* nsSplittableFrame::GetPrevContinuation() const
85 : {
86 0 : return mPrevContinuation;
87 : }
88 :
89 0 : NS_METHOD nsSplittableFrame::SetPrevContinuation(nsIFrame* aFrame)
90 : {
91 0 : NS_ASSERTION (!aFrame || GetType() == aFrame->GetType(), "setting a prev continuation with incorrect type!");
92 0 : NS_ASSERTION (!IsInPrevContinuationChain(aFrame, this), "creating a loop in continuation chain!");
93 0 : mPrevContinuation = aFrame;
94 0 : RemoveStateBits(NS_FRAME_IS_FLUID_CONTINUATION);
95 0 : return NS_OK;
96 : }
97 :
98 0 : nsIFrame* nsSplittableFrame::GetNextContinuation() const
99 : {
100 0 : return mNextContinuation;
101 : }
102 :
103 0 : NS_METHOD nsSplittableFrame::SetNextContinuation(nsIFrame* aFrame)
104 : {
105 0 : NS_ASSERTION (!aFrame || GetType() == aFrame->GetType(), "setting a next continuation with incorrect type!");
106 0 : NS_ASSERTION (!IsInNextContinuationChain(aFrame, this), "creating a loop in continuation chain!");
107 0 : mNextContinuation = aFrame;
108 0 : if (aFrame)
109 0 : aFrame->RemoveStateBits(NS_FRAME_IS_FLUID_CONTINUATION);
110 0 : return NS_OK;
111 : }
112 :
113 0 : nsIFrame* nsSplittableFrame::GetFirstContinuation() const
114 : {
115 0 : nsSplittableFrame* firstContinuation = const_cast<nsSplittableFrame*>(this);
116 0 : while (firstContinuation->mPrevContinuation) {
117 0 : firstContinuation = static_cast<nsSplittableFrame*>(firstContinuation->mPrevContinuation);
118 : }
119 0 : NS_POSTCONDITION(firstContinuation, "illegal state in continuation chain.");
120 0 : return firstContinuation;
121 : }
122 :
123 0 : nsIFrame* nsSplittableFrame::GetLastContinuation() const
124 : {
125 0 : nsSplittableFrame* lastContinuation = const_cast<nsSplittableFrame*>(this);
126 0 : while (lastContinuation->mNextContinuation) {
127 0 : lastContinuation = static_cast<nsSplittableFrame*>(lastContinuation->mNextContinuation);
128 : }
129 0 : NS_POSTCONDITION(lastContinuation, "illegal state in continuation chain.");
130 0 : return lastContinuation;
131 : }
132 :
133 : #ifdef DEBUG
134 0 : bool nsSplittableFrame::IsInPrevContinuationChain(nsIFrame* aFrame1, nsIFrame* aFrame2)
135 : {
136 0 : PRInt32 iterations = 0;
137 0 : while (aFrame1 && iterations < 10) {
138 : // Bail out after 10 iterations so we don't bog down debug builds too much
139 0 : if (aFrame1 == aFrame2)
140 0 : return true;
141 0 : aFrame1 = aFrame1->GetPrevContinuation();
142 0 : ++iterations;
143 : }
144 0 : return false;
145 : }
146 :
147 0 : bool nsSplittableFrame::IsInNextContinuationChain(nsIFrame* aFrame1, nsIFrame* aFrame2)
148 : {
149 0 : PRInt32 iterations = 0;
150 0 : while (aFrame1 && iterations < 10) {
151 : // Bail out after 10 iterations so we don't bog down debug builds too much
152 0 : if (aFrame1 == aFrame2)
153 0 : return true;
154 0 : aFrame1 = aFrame1->GetNextContinuation();
155 0 : ++iterations;
156 : }
157 0 : return false;
158 : }
159 : #endif
160 :
161 0 : nsIFrame* nsSplittableFrame::GetPrevInFlow() const
162 : {
163 0 : return (GetStateBits() & NS_FRAME_IS_FLUID_CONTINUATION) ? mPrevContinuation : nsnull;
164 : }
165 :
166 0 : NS_METHOD nsSplittableFrame::SetPrevInFlow(nsIFrame* aFrame)
167 : {
168 0 : NS_ASSERTION (!aFrame || GetType() == aFrame->GetType(), "setting a prev in flow with incorrect type!");
169 0 : NS_ASSERTION (!IsInPrevContinuationChain(aFrame, this), "creating a loop in continuation chain!");
170 0 : mPrevContinuation = aFrame;
171 0 : AddStateBits(NS_FRAME_IS_FLUID_CONTINUATION);
172 0 : return NS_OK;
173 : }
174 :
175 0 : nsIFrame* nsSplittableFrame::GetNextInFlow() const
176 : {
177 0 : return mNextContinuation && (mNextContinuation->GetStateBits() & NS_FRAME_IS_FLUID_CONTINUATION) ?
178 0 : mNextContinuation : nsnull;
179 : }
180 :
181 0 : NS_METHOD nsSplittableFrame::SetNextInFlow(nsIFrame* aFrame)
182 : {
183 0 : NS_ASSERTION (!aFrame || GetType() == aFrame->GetType(), "setting a next in flow with incorrect type!");
184 0 : NS_ASSERTION (!IsInNextContinuationChain(aFrame, this), "creating a loop in continuation chain!");
185 0 : mNextContinuation = aFrame;
186 0 : if (aFrame)
187 0 : aFrame->AddStateBits(NS_FRAME_IS_FLUID_CONTINUATION);
188 0 : return NS_OK;
189 : }
190 :
191 0 : nsIFrame* nsSplittableFrame::GetFirstInFlow() const
192 : {
193 0 : nsSplittableFrame* firstInFlow = const_cast<nsSplittableFrame*>(this);
194 0 : while (nsIFrame *prev = firstInFlow->GetPrevInFlow()) {
195 0 : firstInFlow = static_cast<nsSplittableFrame*>(prev);
196 : }
197 0 : NS_POSTCONDITION(firstInFlow, "illegal state in flow chain.");
198 0 : return firstInFlow;
199 : }
200 :
201 0 : nsIFrame* nsSplittableFrame::GetLastInFlow() const
202 : {
203 0 : nsSplittableFrame* lastInFlow = const_cast<nsSplittableFrame*>(this);
204 0 : while (nsIFrame* next = lastInFlow->GetNextInFlow()) {
205 0 : lastInFlow = static_cast<nsSplittableFrame*>(next);
206 : }
207 0 : NS_POSTCONDITION(lastInFlow, "illegal state in flow chain.");
208 0 : return lastInFlow;
209 : }
210 :
211 : // Remove this frame from the flow. Connects prev in flow and next in flow
212 : void
213 0 : nsSplittableFrame::RemoveFromFlow(nsIFrame* aFrame)
214 : {
215 0 : nsIFrame* prevContinuation = aFrame->GetPrevContinuation();
216 0 : nsIFrame* nextContinuation = aFrame->GetNextContinuation();
217 :
218 : // The new continuation is fluid only if the continuation on both sides
219 : // of the removed frame was fluid
220 0 : if (aFrame->GetPrevInFlow() && aFrame->GetNextInFlow()) {
221 0 : if (prevContinuation) {
222 0 : prevContinuation->SetNextInFlow(nextContinuation);
223 : }
224 0 : if (nextContinuation) {
225 0 : nextContinuation->SetPrevInFlow(prevContinuation);
226 : }
227 : } else {
228 0 : if (prevContinuation) {
229 0 : prevContinuation->SetNextContinuation(nextContinuation);
230 : }
231 0 : if (nextContinuation) {
232 0 : nextContinuation->SetPrevContinuation(prevContinuation);
233 : }
234 : }
235 :
236 0 : aFrame->SetPrevInFlow(nsnull);
237 0 : aFrame->SetNextInFlow(nsnull);
238 0 : }
239 :
240 : #ifdef DEBUG
241 : void
242 0 : nsSplittableFrame::DumpBaseRegressionData(nsPresContext* aPresContext, FILE* out, PRInt32 aIndent)
243 : {
244 0 : nsFrame::DumpBaseRegressionData(aPresContext, out, aIndent);
245 0 : if (nsnull != mNextContinuation) {
246 0 : IndentBy(out, aIndent);
247 0 : fprintf(out, "<next-continuation va=\"%ld\"/>\n", PRUptrdiff(mNextContinuation));
248 : }
249 0 : if (nsnull != mPrevContinuation) {
250 0 : IndentBy(out, aIndent);
251 0 : fprintf(out, "<prev-continuation va=\"%ld\"/>\n", PRUptrdiff(mPrevContinuation));
252 : }
253 :
254 0 : }
255 : #endif
|