Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/layout/mathml/nsMathMLmfencedFrame.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 "gfxContext.h"
8
#include "nsMathMLmfencedFrame.h"
9
#include "nsMathMLChar.h"
10
#include <algorithm>
11
12
using namespace mozilla;
13
14
//
15
// <mfenced> -- surround content with a pair of fences
16
//
17
18
nsIFrame*
19
NS_NewMathMLmfencedFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle)
20
0
{
21
0
  return new (aPresShell) nsMathMLmfencedFrame(aStyle);
22
0
}
23
24
NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmfencedFrame)
25
26
void
27
nsMathMLmfencedFrame::DestroyFrom(nsIFrame* aDestructRoot,
28
                                  PostDestroyData& aPostDestroyData)
29
0
{
30
0
  RemoveFencesAndSeparators();
31
0
  nsMathMLContainerFrame::DestroyFrom(aDestructRoot, aPostDestroyData);
32
0
}
33
34
NS_IMETHODIMP
35
nsMathMLmfencedFrame::InheritAutomaticData(nsIFrame* aParent)
36
0
{
37
0
  // let the base class get the default from our parent
38
0
  nsMathMLContainerFrame::InheritAutomaticData(aParent);
39
0
40
0
  mPresentationData.flags |= NS_MATHML_STRETCH_ALL_CHILDREN_VERTICALLY;
41
0
42
0
  RemoveFencesAndSeparators();
43
0
  CreateFencesAndSeparators(PresContext());
44
0
45
0
  return NS_OK;
46
0
}
47
48
void
49
nsMathMLmfencedFrame::SetInitialChildList(ChildListID     aListID,
50
                                          nsFrameList&    aChildList)
51
0
{
52
0
  // First, let the base class do its work
53
0
  nsMathMLContainerFrame::SetInitialChildList(aListID, aChildList);
54
0
55
0
  // InheritAutomaticData will not get called if our parent is not a mathml
56
0
  // frame, so initialize NS_MATHML_STRETCH_ALL_CHILDREN_VERTICALLY for
57
0
  // GetPreferredStretchSize() from Reflow().
58
0
  mPresentationData.flags |= NS_MATHML_STRETCH_ALL_CHILDREN_VERTICALLY;
59
0
  // No need to track the ComputedStyle given to our MathML chars.
60
0
  // The Style System will use Get/SetAdditionalComputedStyle() to keep them
61
0
  // up-to-date if dynamic changes arise.
62
0
  CreateFencesAndSeparators(PresContext());
63
0
}
64
65
nsresult
66
nsMathMLmfencedFrame::AttributeChanged(int32_t         aNameSpaceID,
67
                                       nsAtom*        aAttribute,
68
                                       int32_t         aModType)
69
0
{
70
0
  RemoveFencesAndSeparators();
71
0
  CreateFencesAndSeparators(PresContext());
72
0
73
0
  return nsMathMLContainerFrame::
74
0
         AttributeChanged(aNameSpaceID, aAttribute, aModType);
75
0
}
76
77
nsresult
78
nsMathMLmfencedFrame::ChildListChanged(int32_t aModType)
79
0
{
80
0
  RemoveFencesAndSeparators();
81
0
  CreateFencesAndSeparators(PresContext());
82
0
83
0
  return nsMathMLContainerFrame::ChildListChanged(aModType);
84
0
}
85
86
void
87
nsMathMLmfencedFrame::RemoveFencesAndSeparators()
88
0
{
89
0
  MarkNeedsDisplayItemRebuild();
90
0
  delete mOpenChar;
91
0
  delete mCloseChar;
92
0
  if (mSeparatorsChar) delete[] mSeparatorsChar;
93
0
94
0
  mOpenChar = nullptr;
95
0
  mCloseChar = nullptr;
96
0
  mSeparatorsChar = nullptr;
97
0
  mSeparatorsCount = 0;
98
0
}
99
100
void
101
nsMathMLmfencedFrame::CreateFencesAndSeparators(nsPresContext* aPresContext)
102
0
{
103
0
  nsAutoString value;
104
0
105
0
  //////////////
106
0
  // see if the opening fence is there ...
107
0
  if (!mContent->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::open, value)) {
108
0
    value = char16_t('('); // default as per the MathML REC
109
0
  } else {
110
0
    value.CompressWhitespace();
111
0
  }
