Coverage Report

Created: 2018-09-25 14:53

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