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 MathML Project.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * The University Of Queensland.
19 : * Portions created by the Initial Developer are Copyright (C) 1999
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Roger B. Sidje <rbs@maths.uq.edu.au>
24 : * David J. Fiddes <D.J.Fiddes@hw.ac.uk>
25 : * Pierre Phaneuf <pp@ludusdesign.com>
26 : * Karl Tomlinson <karlt+@karlt.net>, Mozilla Corporation
27 : * Frederic Wang <fred.wang@free.fr>
28 : *
29 : * Alternatively, the contents of this file may be used under the terms of
30 : * either of the GNU General Public License Version 2 or later (the "GPL"),
31 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
32 : * in which case the provisions of the GPL or the LGPL are applicable instead
33 : * of those above. If you wish to allow use of your version of this file only
34 : * under the terms of either the GPL or the LGPL, and not to allow others to
35 : * use your version of this file under the terms of the MPL, indicate your
36 : * decision by deleting the provisions above and replace them with the notice
37 : * and other provisions required by the GPL or the LGPL. If you do not delete
38 : * the provisions above, a recipient may use your version of this file under
39 : * the terms of any one of the MPL, the GPL or the LGPL.
40 : *
41 : * ***** END LICENSE BLOCK ***** */
42 :
43 : #include "nsCOMPtr.h"
44 : #include "nsHTMLParts.h"
45 : #include "nsFrame.h"
46 : #include "nsPresContext.h"
47 : #include "nsIPresShell.h"
48 : #include "nsCSSAnonBoxes.h"
49 : #include "nsStyleContext.h"
50 : #include "nsStyleConsts.h"
51 : #include "nsINameSpaceManager.h"
52 : #include "nsRenderingContext.h"
53 :
54 : #include "nsIDOMMutationEvent.h"
55 : #include "nsFrameManager.h"
56 : #include "nsStyleChangeList.h"
57 :
58 : #include "nsGkAtoms.h"
59 : #include "nsMathMLParts.h"
60 : #include "nsMathMLContainerFrame.h"
61 : #include "nsAutoPtr.h"
62 : #include "nsStyleSet.h"
63 : #include "nsDisplayList.h"
64 : #include "nsCSSFrameConstructor.h"
65 : #include "nsIReflowCallback.h"
66 :
67 : using namespace mozilla;
68 :
69 : //
70 : // nsMathMLContainerFrame implementation
71 : //
72 :
73 0 : NS_IMPL_FRAMEARENA_HELPERS(nsMathMLContainerFrame)
74 :
75 0 : NS_QUERYFRAME_HEAD(nsMathMLContainerFrame)
76 0 : NS_QUERYFRAME_ENTRY(nsMathMLFrame)
77 0 : NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
78 :
79 : // =============================================================================
80 :
81 : // error handlers
82 : // provide a feedback to the user when a frame with bad markup can not be rendered
83 : nsresult
84 0 : nsMathMLContainerFrame::ReflowError(nsRenderingContext& aRenderingContext,
85 : nsHTMLReflowMetrics& aDesiredSize)
86 : {
87 : // clear all other flags and record that there is an error with this frame
88 0 : mEmbellishData.flags = 0;
89 0 : mPresentationData.flags = NS_MATHML_ERROR;
90 :
91 : ///////////////
92 : // Set font
93 0 : nsRefPtr<nsFontMetrics> fm;
94 0 : nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm));
95 0 : aRenderingContext.SetFont(fm);
96 :
97 : // bounding metrics
98 0 : nsAutoString errorMsg; errorMsg.AssignLiteral("invalid-markup");
99 : mBoundingMetrics =
100 0 : aRenderingContext.GetBoundingMetrics(errorMsg.get(), errorMsg.Length());
101 :
102 : // reflow metrics
103 0 : aDesiredSize.ascent = fm->MaxAscent();
104 0 : nscoord descent = fm->MaxDescent();
105 0 : aDesiredSize.height = aDesiredSize.ascent + descent;
106 0 : aDesiredSize.width = mBoundingMetrics.width;
107 :
108 : // Also return our bounding metrics
109 0 : aDesiredSize.mBoundingMetrics = mBoundingMetrics;
110 :
111 0 : return NS_OK;
112 : }
113 :
114 : class nsDisplayMathMLError : public nsDisplayItem {
115 : public:
116 0 : nsDisplayMathMLError(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
117 0 : : nsDisplayItem(aBuilder, aFrame) {
118 0 : MOZ_COUNT_CTOR(nsDisplayMathMLError);
119 0 : }
120 : #ifdef NS_BUILD_REFCNT_LOGGING
121 0 : virtual ~nsDisplayMathMLError() {
122 0 : MOZ_COUNT_DTOR(nsDisplayMathMLError);
123 0 : }
124 : #endif
125 :
126 : virtual void Paint(nsDisplayListBuilder* aBuilder,
127 : nsRenderingContext* aCtx);
128 0 : NS_DISPLAY_DECL_NAME("MathMLError", TYPE_MATHML_ERROR)
129 : };
130 :
131 0 : void nsDisplayMathMLError::Paint(nsDisplayListBuilder* aBuilder,
132 : nsRenderingContext* aCtx)
133 : {
134 : // Set color and font ...
135 0 : nsRefPtr<nsFontMetrics> fm;
136 0 : nsLayoutUtils::GetFontMetricsForFrame(mFrame, getter_AddRefs(fm));
137 0 : aCtx->SetFont(fm);
138 :
139 0 : nsPoint pt = ToReferenceFrame();
140 0 : aCtx->SetColor(NS_RGB(255,0,0));
141 0 : aCtx->FillRect(nsRect(pt, mFrame->GetSize()));
142 0 : aCtx->SetColor(NS_RGB(255,255,255));
143 :
144 0 : nscoord ascent = aCtx->FontMetrics()->MaxAscent();
145 :
146 0 : NS_NAMED_LITERAL_STRING(errorMsg, "invalid-markup");
147 : aCtx->DrawString(errorMsg.get(), PRUint32(errorMsg.Length()),
148 0 : pt.x, pt.y+ascent);
149 0 : }
150 :
151 : /* /////////////
152 : * nsIMathMLFrame - support methods for stretchy elements
153 : * =============================================================================
154 : */
155 :
156 : static bool
157 0 : IsForeignChild(const nsIFrame* aFrame)
158 : {
159 : // This counts nsMathMLmathBlockFrame as a foreign child, because it
160 : // uses block reflow
161 0 : return !(aFrame->IsFrameOfType(nsIFrame::eMathML)) ||
162 0 : aFrame->GetType() == nsGkAtoms::blockFrame;
163 : }
164 :
165 : static void
166 0 : DestroyHTMLReflowMetrics(void *aPropertyValue)
167 : {
168 0 : delete static_cast<nsHTMLReflowMetrics*>(aPropertyValue);
169 0 : }
170 :
171 0 : NS_DECLARE_FRAME_PROPERTY(HTMLReflowMetricsProperty, DestroyHTMLReflowMetrics)
172 :
173 : /* static */ void
174 0 : nsMathMLContainerFrame::SaveReflowAndBoundingMetricsFor(nsIFrame* aFrame,
175 : const nsHTMLReflowMetrics& aReflowMetrics,
176 : const nsBoundingMetrics& aBoundingMetrics)
177 : {
178 0 : nsHTMLReflowMetrics *metrics = new nsHTMLReflowMetrics(aReflowMetrics);
179 0 : metrics->mBoundingMetrics = aBoundingMetrics;
180 0 : aFrame->Properties().Set(HTMLReflowMetricsProperty(), metrics);
181 0 : }
182 :
183 : // helper method to facilitate getting the reflow and bounding metrics
184 : /* static */ void
185 0 : nsMathMLContainerFrame::GetReflowAndBoundingMetricsFor(nsIFrame* aFrame,
186 : nsHTMLReflowMetrics& aReflowMetrics,
187 : nsBoundingMetrics& aBoundingMetrics,
188 : eMathMLFrameType* aMathMLFrameType)
189 : {
190 0 : NS_PRECONDITION(aFrame, "null arg");
191 :
192 : nsHTMLReflowMetrics *metrics = static_cast<nsHTMLReflowMetrics*>
193 0 : (aFrame->Properties().Get(HTMLReflowMetricsProperty()));
194 :
195 : // IMPORTANT: This function is only meant to be called in Place() methods
196 : // where it is assumed that SaveReflowAndBoundingMetricsFor has recorded the
197 : // information.
198 0 : NS_ASSERTION(metrics, "Didn't SaveReflowAndBoundingMetricsFor frame!");
199 0 : if (metrics) {
200 0 : aReflowMetrics = *metrics;
201 0 : aBoundingMetrics = metrics->mBoundingMetrics;
202 : }
203 :
204 0 : if (aMathMLFrameType) {
205 0 : if (!IsForeignChild(aFrame)) {
206 0 : nsIMathMLFrame* mathMLFrame = do_QueryFrame(aFrame);
207 0 : if (mathMLFrame) {
208 0 : *aMathMLFrameType = mathMLFrame->GetMathMLFrameType();
209 0 : return;
210 : }
211 : }
212 0 : *aMathMLFrameType = eMathMLFrameType_UNKNOWN;
213 : }
214 :
215 : }
216 :
217 : void
218 0 : nsMathMLContainerFrame::ClearSavedChildMetrics()
219 : {
220 0 : nsIFrame* childFrame = mFrames.FirstChild();
221 0 : FramePropertyTable* props = PresContext()->PropertyTable();
222 0 : while (childFrame) {
223 0 : props->Delete(childFrame, HTMLReflowMetricsProperty());
224 0 : childFrame = childFrame->GetNextSibling();
225 : }
226 0 : }
227 :
228 : // helper to get the preferred size that a container frame should use to fire
229 : // the stretch on its stretchy child frames.
230 : void
231 0 : nsMathMLContainerFrame::GetPreferredStretchSize(nsRenderingContext& aRenderingContext,
232 : PRUint32 aOptions,
233 : nsStretchDirection aStretchDirection,
234 : nsBoundingMetrics& aPreferredStretchSize)
235 : {
236 0 : if (aOptions & STRETCH_CONSIDER_ACTUAL_SIZE) {
237 : // when our actual size is ok, just use it
238 0 : aPreferredStretchSize = mBoundingMetrics;
239 : }
240 0 : else if (aOptions & STRETCH_CONSIDER_EMBELLISHMENTS) {
241 : // compute our up-to-date size using Place()
242 0 : nsHTMLReflowMetrics metrics;
243 0 : Place(aRenderingContext, false, metrics);
244 0 : aPreferredStretchSize = metrics.mBoundingMetrics;
245 : }
246 : else {
247 : // compute a size that doesn't include embellishements
248 : bool stretchAll =
249 : NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(mPresentationData.flags) ||
250 0 : NS_MATHML_WILL_STRETCH_ALL_CHILDREN_HORIZONTALLY(mPresentationData.flags);
251 0 : NS_ASSERTION(NS_MATHML_IS_EMBELLISH_OPERATOR(mEmbellishData.flags) ||
252 : stretchAll,
253 : "invalid call to GetPreferredStretchSize");
254 0 : bool firstTime = true;
255 0 : nsBoundingMetrics bm, bmChild;
256 : nsIFrame* childFrame =
257 0 : stretchAll ? GetFirstPrincipalChild() : mPresentationData.baseFrame;
258 0 : while (childFrame) {
259 : // initializations in case this child happens not to be a MathML frame
260 0 : nsIMathMLFrame* mathMLFrame = do_QueryFrame(childFrame);
261 0 : if (mathMLFrame) {
262 0 : nsEmbellishData embellishData;
263 0 : nsPresentationData presentationData;
264 0 : mathMLFrame->GetEmbellishData(embellishData);
265 0 : mathMLFrame->GetPresentationData(presentationData);
266 0 : if (NS_MATHML_IS_EMBELLISH_OPERATOR(embellishData.flags) &&
267 : embellishData.direction == aStretchDirection &&
268 : presentationData.baseFrame) {
269 : // embellishements are not included, only consider the inner first child itself
270 : // XXXkt Does that mean the core descendent frame should be used
271 : // instead of the base child?
272 0 : nsIMathMLFrame* mathMLchildFrame = do_QueryFrame(presentationData.baseFrame);
273 0 : if (mathMLchildFrame) {
274 0 : mathMLFrame = mathMLchildFrame;
275 : }
276 : }
277 0 : mathMLFrame->GetBoundingMetrics(bmChild);
278 : }
279 : else {
280 0 : nsHTMLReflowMetrics unused;
281 0 : GetReflowAndBoundingMetricsFor(childFrame, unused, bmChild);
282 : }
283 :
284 0 : if (firstTime) {
285 0 : firstTime = false;
286 0 : bm = bmChild;
287 0 : if (!stretchAll) {
288 : // we may get here for cases such as <msup><mo>...</mo> ... </msup>,
289 : // or <maction>...<mo>...</mo></maction>.
290 0 : break;
291 : }
292 : }
293 : else {
294 0 : if (NS_MATHML_WILL_STRETCH_ALL_CHILDREN_HORIZONTALLY(mPresentationData.flags)) {
295 : // if we get here, it means this is container that will stack its children
296 : // vertically and fire an horizontal stretch on each them. This is the case
297 : // for \munder, \mover, \munderover. We just sum-up the size vertically.
298 0 : bm.descent += bmChild.ascent + bmChild.descent;
299 : // Sometimes non-spacing marks (when width is zero) are positioned
300 : // to the left of the origin, but it is the distance between left
301 : // and right bearing that is important rather than the offsets from
302 : // the origin.
303 0 : if (bmChild.width == 0) {
304 0 : bmChild.rightBearing -= bmChild.leftBearing;
305 0 : bmChild.leftBearing = 0;
306 : }
307 0 : if (bm.leftBearing > bmChild.leftBearing)
308 0 : bm.leftBearing = bmChild.leftBearing;
309 0 : if (bm.rightBearing < bmChild.rightBearing)
310 0 : bm.rightBearing = bmChild.rightBearing;
311 : }
312 0 : else if (NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(mPresentationData.flags)) {
313 : // just sum-up the sizes horizontally.
314 0 : bm += bmChild;
315 : }
316 : else {
317 0 : NS_ERROR("unexpected case in GetPreferredStretchSize");
318 0 : break;
319 : }
320 : }
321 0 : childFrame = childFrame->GetNextSibling();
322 : }
323 0 : aPreferredStretchSize = bm;
324 : }
325 0 : }
326 :
327 : NS_IMETHODIMP
328 0 : nsMathMLContainerFrame::Stretch(nsRenderingContext& aRenderingContext,
329 : nsStretchDirection aStretchDirection,
330 : nsBoundingMetrics& aContainerSize,
331 : nsHTMLReflowMetrics& aDesiredStretchSize)
332 : {
333 0 : if (NS_MATHML_IS_EMBELLISH_OPERATOR(mEmbellishData.flags)) {
334 :
335 0 : if (NS_MATHML_STRETCH_WAS_DONE(mPresentationData.flags)) {
336 0 : NS_WARNING("it is wrong to fire stretch more than once on a frame");
337 0 : return NS_OK;
338 : }
339 0 : mPresentationData.flags |= NS_MATHML_STRETCH_DONE;
340 :
341 0 : if (NS_MATHML_HAS_ERROR(mPresentationData.flags)) {
342 0 : NS_WARNING("it is wrong to fire stretch on a erroneous frame");
343 0 : return NS_OK;
344 : }
345 :
346 : // Pass the stretch to the base child ...
347 :
348 0 : nsIFrame* baseFrame = mPresentationData.baseFrame;
349 0 : if (baseFrame) {
350 0 : nsIMathMLFrame* mathMLFrame = do_QueryFrame(baseFrame);
351 0 : NS_ASSERTION(mathMLFrame, "Something is wrong somewhere");
352 0 : if (mathMLFrame) {
353 : bool stretchAll =
354 : NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(mPresentationData.flags) ||
355 0 : NS_MATHML_WILL_STRETCH_ALL_CHILDREN_HORIZONTALLY(mPresentationData.flags);
356 :
357 : // And the trick is that the child's rect.x is still holding the descent,
358 : // and rect.y is still holding the ascent ...
359 0 : nsHTMLReflowMetrics childSize(aDesiredStretchSize);
360 0 : GetReflowAndBoundingMetricsFor(baseFrame, childSize, childSize.mBoundingMetrics);
361 :
362 : // See if we should downsize and confine the stretch to us...
363 : // XXX there may be other cases where we can downsize the stretch,
364 : // e.g., the first ∑ might appear big in the following situation
365 : // <math xmlns='http://www.w3.org/1998/Math/MathML'>
366 : // <mstyle>
367 : // <msub>
368 : // <msub><mo>∑</mo><mfrac><mi>a</mi><mi>b</mi></mfrac></msub>
369 : // <msub><mo>∑</mo><mfrac><mi>a</mi><mi>b</mi></mfrac></msub>
370 : // </msub>
371 : // </mstyle>
372 : // </math>
373 0 : nsBoundingMetrics containerSize = aContainerSize;
374 0 : if (aStretchDirection != NS_STRETCH_DIRECTION_DEFAULT &&
375 : aStretchDirection != mEmbellishData.direction) {
376 0 : if (mEmbellishData.direction == NS_STRETCH_DIRECTION_UNSUPPORTED) {
377 0 : containerSize = childSize.mBoundingMetrics;
378 : }
379 : else {
380 : GetPreferredStretchSize(aRenderingContext,
381 : stretchAll ? STRETCH_CONSIDER_EMBELLISHMENTS : 0,
382 0 : mEmbellishData.direction, containerSize);
383 : }
384 : }
385 :
386 : // do the stretching...
387 : mathMLFrame->Stretch(aRenderingContext,
388 0 : mEmbellishData.direction, containerSize, childSize);
389 : // store the updated metrics
390 : SaveReflowAndBoundingMetricsFor(baseFrame, childSize,
391 0 : childSize.mBoundingMetrics);
392 :
393 : // Remember the siblings which were _deferred_.
394 : // Now that this embellished child may have changed, we need to
395 : // fire the stretch on its siblings using our updated size
396 :
397 0 : if (stretchAll) {
398 :
399 : nsStretchDirection stretchDir =
400 : NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(mPresentationData.flags) ?
401 0 : NS_STRETCH_DIRECTION_VERTICAL : NS_STRETCH_DIRECTION_HORIZONTAL;
402 :
403 : GetPreferredStretchSize(aRenderingContext, STRETCH_CONSIDER_EMBELLISHMENTS,
404 0 : stretchDir, containerSize);
405 :
406 0 : nsIFrame* childFrame = mFrames.FirstChild();
407 0 : while (childFrame) {
408 0 : if (childFrame != mPresentationData.baseFrame) {
409 0 : mathMLFrame = do_QueryFrame(childFrame);
410 0 : if (mathMLFrame) {
411 : // retrieve the metrics that was stored at the previous pass
412 : GetReflowAndBoundingMetricsFor(childFrame,
413 0 : childSize, childSize.mBoundingMetrics);
414 : // do the stretching...
415 : mathMLFrame->Stretch(aRenderingContext, stretchDir,
416 0 : containerSize, childSize);
417 : // store the updated metrics
418 : SaveReflowAndBoundingMetricsFor(childFrame, childSize,
419 0 : childSize.mBoundingMetrics);
420 : }
421 : }
422 0 : childFrame = childFrame->GetNextSibling();
423 : }
424 : }
425 :
426 : // re-position all our children
427 0 : nsresult rv = Place(aRenderingContext, true, aDesiredStretchSize);
428 0 : if (NS_MATHML_HAS_ERROR(mPresentationData.flags) || NS_FAILED(rv)) {
429 : // Make sure the child frames get their DidReflow() calls.
430 0 : DidReflowChildren(mFrames.FirstChild());
431 : }
432 :
433 : // If our parent is not embellished, it means we are the outermost embellished
434 : // container and so we put the spacing, otherwise we don't include the spacing,
435 : // the outermost embellished container will take care of it.
436 :
437 0 : nsEmbellishData parentData;
438 0 : GetEmbellishDataFrom(mParent, parentData);
439 : // ensure that we are the embellished child, not just a sibling
440 : // (need to test coreFrame since <mfrac> resets other things)
441 0 : if (parentData.coreFrame != mEmbellishData.coreFrame) {
442 : // (we fetch values from the core since they may use units that depend
443 : // on style data, and style changes could have occurred in the core since
444 : // our last visit there)
445 0 : nsEmbellishData coreData;
446 0 : GetEmbellishDataFrom(mEmbellishData.coreFrame, coreData);
447 :
448 : mBoundingMetrics.width +=
449 0 : coreData.leadingSpace + coreData.trailingSpace;
450 0 : aDesiredStretchSize.width = mBoundingMetrics.width;
451 0 : aDesiredStretchSize.mBoundingMetrics.width = mBoundingMetrics.width;
452 :
453 : nscoord dx = (NS_MATHML_IS_RTL(mPresentationData.flags) ?
454 0 : coreData.trailingSpace : coreData.leadingSpace);
455 0 : if (dx != 0) {
456 0 : mBoundingMetrics.leftBearing += dx;
457 0 : mBoundingMetrics.rightBearing += dx;
458 0 : aDesiredStretchSize.mBoundingMetrics.leftBearing += dx;
459 0 : aDesiredStretchSize.mBoundingMetrics.rightBearing += dx;
460 :
461 0 : nsIFrame* childFrame = mFrames.FirstChild();
462 0 : while (childFrame) {
463 : childFrame->SetPosition(childFrame->GetPosition()
464 0 : + nsPoint(dx, 0));
465 0 : childFrame = childFrame->GetNextSibling();
466 : }
467 : }
468 : }
469 :
470 : // Finished with these:
471 0 : ClearSavedChildMetrics();
472 : // Set our overflow area
473 0 : GatherAndStoreOverflow(&aDesiredStretchSize);
474 : }
475 : }
476 : }
477 0 : return NS_OK;
478 : }
479 :
480 : nsresult
481 0 : nsMathMLContainerFrame::FinalizeReflow(nsRenderingContext& aRenderingContext,
482 : nsHTMLReflowMetrics& aDesiredSize)
483 : {
484 : // During reflow, we use rect.x and rect.y as placeholders for the child's ascent
485 : // and descent in expectation of a stretch command. Hence we need to ensure that
486 : // a stretch command will actually be fired later on, after exiting from our
487 : // reflow. If the stretch is not fired, the rect.x, and rect.y will remain
488 : // with inappropriate data causing children to be improperly positioned.
489 : // This helper method checks to see if our parent will fire a stretch command
490 : // targeted at us. If not, we go ahead and fire an involutive stretch on
491 : // ourselves. This will clear all the rect.x and rect.y, and return our
492 : // desired size.
493 :
494 :
495 : // First, complete the post-reflow hook.
496 : // We use the information in our children rectangles to position them.
497 : // If placeOrigin==false, then Place() will not touch rect.x, and rect.y.
498 : // They will still be holding the ascent and descent for each child.
499 :
500 : // The first clause caters for any non-embellished container.
501 : // The second clause is for a container which won't fire stretch even though it is
502 : // embellished, e.g., as in <mfrac><mo>...</mo> ... </mfrac>, the test is convoluted
503 : // because it excludes the particular case of the core <mo>...</mo> itself.
504 : // (<mo> needs to fire stretch on its MathMLChar in any case to initialize it)
505 0 : bool placeOrigin = !NS_MATHML_IS_EMBELLISH_OPERATOR(mEmbellishData.flags) ||
506 0 : (mEmbellishData.coreFrame != this && !mPresentationData.baseFrame &&
507 0 : mEmbellishData.direction == NS_STRETCH_DIRECTION_UNSUPPORTED);
508 0 : nsresult rv = Place(aRenderingContext, placeOrigin, aDesiredSize);
509 :
510 : // Place() will call FinishReflowChild() when placeOrigin is true but if
511 : // it returns before reaching FinishReflowChild() due to errors we need
512 : // to fulfill the reflow protocol by calling DidReflow for the child frames
513 : // that still needs it here (or we may crash - bug 366012).
514 : // If placeOrigin is false we should reach Place() with aPlaceOrigin == true
515 : // through Stretch() eventually.
516 0 : if (NS_MATHML_HAS_ERROR(mPresentationData.flags) || NS_FAILED(rv)) {
517 0 : DidReflowChildren(GetFirstPrincipalChild());
518 0 : return rv;
519 : }
520 :
521 0 : bool parentWillFireStretch = false;
522 0 : if (!placeOrigin) {
523 : // This means the rect.x and rect.y of our children were not set!!
524 : // Don't go without checking to see if our parent will later fire a Stretch() command
525 : // targeted at us. The Stretch() will cause the rect.x and rect.y to clear...
526 0 : nsIMathMLFrame* mathMLFrame = do_QueryFrame(mParent);
527 0 : if (mathMLFrame) {
528 0 : nsEmbellishData embellishData;
529 0 : nsPresentationData presentationData;
530 0 : mathMLFrame->GetEmbellishData(embellishData);
531 0 : mathMLFrame->GetPresentationData(presentationData);
532 0 : if (NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(presentationData.flags) ||
533 : NS_MATHML_WILL_STRETCH_ALL_CHILDREN_HORIZONTALLY(presentationData.flags) ||
534 : (NS_MATHML_IS_EMBELLISH_OPERATOR(embellishData.flags)
535 : && presentationData.baseFrame == this))
536 : {
537 0 : parentWillFireStretch = true;
538 : }
539 : }
540 0 : if (!parentWillFireStretch) {
541 : // There is nobody who will fire the stretch for us, we do it ourselves!
542 :
543 : bool stretchAll =
544 : /* NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(mPresentationData.flags) || */
545 0 : NS_MATHML_WILL_STRETCH_ALL_CHILDREN_HORIZONTALLY(mPresentationData.flags);
546 :
547 0 : nsBoundingMetrics defaultSize;
548 0 : if (mEmbellishData.coreFrame == this /* case of a bare <mo>...</mo> itself */
549 : || stretchAll) { /* or <mover><mo>...</mo>...</mover>, or friends */
550 : // use our current size as computed earlier by Place()
551 0 : defaultSize = aDesiredSize.mBoundingMetrics;
552 : }
553 : else { /* case of <msup><mo>...</mo>...</msup> or friends */
554 : // compute a size that doesn't include embellishments
555 : GetPreferredStretchSize(aRenderingContext, 0, mEmbellishData.direction,
556 0 : defaultSize);
557 : }
558 : Stretch(aRenderingContext, NS_STRETCH_DIRECTION_DEFAULT, defaultSize,
559 0 : aDesiredSize);
560 : #ifdef NS_DEBUG
561 : {
562 : // The Place() call above didn't request FinishReflowChild(),
563 : // so let's check that we eventually did through Stretch().
564 0 : nsIFrame* childFrame = GetFirstPrincipalChild();
565 0 : for ( ; childFrame; childFrame = childFrame->GetNextSibling()) {
566 0 : NS_ASSERTION(!(childFrame->GetStateBits() & NS_FRAME_IN_REFLOW),
567 : "DidReflow() was never called");
568 : }
569 : }
570 : #endif
571 : }
572 : }
573 :
574 : // see if we should fix the spacing
575 0 : FixInterFrameSpacing(aDesiredSize);
576 :
577 : // Also return our bounding metrics
578 0 : aDesiredSize.mBoundingMetrics = mBoundingMetrics;
579 :
580 0 : if (!parentWillFireStretch) {
581 : // Not expecting a stretch.
582 : // Finished with these:
583 0 : ClearSavedChildMetrics();
584 : // Set our overflow area.
585 0 : GatherAndStoreOverflow(&aDesiredSize);
586 : }
587 :
588 0 : return NS_OK;
589 : }
590 :
591 :
592 : /* /////////////
593 : * nsIMathMLFrame - support methods for scripting elements (nested frames
594 : * within msub, msup, msubsup, munder, mover, munderover, mmultiscripts,
595 : * mfrac, mroot, mtable).
596 : * =============================================================================
597 : */
598 :
599 : // helper to let the update of presentation data pass through
600 : // a subtree that may contain non-mathml container frames
601 : /* static */ void
602 0 : nsMathMLContainerFrame::PropagatePresentationDataFor(nsIFrame* aFrame,
603 : PRUint32 aFlagsValues,
604 : PRUint32 aFlagsToUpdate)
605 : {
606 0 : if (!aFrame || !aFlagsToUpdate)
607 0 : return;
608 0 : nsIMathMLFrame* mathMLFrame = do_QueryFrame(aFrame);
609 0 : if (mathMLFrame) {
610 : // update
611 : mathMLFrame->UpdatePresentationData(aFlagsValues,
612 0 : aFlagsToUpdate);
613 : // propagate using the base method to make sure that the control
614 : // is passed on to MathML frames that may be overloading the method
615 : mathMLFrame->UpdatePresentationDataFromChildAt(0, -1,
616 0 : aFlagsValues, aFlagsToUpdate);
617 : }
618 : else {
619 : // propagate down the subtrees
620 0 : nsIFrame* childFrame = aFrame->GetFirstPrincipalChild();
621 0 : while (childFrame) {
622 : PropagatePresentationDataFor(childFrame,
623 0 : aFlagsValues, aFlagsToUpdate);
624 0 : childFrame = childFrame->GetNextSibling();
625 : }
626 : }
627 : }
628 :
629 : /* static */ void
630 0 : nsMathMLContainerFrame::PropagatePresentationDataFromChildAt(nsIFrame* aParentFrame,
631 : PRInt32 aFirstChildIndex,
632 : PRInt32 aLastChildIndex,
633 : PRUint32 aFlagsValues,
634 : PRUint32 aFlagsToUpdate)
635 : {
636 0 : if (!aParentFrame || !aFlagsToUpdate)
637 0 : return;
638 0 : PRInt32 index = 0;
639 0 : nsIFrame* childFrame = aParentFrame->GetFirstPrincipalChild();
640 0 : while (childFrame) {
641 0 : if ((index >= aFirstChildIndex) &&
642 : ((aLastChildIndex <= 0) || ((aLastChildIndex > 0) &&
643 : (index <= aLastChildIndex)))) {
644 : PropagatePresentationDataFor(childFrame,
645 0 : aFlagsValues, aFlagsToUpdate);
646 : }
647 0 : index++;
648 0 : childFrame = childFrame->GetNextSibling();
649 : }
650 : }
651 :
652 : /* //////////////////
653 : * Frame construction
654 : * =============================================================================
655 : */
656 :
657 :
658 : NS_IMETHODIMP
659 0 : nsMathMLContainerFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
660 : const nsRect& aDirtyRect,
661 : const nsDisplayListSet& aLists)
662 : {
663 : // report an error if something wrong was found in this frame
664 0 : if (NS_MATHML_HAS_ERROR(mPresentationData.flags)) {
665 0 : if (!IsVisibleForPainting(aBuilder))
666 0 : return NS_OK;
667 :
668 : return aLists.Content()->AppendNewToTop(
669 0 : new (aBuilder) nsDisplayMathMLError(aBuilder, this));
670 : }
671 :
672 0 : nsresult rv = DisplayBorderBackgroundOutline(aBuilder, aLists);
673 0 : NS_ENSURE_SUCCESS(rv, rv);
674 :
675 : rv = BuildDisplayListForNonBlockChildren(aBuilder, aDirtyRect, aLists,
676 0 : DISPLAY_CHILD_INLINE);
677 0 : NS_ENSURE_SUCCESS(rv, rv);
678 :
679 : #if defined(NS_DEBUG) && defined(SHOW_BOUNDING_BOX)
680 : // for visual debug
681 : // ----------------
682 : // if you want to see your bounding box, make sure to properly fill
683 : // your mBoundingMetrics and mReference point, and set
684 : // mPresentationData.flags |= NS_MATHML_SHOW_BOUNDING_METRICS
685 : // in the Init() of your sub-class
686 : rv = DisplayBoundingMetrics(aBuilder, this, mReference, mBoundingMetrics, aLists);
687 : #endif
688 0 : return rv;
689 : }
690 :
691 : // Note that this method re-builds the automatic data in the children -- not
692 : // in aParentFrame itself (except for those particular operations that the
693 : // parent frame may do in its TransmitAutomaticData()).
694 : /* static */ void
695 0 : nsMathMLContainerFrame::RebuildAutomaticDataForChildren(nsIFrame* aParentFrame)
696 : {
697 : // 1. As we descend the tree, make each child frame inherit data from
698 : // the parent
699 : // 2. As we ascend the tree, transmit any specific change that we want
700 : // down the subtrees
701 0 : nsIFrame* childFrame = aParentFrame->GetFirstPrincipalChild();
702 0 : while (childFrame) {
703 0 : nsIMathMLFrame* childMathMLFrame = do_QueryFrame(childFrame);
704 0 : if (childMathMLFrame) {
705 0 : childMathMLFrame->InheritAutomaticData(aParentFrame);
706 : }
707 0 : RebuildAutomaticDataForChildren(childFrame);
708 0 : childFrame = childFrame->GetNextSibling();
709 : }
710 0 : nsIMathMLFrame* mathMLFrame = do_QueryFrame(aParentFrame);
711 0 : if (mathMLFrame) {
712 0 : mathMLFrame->TransmitAutomaticData();
713 : }
714 0 : }
715 :
716 : /* static */ nsresult
717 0 : nsMathMLContainerFrame::ReLayoutChildren(nsIFrame* aParentFrame)
718 : {
719 0 : if (!aParentFrame)
720 0 : return NS_OK;
721 :
722 : // walk-up to the first frame that is a MathML frame, stop if we reach <math>
723 0 : nsIFrame* frame = aParentFrame;
724 0 : while (1) {
725 0 : nsIFrame* parent = frame->GetParent();
726 0 : if (!parent || !parent->GetContent())
727 0 : break;
728 :
729 : // stop if it is a MathML frame
730 0 : nsIMathMLFrame* mathMLFrame = do_QueryFrame(frame);
731 0 : if (mathMLFrame)
732 0 : break;
733 :
734 : // stop if we reach the root <math> tag
735 0 : nsIContent* content = frame->GetContent();
736 0 : NS_ASSERTION(content, "dangling frame without a content node");
737 0 : if (!content)
738 0 : break;
739 0 : if (content->GetNameSpaceID() == kNameSpaceID_MathML &&
740 0 : content->Tag() == nsGkAtoms::math)
741 0 : break;
742 :
743 : // mark the frame dirty, and continue to climb up. It's important that
744 : // we're NOT doing this to the frame we plan to pass to FrameNeedsReflow()
745 : // XXXldb Why do we need to bother with this? Marking ancestor
746 : // dirty (which we do below) should do a superset of the work this
747 : // does.
748 0 : frame->AddStateBits(NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN);
749 :
750 0 : frame = parent;
751 : }
752 :
753 : // re-sync the presentation data and embellishment data of our children
754 0 : RebuildAutomaticDataForChildren(frame);
755 :
756 : // Ask our parent frame to reflow us
757 0 : nsIFrame* parent = frame->GetParent();
758 0 : NS_ASSERTION(parent, "No parent to pass the reflow request up to");
759 0 : if (!parent)
760 0 : return NS_OK;
761 :
762 0 : frame->PresContext()->PresShell()->
763 0 : FrameNeedsReflow(frame, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
764 :
765 0 : return NS_OK;
766 : }
767 :
768 : // There are precise rules governing children of a MathML frame,
769 : // and properties such as the scriptlevel depends on those rules.
770 : // Hence for things to work, callers must use Append/Insert/etc wisely.
771 :
772 : nsresult
773 0 : nsMathMLContainerFrame::ChildListChanged(PRInt32 aModType)
774 : {
775 : // If this is an embellished frame we need to rebuild the
776 : // embellished hierarchy by walking-up to the parent of the
777 : // outermost embellished container.
778 0 : nsIFrame* frame = this;
779 0 : if (mEmbellishData.coreFrame) {
780 0 : nsIFrame* parent = mParent;
781 0 : nsEmbellishData embellishData;
782 0 : for ( ; parent; frame = parent, parent = parent->GetParent()) {
783 0 : GetEmbellishDataFrom(parent, embellishData);
784 0 : if (embellishData.coreFrame != mEmbellishData.coreFrame)
785 0 : break;
786 :
787 : // Important: do not do this to the frame we plan to pass to
788 : // ReLayoutChildren
789 : // XXXldb Why do we need to bother with this? Marking ancestor
790 : // dirty (which we do below) should do a superset of the work this
791 : // does.
792 0 : frame->AddStateBits(NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN);
793 : }
794 : }
795 0 : return ReLayoutChildren(frame);
796 : }
797 :
798 : NS_IMETHODIMP
799 0 : nsMathMLContainerFrame::AppendFrames(ChildListID aListID,
800 : nsFrameList& aFrameList)
801 : {
802 0 : if (aListID != kPrincipalList) {
803 0 : return NS_ERROR_INVALID_ARG;
804 : }
805 0 : mFrames.AppendFrames(this, aFrameList);
806 0 : return ChildListChanged(nsIDOMMutationEvent::ADDITION);
807 : }
808 :
809 : NS_IMETHODIMP
810 0 : nsMathMLContainerFrame::InsertFrames(ChildListID aListID,
811 : nsIFrame* aPrevFrame,
812 : nsFrameList& aFrameList)
813 : {
814 0 : if (aListID != kPrincipalList) {
815 0 : return NS_ERROR_INVALID_ARG;
816 : }
817 : // Insert frames after aPrevFrame
818 0 : mFrames.InsertFrames(this, aPrevFrame, aFrameList);
819 0 : return ChildListChanged(nsIDOMMutationEvent::ADDITION);
820 : }
821 :
822 : NS_IMETHODIMP
823 0 : nsMathMLContainerFrame::RemoveFrame(ChildListID aListID,
824 : nsIFrame* aOldFrame)
825 : {
826 0 : if (aListID != kPrincipalList) {
827 0 : return NS_ERROR_INVALID_ARG;
828 : }
829 : // remove the child frame
830 0 : mFrames.DestroyFrame(aOldFrame);
831 0 : return ChildListChanged(nsIDOMMutationEvent::REMOVAL);
832 : }
833 :
834 : NS_IMETHODIMP
835 0 : nsMathMLContainerFrame::AttributeChanged(PRInt32 aNameSpaceID,
836 : nsIAtom* aAttribute,
837 : PRInt32 aModType)
838 : {
839 : // XXX Since they are numerous MathML attributes that affect layout, and
840 : // we can't check all of them here, play safe by requesting a reflow.
841 : // XXXldb This should only do work for attributes that cause changes!
842 0 : PresContext()->PresShell()->
843 0 : FrameNeedsReflow(this, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
844 :
845 0 : return NS_OK;
846 : }
847 :
848 : void
849 0 : nsMathMLContainerFrame::GatherAndStoreOverflow(nsHTMLReflowMetrics* aMetrics)
850 : {
851 : // nsIFrame::FinishAndStoreOverflow likes the overflow area to include the
852 : // frame rectangle.
853 0 : aMetrics->SetOverflowAreasToDesiredBounds();
854 :
855 : // All non-child-frame content such as nsMathMLChars (and most child-frame
856 : // content) is included in mBoundingMetrics.
857 : nsRect boundingBox(mBoundingMetrics.leftBearing,
858 : aMetrics->ascent - mBoundingMetrics.ascent,
859 : mBoundingMetrics.rightBearing - mBoundingMetrics.leftBearing,
860 0 : mBoundingMetrics.ascent + mBoundingMetrics.descent);
861 :
862 : // REVIEW: Maybe this should contribute only to visual overflow
863 : // and not scrollable?
864 0 : aMetrics->mOverflowAreas.UnionAllWith(boundingBox);
865 :
866 : // mBoundingMetrics does not necessarily include content of <mpadded>
867 : // elements whose mBoundingMetrics may not be representative of the true
868 : // bounds, and doesn't include the CSS2 outline rectangles of children, so
869 : // make such to include child overflow areas.
870 0 : nsIFrame* childFrame = mFrames.FirstChild();
871 0 : while (childFrame) {
872 0 : ConsiderChildOverflow(aMetrics->mOverflowAreas, childFrame);
873 0 : childFrame = childFrame->GetNextSibling();
874 : }
875 :
876 0 : FinishAndStoreOverflow(aMetrics);
877 0 : }
878 :
879 : bool
880 0 : nsMathMLContainerFrame::UpdateOverflow()
881 : {
882 : // Our overflow areas may have changed, so reflow the frame.
883 0 : PresContext()->PresShell()->FrameNeedsReflow(
884 0 : this, nsIPresShell::eResize, NS_FRAME_IS_DIRTY);
885 :
886 : // As we're reflowing, there's no need to propagate this change.
887 0 : return false;
888 : }
889 :
890 : nsresult
891 0 : nsMathMLContainerFrame::ReflowChild(nsIFrame* aChildFrame,
892 : nsPresContext* aPresContext,
893 : nsHTMLReflowMetrics& aDesiredSize,
894 : const nsHTMLReflowState& aReflowState,
895 : nsReflowStatus& aStatus)
896 : {
897 : // Having foreign/hybrid children, e.g., from html markups, is not defined by
898 : // the MathML spec. But it can happen in practice, e.g., <html:img> allows us
899 : // to do some cool demos... or we may have a child that is an nsInlineFrame
900 : // from a generated content such as :before { content: open-quote } or
901 : // :after { content: close-quote }. Unfortunately, the other frames out-there
902 : // may expect their own invariants that are not met when we mix things.
903 : // Hence we do not claim their support, but we will nevertheless attempt to keep
904 : // them in the flow, if we can get their desired size. We observed that most
905 : // frames may be reflowed generically, but nsInlineFrames need extra care.
906 :
907 : #ifdef DEBUG
908 0 : nsInlineFrame* inlineFrame = do_QueryFrame(aChildFrame);
909 0 : NS_ASSERTION(!inlineFrame, "Inline frames should be wrapped in blocks");
910 : #endif
911 :
912 : nsresult rv = nsContainerFrame::
913 : ReflowChild(aChildFrame, aPresContext, aDesiredSize, aReflowState,
914 0 : 0, 0, NS_FRAME_NO_MOVE_FRAME, aStatus);
915 :
916 0 : if (NS_FAILED(rv))
917 0 : return rv;
918 :
919 0 : if (aDesiredSize.ascent == nsHTMLReflowMetrics::ASK_FOR_BASELINE) {
920 : // This will be suitable for inline frames, which are wrapped in a block.
921 0 : if(!nsLayoutUtils::GetLastLineBaseline(aChildFrame,
922 0 : &aDesiredSize.ascent)) {
923 : // We don't expect any other block children so just place the frame on
924 : // the baseline instead of going through DidReflow() and
925 : // GetBaseline(). This is what nsFrame::GetBaseline() will do anyway.
926 0 : aDesiredSize.ascent = aDesiredSize.height;
927 : }
928 : }
929 0 : if (IsForeignChild(aChildFrame)) {
930 : // use ComputeTightBounds API as aDesiredSize.mBoundingMetrics is not set.
931 0 : nsRect r = aChildFrame->ComputeTightBounds(aReflowState.rendContext->ThebesContext());
932 0 : aDesiredSize.mBoundingMetrics.leftBearing = r.x;
933 0 : aDesiredSize.mBoundingMetrics.rightBearing = r.XMost();
934 0 : aDesiredSize.mBoundingMetrics.ascent = aDesiredSize.ascent - r.y;
935 0 : aDesiredSize.mBoundingMetrics.descent = r.YMost() - aDesiredSize.ascent;
936 0 : aDesiredSize.mBoundingMetrics.width = aDesiredSize.width;
937 : }
938 0 : return rv;
939 : }
940 :
941 : NS_IMETHODIMP
942 0 : nsMathMLContainerFrame::Reflow(nsPresContext* aPresContext,
943 : nsHTMLReflowMetrics& aDesiredSize,
944 : const nsHTMLReflowState& aReflowState,
945 : nsReflowStatus& aStatus)
946 : {
947 0 : aDesiredSize.width = aDesiredSize.height = 0;
948 0 : aDesiredSize.ascent = 0;
949 0 : aDesiredSize.mBoundingMetrics = nsBoundingMetrics();
950 :
951 : /////////////
952 : // Reflow children
953 : // Asking each child to cache its bounding metrics
954 :
955 : nsReflowStatus childStatus;
956 0 : nsSize availSize(aReflowState.ComputedWidth(), NS_UNCONSTRAINEDSIZE);
957 0 : nsIFrame* childFrame = mFrames.FirstChild();
958 0 : while (childFrame) {
959 0 : nsHTMLReflowMetrics childDesiredSize(aDesiredSize.mFlags);
960 : nsHTMLReflowState childReflowState(aPresContext, aReflowState,
961 0 : childFrame, availSize);
962 : nsresult rv = ReflowChild(childFrame, aPresContext, childDesiredSize,
963 0 : childReflowState, childStatus);
964 : //NS_ASSERTION(NS_FRAME_IS_COMPLETE(childStatus), "bad status");
965 0 : if (NS_FAILED(rv)) {
966 : // Call DidReflow() for the child frames we successfully did reflow.
967 0 : DidReflowChildren(mFrames.FirstChild(), childFrame);
968 0 : return rv;
969 : }
970 :
971 : SaveReflowAndBoundingMetricsFor(childFrame, childDesiredSize,
972 0 : childDesiredSize.mBoundingMetrics);
973 0 : childFrame = childFrame->GetNextSibling();
974 : }
975 :
976 : /////////////
977 : // If we are a container which is entitled to stretch its children, then we
978 : // ask our stretchy children to stretch themselves
979 :
980 : // The stretching of siblings of an embellished child is _deferred_ until
981 : // after finishing the stretching of the embellished child - bug 117652
982 :
983 0 : if (!NS_MATHML_IS_EMBELLISH_OPERATOR(mEmbellishData.flags) &&
984 : (NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(mPresentationData.flags) ||
985 : NS_MATHML_WILL_STRETCH_ALL_CHILDREN_HORIZONTALLY(mPresentationData.flags))) {
986 :
987 : // get the stretchy direction
988 : nsStretchDirection stretchDir =
989 : NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(mPresentationData.flags)
990 : ? NS_STRETCH_DIRECTION_VERTICAL
991 0 : : NS_STRETCH_DIRECTION_HORIZONTAL;
992 :
993 : // what size should we use to stretch our stretchy children
994 : // We don't use STRETCH_CONSIDER_ACTUAL_SIZE -- because our size is not known yet
995 : // We don't use STRETCH_CONSIDER_EMBELLISHMENTS -- because we don't want to
996 : // include them in the caculations of the size of stretchy elements
997 0 : nsBoundingMetrics containerSize;
998 : GetPreferredStretchSize(*aReflowState.rendContext, 0, stretchDir,
999 0 : containerSize);
1000 :
1001 : // fire the stretch on each child
1002 0 : childFrame = mFrames.FirstChild();
1003 0 : while (childFrame) {
1004 0 : nsIMathMLFrame* mathMLFrame = do_QueryFrame(childFrame);
1005 0 : if (mathMLFrame) {
1006 : // retrieve the metrics that was stored at the previous pass
1007 0 : nsHTMLReflowMetrics childDesiredSize;
1008 : GetReflowAndBoundingMetricsFor(childFrame,
1009 0 : childDesiredSize, childDesiredSize.mBoundingMetrics);
1010 :
1011 : mathMLFrame->Stretch(*aReflowState.rendContext, stretchDir,
1012 0 : containerSize, childDesiredSize);
1013 : // store the updated metrics
1014 : SaveReflowAndBoundingMetricsFor(childFrame, childDesiredSize,
1015 0 : childDesiredSize.mBoundingMetrics);
1016 : }
1017 0 : childFrame = childFrame->GetNextSibling();
1018 : }
1019 : }
1020 :
1021 : /////////////
1022 : // Place children now by re-adjusting the origins to align the baselines
1023 0 : FinalizeReflow(*aReflowState.rendContext, aDesiredSize);
1024 :
1025 0 : aStatus = NS_FRAME_COMPLETE;
1026 0 : NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
1027 0 : return NS_OK;
1028 : }
1029 :
1030 : /* virtual */ nscoord
1031 0 : nsMathMLContainerFrame::GetMinWidth(nsRenderingContext *aRenderingContext)
1032 : {
1033 : nscoord result;
1034 0 : DISPLAY_MIN_WIDTH(this, result);
1035 0 : result = GetIntrinsicWidth(aRenderingContext);
1036 0 : return result;
1037 : }
1038 :
1039 : /* virtual */ nscoord
1040 0 : nsMathMLContainerFrame::GetPrefWidth(nsRenderingContext *aRenderingContext)
1041 : {
1042 : nscoord result;
1043 0 : DISPLAY_MIN_WIDTH(this, result);
1044 0 : result = GetIntrinsicWidth(aRenderingContext);
1045 0 : return result;
1046 : }
1047 :
1048 : /* virtual */ nscoord
1049 0 : nsMathMLContainerFrame::GetIntrinsicWidth(nsRenderingContext* aRenderingContext)
1050 : {
1051 : // Get child widths
1052 0 : nsIFrame* childFrame = mFrames.FirstChild();
1053 0 : while (childFrame) {
1054 : // XXX This includes margin while Reflow currently doesn't consider
1055 : // margin, so we may end up with too much space, but, with stretchy
1056 : // characters, this is an approximation anyway.
1057 : nscoord width =
1058 : nsLayoutUtils::IntrinsicForContainer(aRenderingContext, childFrame,
1059 0 : nsLayoutUtils::PREF_WIDTH);
1060 :
1061 0 : nsHTMLReflowMetrics childDesiredSize;
1062 0 : childDesiredSize.width = width;
1063 0 : childDesiredSize.mBoundingMetrics.width = width;
1064 : // TODO: we need nsIFrame::GetIntrinsicHBounds() for better values here.
1065 0 : childDesiredSize.mBoundingMetrics.leftBearing = 0;
1066 0 : childDesiredSize.mBoundingMetrics.rightBearing = width;
1067 :
1068 : SaveReflowAndBoundingMetricsFor(childFrame, childDesiredSize,
1069 0 : childDesiredSize.mBoundingMetrics);
1070 :
1071 0 : childFrame = childFrame->GetNextSibling();
1072 : }
1073 :
1074 : // Measure
1075 0 : nsHTMLReflowMetrics desiredSize;
1076 0 : nsresult rv = MeasureForWidth(*aRenderingContext, desiredSize);
1077 0 : if (NS_FAILED(rv)) {
1078 0 : ReflowError(*aRenderingContext, desiredSize);
1079 : }
1080 :
1081 0 : ClearSavedChildMetrics();
1082 :
1083 0 : return desiredSize.width;
1084 : }
1085 :
1086 : /* virtual */ nsresult
1087 0 : nsMathMLContainerFrame::MeasureForWidth(nsRenderingContext& aRenderingContext,
1088 : nsHTMLReflowMetrics& aDesiredSize)
1089 : {
1090 0 : return Place(aRenderingContext, false, aDesiredSize);
1091 : }
1092 :
1093 :
1094 : // see spacing table in Chapter 18, TeXBook (p.170)
1095 : // Our table isn't quite identical to TeX because operators have
1096 : // built-in values for lspace & rspace in the Operator Dictionary.
1097 : static PRInt32 kInterFrameSpacingTable[eMathMLFrameType_COUNT][eMathMLFrameType_COUNT] =
1098 : {
1099 : // in units of muspace.
1100 : // upper half of the byte is set if the
1101 : // spacing is not to be used for scriptlevel > 0
1102 :
1103 : /* Ord OpOrd OpInv OpUsr Inner Italic Upright */
1104 : /*Ord */ {0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00},
1105 : /*OpOrd*/ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
1106 : /*OpInv*/ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
1107 : /*OpUsr*/ {0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01},
1108 : /*Inner*/ {0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01},
1109 : /*Italic*/ {0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01},
1110 : /*Upright*/ {0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00}
1111 : };
1112 :
1113 : #define GET_INTERSPACE(scriptlevel_, frametype1_, frametype2_, space_) \
1114 : /* no space if there is a frame that we know nothing about */ \
1115 : if (frametype1_ == eMathMLFrameType_UNKNOWN || \
1116 : frametype2_ == eMathMLFrameType_UNKNOWN) \
1117 : space_ = 0; \
1118 : else { \
1119 : space_ = kInterFrameSpacingTable[frametype1_][frametype2_]; \
1120 : space_ = (scriptlevel_ > 0 && (space_ & 0xF0)) \
1121 : ? 0 /* spacing is disabled */ \
1122 : : space_ & 0x0F; \
1123 : } \
1124 :
1125 : // This function computes the inter-space between two frames. However,
1126 : // since invisible operators need special treatment, the inter-space may
1127 : // be delayed when an invisible operator is encountered. In this case,
1128 : // the function will carry the inter-space forward until it is determined
1129 : // that it can be applied properly (i.e., until we encounter a visible
1130 : // frame where to decide whether to accept or reject the inter-space).
1131 : // aFromFrameType: remembers the frame when the carry-forward initiated.
1132 : // aCarrySpace: keeps track of the inter-space that is delayed.
1133 : // @returns: current inter-space (which is 0 when the true inter-space is
1134 : // delayed -- and thus has no effect since the frame is invisible anyway).
1135 : static nscoord
1136 0 : GetInterFrameSpacing(PRInt32 aScriptLevel,
1137 : eMathMLFrameType aFirstFrameType,
1138 : eMathMLFrameType aSecondFrameType,
1139 : eMathMLFrameType* aFromFrameType, // IN/OUT
1140 : PRInt32* aCarrySpace) // IN/OUT
1141 : {
1142 0 : eMathMLFrameType firstType = aFirstFrameType;
1143 0 : eMathMLFrameType secondType = aSecondFrameType;
1144 :
1145 : PRInt32 space;
1146 0 : GET_INTERSPACE(aScriptLevel, firstType, secondType, space);
1147 :
1148 : // feedback control to avoid the inter-space to be added when not necessary
1149 0 : if (secondType == eMathMLFrameType_OperatorInvisible) {
1150 : // see if we should start to carry the space forward until we
1151 : // encounter a visible frame
1152 0 : if (*aFromFrameType == eMathMLFrameType_UNKNOWN) {
1153 0 : *aFromFrameType = firstType;
1154 0 : *aCarrySpace = space;
1155 : }
1156 : // keep carrying *aCarrySpace forward, while returning 0 for this stage
1157 0 : space = 0;
1158 : }
1159 0 : else if (*aFromFrameType != eMathMLFrameType_UNKNOWN) {
1160 : // no carry-forward anymore, get the real inter-space between
1161 : // the two frames of interest
1162 :
1163 0 : firstType = *aFromFrameType;
1164 :
1165 : // But... the invisible operator that we encountered earlier could
1166 : // be sitting between italic and upright identifiers, e.g.,
1167 : //
1168 : // 1. <mi>sin</mi> <mo>⁡</mo> <mi>x</mi>
1169 : // 2. <mi>x</mi> <mo>&InvisibileTime;</mo> <mi>sin</mi>
1170 : //
1171 : // the trick to get the inter-space in either situation
1172 : // is to promote "<mi>sin</mi><mo>⁡</mo>" and
1173 : // "<mo>&InvisibileTime;</mo><mi>sin</mi>" to user-defined operators...
1174 0 : if (firstType == eMathMLFrameType_UprightIdentifier) {
1175 0 : firstType = eMathMLFrameType_OperatorUserDefined;
1176 : }
1177 0 : else if (secondType == eMathMLFrameType_UprightIdentifier) {
1178 0 : secondType = eMathMLFrameType_OperatorUserDefined;
1179 : }
1180 :
1181 0 : GET_INTERSPACE(aScriptLevel, firstType, secondType, space);
1182 :
1183 : // Now, we have two values: the computed space and the space that
1184 : // has been carried forward until now. Which value do we pick?
1185 : // If the second type is an operator (e.g., fence), it already has
1186 : // built-in lspace & rspace, so we let them win. Otherwise we pick
1187 : // the max between the two values that we have.
1188 0 : if (secondType != eMathMLFrameType_OperatorOrdinary &&
1189 : space < *aCarrySpace)
1190 0 : space = *aCarrySpace;
1191 :
1192 : // reset everything now that the carry-forward is done
1193 0 : *aFromFrameType = eMathMLFrameType_UNKNOWN;
1194 0 : *aCarrySpace = 0;
1195 : }
1196 :
1197 0 : return space;
1198 : }
1199 :
1200 0 : static nscoord GetThinSpace(const nsStyleFont* aStyleFont)
1201 : {
1202 0 : return NSToCoordRound(float(aStyleFont->mFont.size)*float(3) / float(18));
1203 : }
1204 :
1205 0 : class nsMathMLContainerFrame::RowChildFrameIterator {
1206 : public:
1207 0 : explicit RowChildFrameIterator(nsMathMLContainerFrame* aParentFrame) :
1208 : mParentFrame(aParentFrame),
1209 : mX(0),
1210 : mCarrySpace(0),
1211 : mFromFrameType(eMathMLFrameType_UNKNOWN),
1212 0 : mRTL(NS_MATHML_IS_RTL(aParentFrame->mPresentationData.flags))
1213 : {
1214 0 : if (!mRTL) {
1215 0 : mChildFrame = aParentFrame->mFrames.FirstChild();
1216 : } else {
1217 0 : mChildFrame = aParentFrame->mFrames.LastChild();
1218 : }
1219 :
1220 0 : if (!mChildFrame)
1221 0 : return;
1222 :
1223 0 : InitMetricsForChild();
1224 : }
1225 :
1226 0 : RowChildFrameIterator& operator++()
1227 : {
1228 : // add child size + italic correction
1229 0 : mX += mSize.mBoundingMetrics.width + mItalicCorrection;
1230 :
1231 0 : if (!mRTL) {
1232 0 : mChildFrame = mChildFrame->GetNextSibling();
1233 : } else {
1234 0 : mChildFrame = mChildFrame->GetPrevSibling();
1235 : }
1236 :
1237 0 : if (!mChildFrame)
1238 0 : return *this;
1239 :
1240 0 : eMathMLFrameType prevFrameType = mChildFrameType;
1241 0 : InitMetricsForChild();
1242 :
1243 : // add inter frame spacing
1244 0 : const nsStyleFont* font = mParentFrame->GetStyleFont();
1245 : nscoord space =
1246 : GetInterFrameSpacing(font->mScriptLevel,
1247 : prevFrameType, mChildFrameType,
1248 0 : &mFromFrameType, &mCarrySpace);
1249 0 : mX += space * GetThinSpace(font);
1250 0 : return *this;
1251 : }
1252 :
1253 0 : nsIFrame* Frame() const { return mChildFrame; }
1254 0 : nscoord X() const { return mX; }
1255 0 : const nsHTMLReflowMetrics& ReflowMetrics() const { return mSize; }
1256 0 : nscoord Ascent() const { return mSize.ascent; }
1257 0 : nscoord Descent() const { return mSize.height - mSize.ascent; }
1258 0 : const nsBoundingMetrics& BoundingMetrics() const {
1259 0 : return mSize.mBoundingMetrics;
1260 : }
1261 :
1262 : private:
1263 : const nsMathMLContainerFrame* mParentFrame;
1264 : nsIFrame* mChildFrame;
1265 : nsHTMLReflowMetrics mSize;
1266 : nscoord mX;
1267 :
1268 : nscoord mItalicCorrection;
1269 : eMathMLFrameType mChildFrameType;
1270 : PRInt32 mCarrySpace;
1271 : eMathMLFrameType mFromFrameType;
1272 :
1273 : bool mRTL;
1274 :
1275 0 : void InitMetricsForChild()
1276 : {
1277 : GetReflowAndBoundingMetricsFor(mChildFrame, mSize, mSize.mBoundingMetrics,
1278 0 : &mChildFrameType);
1279 : nscoord leftCorrection, rightCorrection;
1280 : GetItalicCorrection(mSize.mBoundingMetrics,
1281 0 : leftCorrection, rightCorrection);
1282 0 : if (!mChildFrame->GetPrevSibling() &&
1283 0 : mParentFrame->GetContent()->Tag() == nsGkAtoms::msqrt_) {
1284 : // Remove leading correction in <msqrt> because the sqrt glyph itself is
1285 : // there first.
1286 0 : if (!mRTL) {
1287 0 : leftCorrection = 0;
1288 : } else {
1289 0 : rightCorrection = 0;
1290 : }
1291 : }
1292 : // add left correction -- this fixes the problem of the italic 'f'
1293 : // e.g., <mo>q</mo> <mi>f</mi> <mo>I</mo>
1294 0 : mX += leftCorrection;
1295 0 : mItalicCorrection = rightCorrection;
1296 0 : }
1297 : };
1298 :
1299 : /* virtual */ nsresult
1300 0 : nsMathMLContainerFrame::Place(nsRenderingContext& aRenderingContext,
1301 : bool aPlaceOrigin,
1302 : nsHTMLReflowMetrics& aDesiredSize)
1303 : {
1304 : // This is needed in case this frame is empty (i.e., no child frames)
1305 0 : mBoundingMetrics = nsBoundingMetrics();
1306 :
1307 0 : RowChildFrameIterator child(this);
1308 0 : nscoord ascent = 0, descent = 0;
1309 0 : while (child.Frame()) {
1310 0 : if (descent < child.Descent())
1311 0 : descent = child.Descent();
1312 0 : if (ascent < child.Ascent())
1313 0 : ascent = child.Ascent();
1314 : // add the child size
1315 0 : mBoundingMetrics.width = child.X();
1316 0 : mBoundingMetrics += child.BoundingMetrics();
1317 0 : ++child;
1318 : }
1319 : // Add the italic correction at the end (including the last child).
1320 : // This gives a nice gap between math and non-math frames, and still
1321 : // gives the same math inter-spacing in case this frame connects to
1322 : // another math frame
1323 0 : mBoundingMetrics.width = child.X();
1324 :
1325 0 : aDesiredSize.width = mBoundingMetrics.width;
1326 0 : aDesiredSize.height = ascent + descent;
1327 0 : aDesiredSize.ascent = ascent;
1328 0 : aDesiredSize.mBoundingMetrics = mBoundingMetrics;
1329 :
1330 0 : mReference.x = 0;
1331 0 : mReference.y = aDesiredSize.ascent;
1332 :
1333 : //////////////////
1334 : // Place Children
1335 :
1336 0 : if (aPlaceOrigin) {
1337 0 : PositionRowChildFrames(0, aDesiredSize.ascent);
1338 : }
1339 :
1340 0 : return NS_OK;
1341 : }
1342 :
1343 : void
1344 0 : nsMathMLContainerFrame::PositionRowChildFrames(nscoord aOffsetX,
1345 : nscoord aBaseline)
1346 : {
1347 0 : RowChildFrameIterator child(this);
1348 0 : while (child.Frame()) {
1349 0 : nscoord dx = aOffsetX + child.X();
1350 0 : nscoord dy = aBaseline - child.Ascent();
1351 : FinishReflowChild(child.Frame(), PresContext(), nsnull,
1352 0 : child.ReflowMetrics(), dx, dy, 0);
1353 0 : ++child;
1354 : }
1355 0 : }
1356 :
1357 1464 : class ForceReflow : public nsIReflowCallback {
1358 : public:
1359 0 : virtual bool ReflowFinished() {
1360 0 : return true;
1361 : }
1362 0 : virtual void ReflowCallbackCanceled() {}
1363 : };
1364 :
1365 : // We only need one of these so we just make it a static global, no need
1366 : // to dynamically allocate/destroy it.
1367 1464 : static ForceReflow gForceReflow;
1368 :
1369 : void
1370 0 : nsMathMLContainerFrame::SetIncrementScriptLevel(PRInt32 aChildIndex, bool aIncrement)
1371 : {
1372 0 : nsIFrame* child = PrincipalChildList().FrameAt(aChildIndex);
1373 0 : if (!child)
1374 0 : return;
1375 0 : nsIContent* content = child->GetContent();
1376 0 : if (!content->IsMathML())
1377 0 : return;
1378 0 : nsMathMLElement* element = static_cast<nsMathMLElement*>(content);
1379 :
1380 0 : if (element->GetIncrementScriptLevel() == aIncrement)
1381 0 : return;
1382 :
1383 : // XXXroc this does a ContentStatesChanged, is it safe to call here? If
1384 : // not we should do it in a post-reflow callback.
1385 0 : element->SetIncrementScriptLevel(aIncrement, true);
1386 0 : PresContext()->PresShell()->PostReflowCallback(&gForceReflow);
1387 : }
1388 :
1389 : // helpers to fix the inter-spacing when <math> is the only parent
1390 : // e.g., it fixes <math> <mi>f</mi> <mo>q</mo> <mi>f</mi> <mo>I</mo> </math>
1391 :
1392 : static nscoord
1393 0 : GetInterFrameSpacingFor(PRInt32 aScriptLevel,
1394 : nsIFrame* aParentFrame,
1395 : nsIFrame* aChildFrame)
1396 : {
1397 0 : nsIFrame* childFrame = aParentFrame->GetFirstPrincipalChild();
1398 0 : if (!childFrame || aChildFrame == childFrame)
1399 0 : return 0;
1400 :
1401 0 : PRInt32 carrySpace = 0;
1402 0 : eMathMLFrameType fromFrameType = eMathMLFrameType_UNKNOWN;
1403 0 : eMathMLFrameType prevFrameType = eMathMLFrameType_UNKNOWN;
1404 0 : eMathMLFrameType childFrameType = nsMathMLFrame::GetMathMLFrameTypeFor(childFrame);
1405 0 : childFrame = childFrame->GetNextSibling();
1406 0 : while (childFrame) {
1407 0 : prevFrameType = childFrameType;
1408 0 : childFrameType = nsMathMLFrame::GetMathMLFrameTypeFor(childFrame);
1409 : nscoord space = GetInterFrameSpacing(aScriptLevel,
1410 0 : prevFrameType, childFrameType, &fromFrameType, &carrySpace);
1411 0 : if (aChildFrame == childFrame) {
1412 : // get thinspace
1413 0 : nsStyleContext* parentContext = aParentFrame->GetStyleContext();
1414 0 : nscoord thinSpace = GetThinSpace(parentContext->GetStyleFont());
1415 : // we are done
1416 0 : return space * thinSpace;
1417 : }
1418 0 : childFrame = childFrame->GetNextSibling();
1419 : }
1420 :
1421 0 : NS_NOTREACHED("child not in the childlist of its parent");
1422 0 : return 0;
1423 : }
1424 :
1425 : nscoord
1426 0 : nsMathMLContainerFrame::FixInterFrameSpacing(nsHTMLReflowMetrics& aDesiredSize)
1427 : {
1428 0 : nscoord gap = 0;
1429 0 : nsIContent* parentContent = mParent->GetContent();
1430 0 : if (NS_UNLIKELY(!parentContent)) {
1431 0 : return 0;
1432 : }
1433 0 : nsIAtom *parentTag = parentContent->Tag();
1434 0 : if (parentContent->GetNameSpaceID() == kNameSpaceID_MathML &&
1435 : (parentTag == nsGkAtoms::math || parentTag == nsGkAtoms::mtd_)) {
1436 0 : gap = GetInterFrameSpacingFor(GetStyleFont()->mScriptLevel, mParent, this);
1437 : // add our own italic correction
1438 0 : nscoord leftCorrection = 0, italicCorrection = 0;
1439 0 : GetItalicCorrection(mBoundingMetrics, leftCorrection, italicCorrection);
1440 0 : gap += leftCorrection;
1441 : // see if we should shift our children to account for the correction
1442 0 : if (gap) {
1443 0 : nsIFrame* childFrame = mFrames.FirstChild();
1444 0 : while (childFrame) {
1445 0 : childFrame->SetPosition(childFrame->GetPosition() + nsPoint(gap, 0));
1446 0 : childFrame = childFrame->GetNextSibling();
1447 : }
1448 0 : mBoundingMetrics.leftBearing += gap;
1449 0 : mBoundingMetrics.rightBearing += gap;
1450 0 : mBoundingMetrics.width += gap;
1451 0 : aDesiredSize.width += gap;
1452 : }
1453 0 : mBoundingMetrics.width += italicCorrection;
1454 0 : aDesiredSize.width += italicCorrection;
1455 : }
1456 0 : return gap;
1457 : }
1458 :
1459 : /* static */ void
1460 0 : nsMathMLContainerFrame::DidReflowChildren(nsIFrame* aFirst, nsIFrame* aStop)
1461 :
1462 : {
1463 0 : if (NS_UNLIKELY(!aFirst))
1464 0 : return;
1465 :
1466 0 : for (nsIFrame* frame = aFirst;
1467 : frame != aStop;
1468 : frame = frame->GetNextSibling()) {
1469 0 : NS_ASSERTION(frame, "aStop isn't a sibling");
1470 0 : if (frame->GetStateBits() & NS_FRAME_IN_REFLOW) {
1471 : // finish off principal descendants, too
1472 0 : nsIFrame* grandchild = frame->GetFirstPrincipalChild();
1473 0 : if (grandchild)
1474 0 : DidReflowChildren(grandchild, nsnull);
1475 :
1476 : frame->DidReflow(frame->PresContext(), nsnull,
1477 0 : NS_FRAME_REFLOW_FINISHED);
1478 : }
1479 : }
1480 : }
1481 :
1482 : // helper used by mstyle, mphantom, mpadded and mrow in their implementations
1483 : // of TransmitAutomaticData().
1484 : nsresult
1485 0 : nsMathMLContainerFrame::TransmitAutomaticDataForMrowLikeElement()
1486 : {
1487 : //
1488 : // One loop to check both conditions below:
1489 : //
1490 : // 1) whether all the children of the mrow-like element are space-like.
1491 : //
1492 : // The REC defines the following elements to be "space-like":
1493 : // * an mstyle, mphantom, or mpadded element, all of whose direct
1494 : // sub-expressions are space-like;
1495 : // * an mrow all of whose direct sub-expressions are space-like.
1496 : //
1497 : // 2) whether all but one child of the mrow-like element are space-like and
1498 : // this non-space-like child is an embellished operator.
1499 : //
1500 : // The REC defines the following elements to be embellished operators:
1501 : // * one of the elements mstyle, mphantom, or mpadded, such that an mrow
1502 : // containing the same arguments would be an embellished operator;
1503 : // * an mrow whose arguments consist (in any order) of one embellished
1504 : // operator and zero or more space-like elements.
1505 : //
1506 : nsIFrame *childFrame, *baseFrame;
1507 0 : bool embellishedOpFound = false;
1508 0 : nsEmbellishData embellishData;
1509 :
1510 0 : for (childFrame = GetFirstPrincipalChild();
1511 : childFrame;
1512 : childFrame = childFrame->GetNextSibling()) {
1513 0 : nsIMathMLFrame* mathMLFrame = do_QueryFrame(childFrame);
1514 0 : if (!mathMLFrame) break;
1515 0 : if (!mathMLFrame->IsSpaceLike()) {
1516 0 : if (embellishedOpFound) break;
1517 0 : baseFrame = childFrame;
1518 0 : GetEmbellishDataFrom(baseFrame, embellishData);
1519 0 : if (!NS_MATHML_IS_EMBELLISH_OPERATOR(embellishData.flags)) break;
1520 0 : embellishedOpFound = true;
1521 : }
1522 : }
1523 :
1524 0 : if (!childFrame) {
1525 : // we successfully went to the end of the loop. This means that one of
1526 : // condition 1) or 2) holds.
1527 0 : if (!embellishedOpFound) {
1528 : // the mrow-like element is space-like.
1529 0 : mPresentationData.flags |= NS_MATHML_SPACE_LIKE;
1530 : } else {
1531 : // the mrow-like element is an embellished operator.
1532 : // let the state of the embellished operator found bubble to us.
1533 0 : mPresentationData.baseFrame = baseFrame;
1534 0 : mEmbellishData = embellishData;
1535 : }
1536 : }
1537 :
1538 0 : if (childFrame || !embellishedOpFound) {
1539 : // The element is not embellished operator
1540 0 : mPresentationData.baseFrame = nsnull;
1541 0 : mEmbellishData.flags = 0;
1542 0 : mEmbellishData.coreFrame = nsnull;
1543 0 : mEmbellishData.direction = NS_STRETCH_DIRECTION_UNSUPPORTED;
1544 0 : mEmbellishData.leadingSpace = 0;
1545 0 : mEmbellishData.trailingSpace = 0;
1546 : }
1547 :
1548 0 : if (childFrame || embellishedOpFound) {
1549 : // The element is not space-like
1550 0 : mPresentationData.flags &= ~NS_MATHML_SPACE_LIKE;
1551 : }
1552 :
1553 0 : return NS_OK;
1554 : }
1555 :
1556 : //==========================
1557 :
1558 : nsIFrame*
1559 0 : NS_NewMathMLmathBlockFrame(nsIPresShell* aPresShell, nsStyleContext* aContext,
1560 : PRUint32 aFlags)
1561 : {
1562 0 : nsMathMLmathBlockFrame* it = new (aPresShell) nsMathMLmathBlockFrame(aContext);
1563 0 : if (it) {
1564 0 : it->SetFlags(aFlags);
1565 : }
1566 0 : return it;
1567 : }
1568 :
1569 0 : NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmathBlockFrame)
1570 :
1571 : nsIFrame*
1572 0 : NS_NewMathMLmathInlineFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
1573 : {
1574 0 : return new (aPresShell) nsMathMLmathInlineFrame(aContext);
1575 : }
1576 :
1577 4392 : NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmathInlineFrame)
|