112
0
113
0
  if (!value.IsEmpty()) {
114
0
    mOpenChar = new nsMathMLChar;
115
0
    mOpenChar->SetData(value);
116
0
    ResolveMathMLCharStyle(aPresContext, mContent, mComputedStyle, mOpenChar);
117
0
  }
118
0
119
0
  //////////////
120
0
  // see if the closing fence is there ...
121
0
  if(!mContent->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::close, value)) {
122
0
    value = char16_t(')'); // default as per the MathML REC
123
0
  } else {
124
0
    value.CompressWhitespace();
125
0
  }
126
0
127
0
  if (!value.IsEmpty()) {
128
0
    mCloseChar = new nsMathMLChar;
129
0
    mCloseChar->SetData(value);
130
0
    ResolveMathMLCharStyle(aPresContext, mContent, mComputedStyle, mCloseChar);
131
0
  }
132
0
133
0
  //////////////
134
0
  // see if separators are there ...
135
0
  if (!mContent->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::separators_, value)) {
136
0
    value = char16_t(','); // default as per the MathML REC
137
0
  } else {
138
0
    value.StripWhitespace();
139
0
  }
140
0
141
0
  mSeparatorsCount = value.Length();
142
0
  if (0 < mSeparatorsCount) {
143
0
    int32_t sepCount = mFrames.GetLength() - 1;
144
0
    if (0 < sepCount) {
145
0
      mSeparatorsChar = new nsMathMLChar[sepCount];
146
0
      nsAutoString sepChar;
147
0
      for (int32_t i = 0; i < sepCount; i++) {
148
0
        if (i < mSeparatorsCount) {
149
0
          sepChar = value[i];
150
0
        }
151
0
        else {
152
0
          sepChar = value[mSeparatorsCount-1];
153
0
        }
154
0
        mSeparatorsChar[i].SetData(sepChar);
155
0
        ResolveMathMLCharStyle(aPresContext, mContent, mComputedStyle, &mSeparatorsChar[i]);
156
0
      }
157
0
      mSeparatorsCount = sepCount;
158
0
    } else {
159
0
      // No separators.  Note that sepCount can be -1 here, so don't
160
0
      // set mSeparatorsCount to it.
161
0
      mSeparatorsCount = 0;
162
0
    }
163
0
  }
164
0
}
165
166
void
167
nsMathMLmfencedFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
168
                                       const nsDisplayListSet& aLists)
169
0
{
170
0
  /////////////
171
0
  // display the content
172
0
  nsMathMLContainerFrame::BuildDisplayList(aBuilder, aLists);
173
0
174
0
  ////////////
175
0
  // display fences and separators
176
0
  uint32_t count = 0;
177
0
  if (mOpenChar) {
178
0
    mOpenChar->Display(aBuilder, this, aLists, count++);
179
0
  }
180
0
181
0
  if (mCloseChar) {
182
0
    mCloseChar->Display(aBuilder, this, aLists, count++);
183
0
  }
184
0
185
0
  for (int32_t i = 0; i < mSeparatorsCount; i++) {
186
0
    mSeparatorsChar[i].Display(aBuilder, this, aLists, count++);
187
0
  }
188
0
}
189
190
/* @param aMetrics is an IN/OUT.  Provide the current metrics for the mFenced
191
          frame and it will be enlarged as necessary.
192
For simplicity the width of the container is always incremented by the width
193
of the nsMathMLChar.  As we only stretch fences and separators in the vertical
194
direction, this has no impact on overall appearance.
195
*/
196
static void
197
ApplyUnstretchedMetrics(nsIFrame*           aFrame,
198
                        DrawTarget*         aDrawTarget,
199
                        float               aFontSizeInflation,
200
                        nsMathMLChar*       aMathMLChar,
201
                        nsBoundingMetrics&  aMetrics,
202
                        bool                aIsRTL)
203
0
{
204
0
  if (aMathMLChar && 0 < aMathMLChar->Length()) {
205
0
    nsBoundingMetrics charSize;
206
0
    aMathMLChar->Stretch(aFrame, aDrawTarget, aFontSizeInflation,
207
0
                         NS_STRETCH_DIRECTION_DEFAULT,
208
0
                         aMetrics, // size is unimportant as we aren't stretching
209
0
                         charSize, NS_STRETCH_NONE, aIsRTL);
210
0
    aMetrics += charSize;
211
0
  }
212
0
}
213
214
void
215
nsMathMLmfencedFrame::Reflow(nsPresContext*          aPresContext,
216
                             ReflowOutput&     aDesiredSize,
217
                             const ReflowInput& aReflowInput,
218
                             nsReflowStatus&          aStatus)
219
0
{
220
0
  MarkInReflow();
221
0
  MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
222
0
223
0
  mPresentationData.flags &= ~NS_MATHML_ERROR;
224
0
  aDesiredSize.ClearSize();
225
0
  aDesiredSize.SetBlockStartAscent(0);
226
0
  aDesiredSize.mBoundingMetrics = nsBoundingMetrics();
227
0
228
0
  int32_t i;
229
0
  const nsStyleFont* font = StyleFont();
230
0
  float fontSizeInflation = nsLayoutUtils::FontSizeInflationFor(this);
231
0
  RefPtr<nsFontMetrics> fm =
232
0
    nsLayoutUtils::GetFontMetricsForFrame(this, fontSizeInflation);
233
0
  nscoord axisHeight, em;
234
0
  GetAxisHeight(aReflowInput.mRenderingContext->GetDrawTarget(), fm, axisHeight);
235
0
  GetEmHeight(fm, em);
236
0
  // leading to be left at the top and the bottom of stretched chars
237
0
  nscoord leading = NSToCoordRound(0.2f * em);
238
0
239
0
  /////////////
240
0
  // Reflow children
241
0
  // Asking each child to cache its bounding metrics
242
0
243
0
  // Note that we don't use the base method nsMathMLContainerFrame::Reflow()
244
0
  // because we want to stretch our fences, separators and stretchy frames using
245
0
  // the *same* initial aDesiredSize.mBoundingMetrics. If we were to use the base
246
0
  // method here, our stretchy frames will be stretched and placed, and we may
247
0
  // end up stretching our fences/separators with a different aDesiredSize.
248
0
  // XXX The above decision was revisited in bug 121748 and this code can be
249
0
  // refactored to use nsMathMLContainerFrame::Reflow() at some stage.
250
0
251
0
  nsReflowStatus childStatus;
252
0
  nsIFrame* firstChild = PrincipalChildList().FirstChild();
253
0
  nsIFrame* childFrame = firstChild;
254
0
  nscoord ascent = 0, descent = 0;
255
0
  if (firstChild || mOpenChar || mCloseChar || mSeparatorsCount > 0) {
256
0
    // We use the ASCII metrics to get our minimum height. This way,
257
0
    // if we have borders or a background, they will fit better with
258
0
    // other elements on the line.
259
0
    ascent = fm->MaxAscent();
260
0
    descent = fm->MaxDescent();
261
0
  }
262
0
  while (childFrame) {
263
0
    ReflowOutput childDesiredSize(aReflowInput);
264
0
    WritingMode wm = childFrame->GetWritingMode();
265
0
    LogicalSize availSize = aReflowInput.ComputedSize(wm);
266
0
    availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE;
267
0
    ReflowInput childReflowInput(aPresContext, aReflowInput,
268
0
                                       childFrame, availSize);
269
0
    ReflowChild(childFrame, aPresContext, childDesiredSize,
270
0
                childReflowInput, childStatus);
271
0
    //NS_ASSERTION(childStatus.IsComplete(), "bad status");
272
0
    SaveReflowAndBoundingMetricsFor(childFrame, childDesiredSize,
273
0
                                    childDesiredSize.mBoundingMetrics);
274
0
275
0
    mozilla::WritingMode outerWM = aReflowInput.GetWritingMode();
276
0
    nscoord childDescent = childDesiredSize.BSize(outerWM) -
277
0
                           childDesiredSize.BlockStartAscent();
278
0
    if (descent < childDescent)
279
0
      descent = childDescent;
280
0
    if (ascent < childDesiredSize.BlockStartAscent())
281
0
      ascent = childDesiredSize.BlockStartAscent();
282
0
283
0
    childFrame = childFrame->GetNextSibling();
284
0
  }
285
0
286
0
  /////////////
287
0
  // Ask stretchy children to stretch themselves
288
0
289
0
  nsBoundingMetrics containerSize;
290
0
  nsStretchDirection stretchDir = NS_STRETCH_DIRECTION_VERTICAL;
291
0
292
0
  DrawTarget* drawTarget = aReflowInput.mRenderingContext->GetDrawTarget();
293
0
294
0
  GetPreferredStretchSize(drawTarget,
295
0
                          0, /* i.e., without embellishments */
296
0
                          stretchDir, containerSize);
297
0
  childFrame = firstChild;
298
0
  while (childFrame) {
299
0
    nsIMathMLFrame* mathmlChild = do_QueryFrame(childFrame);
300
0
    if (mathmlChild) {
301
0
      ReflowOutput childDesiredSize(aReflowInput);
302
0
      // retrieve the metrics that was stored at the previous pass
303
0
      GetReflowAndBoundingMetricsFor(childFrame, childDesiredSize,
304
0
                                     childDesiredSize.mBoundingMetrics);
305
0
306
0
      mathmlChild->Stretch(drawTarget,
307
0
                           stretchDir, containerSize, childDesiredSize);
308
0
      // store the updated metrics
309
0
      SaveReflowAndBoundingMetricsFor(childFrame, childDesiredSize,
310
0
                                      childDesiredSize.mBoundingMetrics);
311
0
312
0
      nscoord childDescent = childDesiredSize.Height() - childDesiredSize.BlockStartAscent();
313
0
      if (descent < childDescent)
314
0
        descent = childDescent;
315
0
      if (ascent < childDesiredSize.BlockStartAscent())
316
0
        ascent = childDesiredSize.BlockStartAscent();
317
0
    }
318
0
    childFrame = childFrame->GetNextSibling();
319
0
  }
320
0
321
0
  // bug 121748: for surrounding fences & separators, use a size that covers everything
322
0
  GetPreferredStretchSize(drawTarget, STRETCH_CONSIDER_EMBELLISHMENTS,
323
0
                          stretchDir, containerSize);
324
0
325
0
  bool isRTL = StyleVisibility()->mDirection;
326
0
327
0
  // To achieve a minimum size of "1", the container should be enlarged by the
328
0
  // unstretched metrics of the fences and separators.
329
0
  ApplyUnstretchedMetrics(this, drawTarget,
330
0
                          fontSizeInflation, mOpenChar,
331
0
                          containerSize, isRTL);
332
0
  for (i = 0; i < mSeparatorsCount; i++) {
333
0
    ApplyUnstretchedMetrics(this, drawTarget,
334
0
                            fontSizeInflation, &mSeparatorsChar[i],
335
0
                            containerSize, isRTL);
336
0
  }
337
0
  ApplyUnstretchedMetrics(this, drawTarget,
338
0
                          fontSizeInflation, mCloseChar,
339
0
                          containerSize, isRTL);
340
0
341
0
  //////////////////////////////////////////
342
0
  // Prepare the opening fence, separators, and closing fence, and
343
0
  // adjust the origin of children.
344
0
345
0
  // we need to center around the axis
346
0
  nscoord delta = std::max(containerSize.ascent - axisHeight,
347
0
                         containerSize.descent + axisHeight);
348
0
  containerSize.ascent = delta + axisHeight;
349
0
  containerSize.descent = delta - axisHeight;
350
0
351
0
  /////////////////
352
0
  // opening fence ...
353
0
  ReflowChar(drawTarget, *fm,
354
0
             fontSizeInflation, mOpenChar,
355
0
             NS_MATHML_OPERATOR_FORM_PREFIX, font->mScriptLevel,
356
0
             axisHeight, leading, em, containerSize, ascent, descent, isRTL);
357
0
  /////////////////
358
0
  // separators ...
359
0
  for (i = 0; i < mSeparatorsCount; i++) {
360
0
    ReflowChar(drawTarget, *fm,
361
0
               fontSizeInflation, &mSeparatorsChar[i],
362
0
               NS_MATHML_OPERATOR_FORM_INFIX, font->mScriptLevel,
363
0
               axisHeight, leading, em, containerSize, ascent, descent, isRTL);
364
0
  }
365
0
  /////////////////
366
0
  // closing fence ...
367
0
  ReflowChar(drawTarget, *fm,
368
0
             fontSizeInflation, mCloseChar,
369
0
             NS_MATHML_OPERATOR_FORM_POSTFIX, font->mScriptLevel,
370
0
             axisHeight, leading, em, containerSize, ascent, descent, isRTL);
371
0
372
0
  //////////////////
373
0
  // Adjust the origins of each child.
374
0
  // and update our bounding metrics
375
0
376
0
  i = 0;
377
0
  nscoord dx = 0;
378
0
  nsBoundingMetrics bm;
379
0
  bool firstTime = true;
380
0
  nsMathMLChar *leftChar, *rightChar;
381
0
  if (isRTL) {
382
0
    leftChar = mCloseChar;
383
0
    rightChar = mOpenChar;
384
0
  } else {
385
0
    leftChar = mOpenChar;
386
0
    rightChar = mCloseChar;
387
0
  }
388
0
389
0
  if (leftChar) {
390
0
    PlaceChar(leftChar, ascent, bm, dx);
391
0
    aDesiredSize.mBoundingMetrics = bm;
392
0
    firstTime = false;
393
0
  }
394
0
395
0
  if (isRTL) {
396
0
    childFrame = this->GetChildList(nsIFrame::kPrincipalList).LastChild();
397
0
  } else {
398
0
    childFrame = firstChild;
399
0
  }
400
0
  while (childFrame) {
401
0
    ReflowOutput childSize(aReflowInput);
402
0
    GetReflowAndBoundingMetricsFor(childFrame, childSize, bm);
403
0
    if (firstTime) {
404
0
      firstTime = false;
405
0
      aDesiredSize.mBoundingMetrics  = bm;
406
0
    }
407
0
    else
408
0
      aDesiredSize.mBoundingMetrics += bm;
409
0
410
0
    FinishReflowChild(childFrame, aPresContext, childSize, nullptr,
411
0
                      dx, ascent - childSize.BlockStartAscent(), 0);
412
0
    dx += childSize.Width();
413
0
414
0
    if (i < mSeparatorsCount) {
415
0
      PlaceChar(&mSeparatorsChar[isRTL ? mSeparatorsCount - 1 - i : i],
416
0
                ascent, bm, dx);
417
0
      aDesiredSize.mBoundingMetrics += bm;
418
0
    }
419
0
    i++;
420
0
421
0
    if (isRTL) {
422
0
      childFrame = childFrame->GetPrevSibling();
423
0
    } else {
424
0
      childFrame = childFrame->GetNextSibling();
425
0
    }
426
0
  }
427
0
428
0
  if (rightChar) {
429
0
    PlaceChar(rightChar, ascent, bm, dx);
430
0
    if (firstTime)
431
0
      aDesiredSize.mBoundingMetrics  = bm;
432
0
    else
433
0
      aDesiredSize.mBoundingMetrics += bm;
434
0
  }
435
0
436
0
  aDesiredSize.Width() = aDesiredSize.mBoundingMetrics.width;
437
0
  aDesiredSize.Height() = ascent + descent;
438
0
  aDesiredSize.SetBlockStartAscent(ascent);
439
0
440
0
  SetBoundingMetrics(aDesiredSize.mBoundingMetrics);
441
0
  SetReference(nsPoint(0, aDesiredSize.BlockStartAscent()));
442
0
443
0
  // see if we should fix the spacing
444
0
  FixInterFrameSpacing(aDesiredSize);
445
0
446
0
  // Finished with these:
447
0
  ClearSavedChildMetrics();
448
0
449
0
  // Set our overflow area
450
0
  GatherAndStoreOverflow(&aDesiredSize);
451
0
452
0
  MOZ_ASSERT(aStatus.IsEmpty(), "This type of frame can't be split.");
453
0
  NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize);
454
0
}
455
456
static void
457
GetCharSpacing(nsMathMLChar*        aMathMLChar,
458
               nsOperatorFlags      aForm,
459
               int32_t              aScriptLevel,
460
               nscoord              em,
461
               nscoord&             aLeftSpace,
462
               nscoord&             aRightSpace)
463
0
{
464
0
  nsAutoString data;
465
0
  aMathMLChar->GetData(data);
466
0
  nsOperatorFlags flags = 0;
467
0
  float lspace = 0.0f;
468
0
  float rspace = 0.0f;
469
0
  bool found = nsMathMLOperators::LookupOperator(data, aForm,
470
0
                                                   &flags, &lspace, &rspace);
471
0
472
0
  // We don't want extra space when we are a script
473
0
  if (found && aScriptLevel > 0) {
474
0
    lspace /= 2.0f;
475
0
    rspace /= 2.0f;
476
0
  }
477
0
478
0
  aLeftSpace = NSToCoordRound(lspace * em);
479
0
  aRightSpace = NSToCoordRound(rspace * em);
480
0
}
481
482
// helper functions to perform the common task of formatting our chars
483
nsresult
484
nsMathMLmfencedFrame::ReflowChar(DrawTarget*          aDrawTarget,
485
                                 nsFontMetrics&       aFontMetrics,
486
                                 float                aFontSizeInflation,
487
                                 nsMathMLChar*        aMathMLChar,
488
                                 nsOperatorFlags      aForm,
489
                                 int32_t              aScriptLevel,
490
                                 nscoord              axisHeight,
491
                                 nscoord              leading,
492
                                 nscoord              em,
493
                                 nsBoundingMetrics&   aContainerSize,
494
                                 nscoord&             aAscent,
495
                                 nscoord&             aDescent,
496
                                 bool                 aRTL)
497
0
{
498
0
  if (aMathMLChar && 0 < aMathMLChar->Length()) {
499
0
    nscoord leftSpace;
500
0
    nscoord rightSpace;
501
0
    GetCharSpacing(aMathMLChar, aForm, aScriptLevel, em, leftSpace, rightSpace);
502
0
503
0
    // stretch the char to the appropriate height if it is not big enough.
504
0
    nsBoundingMetrics charSize;
505
0
    nsresult res = aMathMLChar->Stretch(this, aDrawTarget,
506
0
                                        aFontSizeInflation,
507
0
                                        NS_STRETCH_DIRECTION_VERTICAL,
508
0
                                        aContainerSize, charSize,
509
0
                                        NS_STRETCH_NORMAL, aRTL);
510
0
511
0
    if (NS_STRETCH_DIRECTION_UNSUPPORTED != aMathMLChar->GetStretchDirection()) {
512
0
      // has changed... so center the char around the axis
513
0
      nscoord height = charSize.ascent + charSize.descent;
514
0
      charSize.ascent = height/2 + axisHeight;
515
0
      charSize.descent = height - charSize.ascent;
516
0
    }
517
0
    else {
518
0
      // either it hasn't changed or stretching the char failed (i.e.,
519
0
      // nsLayoutUtils::AppUnitBoundsOfString failed)
520
0
      leading = 0;
521
0
      if (NS_FAILED(res)) {
522
0
        nsAutoString data;
523
0
        aMathMLChar->GetData(data);
524
0
        nsBoundingMetrics metrics =
525
0
          nsLayoutUtils::AppUnitBoundsOfString(data.get(), data.Length(),
526
0
                                               aFontMetrics, aDrawTarget);
527
0
        charSize.ascent = metrics.ascent;
528
0
        charSize.descent = metrics.descent;
529
0
        charSize.width = metrics.width;
530
0
        // Set this as the bounding metrics of the MathMLChar to leave
531
0
        // the necessary room to paint the char.
532
0
        aMathMLChar->SetBoundingMetrics(charSize);
533
0
      }
534
0
    }
535
0
536
0
    if (aAscent < charSize.ascent + leading)
537
0
      aAscent = charSize.ascent + leading;
538
0
    if (aDescent < charSize.descent + leading)
539
0
      aDescent = charSize.descent + leading;
540
0
541
0
    // account the spacing
542
0
    charSize.width += leftSpace + rightSpace;
543
0
544
0
    // x-origin is used to store lspace ...
545
0
    // y-origin is used to stored the ascent ...
546
0
    aMathMLChar->SetRect(nsRect(leftSpace,
547
0
                                charSize.ascent, charSize.width,
548
0
                                charSize.ascent + charSize.descent));
549
0
  }
550
0
  return NS_OK;
551
0
}
552
553
/*static*/ void
554
nsMathMLmfencedFrame::PlaceChar(nsMathMLChar*      aMathMLChar,
555
                                nscoord            aDesiredAscent,
556
                                nsBoundingMetrics& bm,
557
                                nscoord&           dx)
558
0
{
559
0
  aMathMLChar->GetBoundingMetrics(bm);
560
0
561
0
  // the char's x-origin was used to store lspace ...
562
0
  // the char's y-origin was used to store the ascent ...
563
0
  // the char's width was used to store the advance with (with spacing) ...
564
0
  nsRect rect;
565
0
  aMathMLChar->GetRect(rect);
566
0
567
0
  nscoord dy = aDesiredAscent - rect.y;
568
0
  if (aMathMLChar->GetStretchDirection() != NS_STRETCH_DIRECTION_UNSUPPORTED) {
569
0
    // the stretchy char will be centered around the axis
570
0
    // so we adjust the returned bounding metrics accordingly
571
0
    bm.descent = (bm.ascent + bm.descent) - rect.y;
572
0
    bm.ascent = rect.y;
573
0
  }
574
0
575
0
  aMathMLChar->SetRect(nsRect(dx + rect.x, dy, bm.width, rect.height));
576
0
577
0
  bm.leftBearing += rect.x;
578
0
  bm.rightBearing += rect.x;
579
0
580
0
  // return rect.width since it includes lspace and rspace
581
0
  bm.width = rect.width;
582
0
  dx += rect.width;
583
0
}
584
585
static nscoord
586
GetMaxCharWidth(nsIFrame*            aFrame,
587
                DrawTarget*          aDrawTarget,
588
                float                aFontSizeInflation,
589
                nsMathMLChar*        aMathMLChar,
590
                nsOperatorFlags      aForm,
591
                int32_t              aScriptLevel,
592
                nscoord              em)
593
0
{
594
0
  nscoord width = aMathMLChar->GetMaxWidth(aFrame, aDrawTarget,
595
0
                                           aFontSizeInflation);
596
0
597
0
  if (0 < aMathMLChar->Length()) {
598
0
    nscoord leftSpace;
599
0
    nscoord rightSpace;
600
0
    GetCharSpacing(aMathMLChar, aForm, aScriptLevel, em, leftSpace, rightSpace);
601
0
602
0
    width += leftSpace + rightSpace;
603
0
  }
604
0
605
0
  return width;
606
0
}
607
608
/* virtual */ void
609
nsMathMLmfencedFrame::GetIntrinsicISizeMetrics(gfxContext* aRenderingContext, ReflowOutput& aDesiredSize)
610
0
{
611
0
  nscoord width = 0;
612
0
613
0
  const nsStyleFont* font = StyleFont();
614
0
  float fontSizeInflation = nsLayoutUtils:: FontSizeInflationFor(this);
615
0
  RefPtr<nsFontMetrics> fm =
616
0
    nsLayoutUtils::GetFontMetricsForFrame(this, fontSizeInflation);
617
0
  nscoord em;
618
0
  GetEmHeight(fm, em);
619
0
620
0
  if (mOpenChar) {
621
0
    width +=
622
0
      GetMaxCharWidth(this, aRenderingContext->GetDrawTarget(),
623
0
                      fontSizeInflation, mOpenChar,
624
0
                      NS_MATHML_OPERATOR_FORM_PREFIX, font->mScriptLevel, em);
625
0
  }
626
0
627
0
  int32_t i = 0;
628
0
  for (nsIFrame* childFrame : PrincipalChildList()) {
629
0
    // XXX This includes margin while Reflow currently doesn't consider
630
0
    // margin, so we may end up with too much space, but, with stretchy
631
0
    // characters, this is an approximation anyway.
632
0
    width += nsLayoutUtils::IntrinsicForContainer(aRenderingContext, childFrame,
633
0
                                                  nsLayoutUtils::PREF_ISIZE);
634
0
635
0
    if (i < mSeparatorsCount) {
636
0
      width +=
637
0
        GetMaxCharWidth(this, aRenderingContext->GetDrawTarget(),
638
0
                        fontSizeInflation, &mSeparatorsChar[i],
639
0
                        NS_MATHML_OPERATOR_FORM_INFIX, font->mScriptLevel, em);
640
0
    }
641
0
    i++;
642
0
  }
643
0
644
0
  if (mCloseChar) {
645
0
    width +=
646
0
      GetMaxCharWidth(this, aRenderingContext->GetDrawTarget(),
647
0
                      fontSizeInflation, mCloseChar,
648
0
                      NS_MATHML_OPERATOR_FORM_POSTFIX, font->mScriptLevel, em);
649
0
  }
650
0
651
0
  aDesiredSize.Width() = width;
652
0
  aDesiredSize.mBoundingMetrics.width = width;
653
0
  aDesiredSize.mBoundingMetrics.leftBearing = 0;
654
0
  aDesiredSize.mBoundingMetrics.rightBearing = width;
655
0
}
656
657
nscoord
658
nsMathMLmfencedFrame::FixInterFrameSpacing(ReflowOutput& aDesiredSize)
659
0
{
660
0
  nscoord gap = nsMathMLContainerFrame::FixInterFrameSpacing(aDesiredSize);
661
0
  if (!gap) return 0;
662
0
663
0
  nsRect rect;
664
0
  if (mOpenChar) {
665
0
    mOpenChar->GetRect(rect);
666
0
    rect.MoveBy(gap, 0);
667
0
    mOpenChar->SetRect(rect);
668
0
  }
669
0
  if (mCloseChar) {
670
0
    mCloseChar->GetRect(rect);
671
0
    rect.MoveBy(gap, 0);
672
0
    mCloseChar->SetRect(rect);
673
0
  }
674
0
  for (int32_t i = 0; i < mSeparatorsCount; i++) {
675
0
    mSeparatorsChar[i].GetRect(rect);
676
0
    rect.MoveBy(gap, 0);
677
0
    mSeparatorsChar[i].SetRect(rect);
678
0
  }
679
0
  return gap;
680
0
}
681
682
// ----------------------
683
// the Style System will use these to pass the proper ComputedStyle to our
684
// MathMLChar
685
ComputedStyle*
686
nsMathMLmfencedFrame::GetAdditionalComputedStyle(int32_t aIndex) const
687
0
{
688
0
  int32_t openIndex = -1;
689
0
  int32_t closeIndex = -1;
690
0
  int32_t lastIndex = mSeparatorsCount-1;
691
0
692
0
  if (mOpenChar) {
693
0
    lastIndex++;
694
0
    openIndex = lastIndex;
695
0
  }
696
0
  if (mCloseChar) {
697
0
    lastIndex++;
698
0
    closeIndex = lastIndex;
699
0
  }
700
0
  if (aIndex < 0 || aIndex > lastIndex) {
701
0
    return nullptr;
702
0
  }
703
0
704
0
  if (aIndex < mSeparatorsCount) {
705
0
    return mSeparatorsChar[aIndex].GetComputedStyle();
706
0
  }
707
0
  else if (aIndex == openIndex) {
708
0
    return mOpenChar->GetComputedStyle();
709
0
  }
710
0
  else if (aIndex == closeIndex) {
711
0
    return mCloseChar->GetComputedStyle();
712
0
  }
713
0
  return nullptr;
714
0
}
715
716
void
717
nsMathMLmfencedFrame::SetAdditionalComputedStyle(int32_t          aIndex,
718
                                                ComputedStyle*  aComputedStyle)
719
0
{
720
0
  int32_t openIndex = -1;
721
0
  int32_t closeIndex = -1;
722
0
  int32_t lastIndex = mSeparatorsCount-1;
723
0
724
0
  if (mOpenChar) {
725
0
    lastIndex++;
726
0
    openIndex = lastIndex;
727
0
  }
728
0
  if (mCloseChar) {
729
0
    lastIndex++;
730
0
    closeIndex = lastIndex;
731
0
  }
732
0
  if (aIndex < 0 || aIndex > lastIndex) {
733
0
    return;
734
0
  }
735
0
736
0
  if (aIndex < mSeparatorsCount) {
737
0
    mSeparatorsChar[aIndex].SetComputedStyle(aComputedStyle);
738
0
  }
739
0
  else if (aIndex == openIndex) {
740
0
    mOpenChar->SetComputedStyle(aComputedStyle);
741
0
  }
742
0
  else if (aIndex == closeIndex) {
743
0
    mCloseChar->SetComputedStyle(aComputedStyle);
744
0
  }
745
0
}